summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/media/src/com/android/commands/media/Media.java20
-rw-r--r--media/java/android/media/AudioManager.java101
-rw-r--r--media/java/android/media/IAudioService.aidl12
-rw-r--r--media/java/android/media/IRemoteControlClient.aidl5
-rw-r--r--media/java/android/media/MediaMetadataEditor.java4
-rw-r--r--media/java/android/media/RemoteControlClient.java203
-rw-r--r--media/java/android/media/RemoteController.java186
-rw-r--r--media/java/android/media/session/ISession.aidl4
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl3
-rw-r--r--media/java/android/media/session/ISessionController.aidl3
-rw-r--r--media/java/android/media/session/ISessionControllerCallback.aidl4
-rw-r--r--media/java/android/media/session/MediaController.java114
-rw-r--r--media/java/android/media/session/MediaSession.java141
-rw-r--r--media/java/android/media/session/MediaSessionLegacyHelper.java21
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java127
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java79
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java182
17 files changed, 1206 insertions, 3 deletions
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index d7f23cb..d185b56 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -222,6 +222,26 @@ public class Media extends BaseCommand {
System.out.println("onVolumeInfoChanged " + info);
}
+ @Override
+ public void onPlayItemResponse(boolean success) throws RemoteException {
+ System.out.println("onPlayItemResponse ");
+ }
+
+ @Override
+ public void onUpdateNowPlayingEntries(long[] playList) throws RemoteException {
+ System.out.println("onUpdateNowPlayingEntries ");
+ }
+
+ @Override
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) throws RemoteException {
+ System.out.println("onUpdateFolderInfoBrowsedPlayer ");
+ }
+
+ @Override
+ public void onUpdateNowPlayingContentChange() throws RemoteException {
+ System.out.println("onUpdateNowPlayingContentChange ");
+ }
+
void printUsageMessage() {
try {
System.out.println("V2Monitoring session " + mController.getTag()
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 875e716..fc917f6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -67,7 +67,6 @@ public class AudioManager {
private final boolean mUseFixedVolume;
private static String TAG = "AudioManager";
private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
-
/**
* Broadcast intent, a hint for applications that audio is about to become
* 'noisy' due to a change in audio outputs. For example, this intent may
@@ -310,6 +309,32 @@ public class AudioManager {
*/
public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
+ /**
+ * @hide Broadcast intent when RemoteControlClient list is updated.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String RCC_CHANGED_ACTION =
+ "org.codeaurora.bluetooth.RCC_CHANGED_ACTION";
+
+ /**
+ * @hide Used for sharing the calling package name
+ */
+ public static final String EXTRA_CALLING_PACKAGE_NAME =
+ "org.codeaurora.bluetooth.EXTRA_CALLING_PACKAGE_NAME";
+
+ /**
+ * @hide Used for sharing the focus changed value
+ */
+ public static final String EXTRA_FOCUS_CHANGED_VALUE =
+ "org.codeaurora.bluetooth.EXTRA_FOCUS_CHANGED_VALUE";
+
+ /**
+ * @hide Used for sharing the availability changed value
+ */
+ public static final String EXTRA_AVAILABLITY_CHANGED_VALUE =
+ "org.codeaurora.bluetooth.EXTRA_AVAILABLITY_CHANGED_VALUE";
+
+
/** The audio stream for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** The audio stream for system sounds */
@@ -2481,6 +2506,7 @@ public class AudioManager {
//====================================================================
// Remote Control
+
/**
* Register a component to be the sole receiver of MEDIA_BUTTON intents.
* @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
@@ -2499,6 +2525,7 @@ public class AudioManager {
"receiver and context package names don't match");
return;
}
+
// construct a PendingIntent for the media button and register it
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
// the associated intent will be handled by the component being registered
@@ -2508,6 +2535,7 @@ public class AudioManager {
registerMediaButtonIntent(pi, eventReceiver);
}
+
/**
* Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
* {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
@@ -2637,6 +2665,13 @@ public class AudioManager {
return false;
}
rctlr.startListeningToSessions();
+ IAudioService service = getService();
+ try {
+ service.updateRemoteControllerOnExistingMediaPlayers();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in calling Audio service interface" +
+ "updateRemoteControllerOnExistingMediaPlayers() due to " + e);
+ }
return true;
}
@@ -2660,6 +2695,24 @@ public class AudioManager {
/**
* @hide
+ */
+ public void updateMediaPlayerList(String packageName, boolean toAdd) {
+ IAudioService service = getService();
+ try {
+ if (toAdd) {
+ Log.d(TAG, "updateMediaPlayerList: Add RCC " + packageName + " to List");
+ service.addMediaPlayerAndUpdateRemoteController(packageName);
+ } else {
+ Log.d(TAG, "updateMediaPlayerList: Remove RCC " + packageName + " from List");
+ service.removeMediaPlayerAndUpdateRemoteController(packageName);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while executing updateMediaPlayerList: " + e);
+ }
+ }
+
+ /**
+ * @hide
* Registers a remote control display that will be sent information by remote control clients.
* Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
* use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
@@ -2811,6 +2864,52 @@ public class AudioManager {
}
}
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to play the requested item.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ * @param uid uid of the song to be played.
+ * @scope scope of the file system to use
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ IAudioService service = getService();
+ try {
+ service.setRemoteControlClientPlayItem(uid, scope);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setRemoteControlClientPlayItem(" +
+ uid + ", " + scope + ")", e);
+ }
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to provide with the now playing list entries.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ */
+ public void getRemoteControlClientNowPlayingEntries() {
+ IAudioService service = getService();
+ try {
+ service.getRemoteControlClientNowPlayingEntries();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getRemoteControlClientNowPlayingEntries(" + ")", e);
+ }
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to set the music player as current browsed player.
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer: ");
+ IAudioService service = getService();
+ try {
+ service.setRemoteControlClientBrowsedPlayer();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setRemoteControlClientBrowsedPlayer(" + ")", e);
+ }
+ }
/**
* @hide
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 8aebe11..0b98e1b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -215,4 +215,16 @@ interface IAudioService {
int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
void setVolumePolicy(in VolumePolicy policy);
+
+ void setRemoteControlClientBrowsedPlayer();
+
+ void getRemoteControlClientNowPlayingEntries();
+
+ void setRemoteControlClientPlayItem(long uid, int scope);
+
+ void updateRemoteControllerOnExistingMediaPlayers();
+
+ void addMediaPlayerAndUpdateRemoteController(String packageName);
+
+ void removeMediaPlayerAndUpdateRemoteController(String packageName);
}
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index aa142d6..d8e73c8 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -52,11 +52,14 @@ oneway interface IRemoteControlClient
*/
void setCurrentClientGenerationId(int clientGeneration);
- void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
+ void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled);
void seekTo(int clientGeneration, long timeMs);
void updateMetadata(int clientGeneration, int key, in Rating value);
+ void setPlayItem(int scope, long uid);
+ void setBrowsedPlayer();
+ void getNowPlayingEntries();
} \ No newline at end of file
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
index 566b93f..eeb8fe2 100644
--- a/media/java/android/media/MediaMetadataEditor.java
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -439,7 +439,7 @@ import android.util.SparseIntArray;
protected static final SparseIntArray METADATA_KEYS_TYPE;
static {
- METADATA_KEYS_TYPE = new SparseIntArray(17);
+ METADATA_KEYS_TYPE = new SparseIntArray(18);
// NOTE: if adding to the list below, make sure you increment the array initialization size
// keys with long values
METADATA_KEYS_TYPE.put(
@@ -465,5 +465,7 @@ import android.util.SparseIntArray;
// keys with Rating values
METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+ // Meta data for total number of tracks in Album
+ METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
}
}
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index c9a86d8..07b8c23 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -707,6 +707,79 @@ import java.lang.IllegalArgumentException;
}
}
+ /**
+ * @hide
+ */
+ public void playItemResponse(boolean success) {
+ Log.e(TAG, "playItemResponse");
+ playItemResponseInt(success);
+ }
+
+ private void playItemResponseInt(boolean success) {
+ Log.d(TAG, "playItemResponseInt");
+ Log.v(TAG, "success: " + success);
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.playItemResponse(success);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingEntries(long[] playList) {
+ Log.e(TAG, "updateNowPlayingEntries: Item numbers: " + playList.length);
+ updateNowPlayingEntriesInt(playList);
+ }
+
+ private void updateNowPlayingEntriesInt(long[] playList) {
+ Log.d(TAG, "updateNowPlayingEntriesInt");
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.updateNowPlayingEntries(playList);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.e(TAG, "updateFolderInfoBrowsedPlayer");
+ synchronized(mCacheLock) {
+ updateFolderInfoBrowsedPlayerInt(stringUri);
+ }
+ }
+
+ private void updateFolderInfoBrowsedPlayerInt(String stringUri) {
+ Log.d(TAG, "updateFolderInfoBrowsedPlayerInt");
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.updateFolderInfoBrowsedPlayer(stringUri);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingContentChange() {
+ Log.e(TAG, "updateNowPlayingContentChange");
+ synchronized(mCacheLock) {
+ updateNowPlayingContentChangeInt();
+ }
+ }
+
+ private void updateNowPlayingContentChangeInt() {
+ Log.d(TAG, "updateNowPlayingContentChangeInt");
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSession.updateNowPlayingContentChange();
+ }
+ }
+
// TODO investigate if we still need position drift checking
private void onPositionDriftCheck() {
if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
@@ -798,6 +871,56 @@ import java.lang.IllegalArgumentException;
}
}
+ /**
+ * @hide
+ */
+ public interface OnGetNowPlayingEntriesListener {
+ public abstract void onGetNowPlayingEntries();
+ }
+
+ /**
+ * @hide
+ */
+ public void setNowPlayingEntriesUpdateListener(OnGetNowPlayingEntriesListener l) {
+ Log.d(TAG, "setNowPlayingEntriesUpdateListener");
+ synchronized(mCacheLock) {
+ mGetNowPlayingEntriesListener = l;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnSetBrowsedPlayerListener {
+ public abstract void onSetBrowsedPlayer();
+ }
+
+ /**
+ * @hide
+ */
+ public void setBrowsedPlayerUpdateListener(OnSetBrowsedPlayerListener l) {
+ Log.d(TAG, "setBrowsedPlayerUpdateListener");
+ synchronized(mCacheLock) {
+ mSetBrowsedPlayerListener = l;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnSetPlayItemListener {
+ public abstract void onSetPlayItem(int scope, long uid);
+ }
+
+ /**
+ * @hide
+ */
+ public void setPlayItemListener(OnSetPlayItemListener l) {
+ Log.d(TAG, "setPlayItemListener");
+ synchronized(mCacheLock) {
+ mSetPlayItemListener = l;
+ }
+ }
/**
* Interface definition for a callback to be invoked when the media playback position is
@@ -946,6 +1069,13 @@ import java.lang.IllegalArgumentException;
/**
* The current remote control client generation ID across the system, as known by this object
*/
+
+ private OnSetBrowsedPlayerListener mSetBrowsedPlayerListener;
+
+ private OnSetPlayItemListener mSetPlayItemListener;
+
+ private OnGetNowPlayingEntriesListener mGetNowPlayingEntriesListener;
+
private int mCurrentClientGenId = -1;
/**
@@ -999,10 +1129,43 @@ import java.lang.IllegalArgumentException;
onUpdateMetadata(mCurrentClientGenId, MetadataEditor.RATING_KEY_BY_USER, rating);
}
}
+
+ @Override
+ public void setPlayItem(int scope, long uid) {
+ // only post messages, we can't block here
+ if (mEventHandler != null) {
+ mEventHandler.removeMessages(MSG_SET_PLAY_ITEM);
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_SET_PLAY_ITEM, 0 /* arg1 */, scope /* arg2, ignored */,
+ new Long(uid)));
+ }
+ }
+
+ @Override
+ public void getNowPlayingEntries() {
+ // only post messages, we can't block here
+ if (mEventHandler != null) {
+ mEventHandler.removeMessages(MSG_GET_NOW_PLAYING_ENTRIES);
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_GET_NOW_PLAYING_ENTRIES, 0, 0, null));
+ }
+ }
+
+ @Override
+ public void setBrowsedPlayer() {
+ Log.d(TAG, "setBrowsedPlayer in RemoteControlClient");
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_SET_BROWSED_PLAYER, 0 /* arg1 */, 0 /* arg2*/, null));
+ }
+ }
};
private EventHandler mEventHandler;
private final static int MSG_POSITION_DRIFT_CHECK = 11;
+ private final static int MSG_SET_BROWSED_PLAYER = 12;
+ private final static int MSG_SET_PLAY_ITEM = 13;
+ private final static int MSG_GET_NOW_PLAYING_ENTRIES = 14;
private class EventHandler extends Handler {
public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1015,6 +1178,16 @@ import java.lang.IllegalArgumentException;
case MSG_POSITION_DRIFT_CHECK:
onPositionDriftCheck();
break;
+ case MSG_SET_BROWSED_PLAYER:
+ Log.d(TAG, "MSG_SET_BROWSED_PLAYER in RemoteControlClient");
+ onSetBrowsedPlayer();
+ break;
+ case MSG_SET_PLAY_ITEM:
+ onSetPlayItem(msg.arg2, ((Long)msg.obj).longValue());
+ break;
+ case MSG_GET_NOW_PLAYING_ENTRIES:
+ onGetNowPlayingEntries();
+ break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
}
@@ -1040,6 +1213,36 @@ import java.lang.IllegalArgumentException;
}
}
+ private void onSetPlayItem(int scope, long uid) {
+ Log.d(TAG, "onSetPlayItem");
+ synchronized (mCacheLock) {
+ if (mSetPlayItemListener != null) {
+ Log.d(TAG, "mSetPlayItemListener.onSetPlayItem");
+ mSetPlayItemListener.onSetPlayItem(scope, uid);
+ }
+ }
+ }
+
+ private void onSetBrowsedPlayer() {
+ Log.d(TAG, "onSetBrowsedPlayer");
+ synchronized (mCacheLock) {
+ if (mSetBrowsedPlayerListener != null) {
+ Log.d(TAG, "mSetBrowsedPlayerListener.onSetBrowsedPlayer");
+ mSetBrowsedPlayerListener.onSetBrowsedPlayer();
+ }
+ }
+ }
+
+ private void onGetNowPlayingEntries() {
+ Log.d(TAG, "onGetNowPlayingEntries");
+ synchronized (mCacheLock) {
+ if (mGetNowPlayingEntriesListener != null) {
+ Log.d(TAG, "mGetNowPlayingEntriesListener.onGetNowPlayingEntries");
+ mGetNowPlayingEntriesListener.onGetNowPlayingEntries();
+ }
+ }
+ }
+
//===========================================================
// Internal utilities
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index d84cf30..aba7ad6 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -88,6 +88,7 @@ import java.util.List;
private boolean mIsRegistered = false;
private PendingIntent mClientPendingIntentCurrent;
private OnClientUpdateListener mOnClientUpdateListener;
+ private OnClientAvrcpUpdateListener mOnClientAvrcpUpdateListener;
private PlaybackInfo mLastPlaybackInfo;
private int mArtworkWidth = -1;
private int mArtworkHeight = -1;
@@ -150,6 +151,25 @@ import java.util.List;
}
}
+ /**
+ * @hide
+ */
+ public RemoteController(Context context, OnClientUpdateListener updateListener, Looper looper,
+ OnClientAvrcpUpdateListener avrcpUpdateListener) throws IllegalArgumentException {
+ this(context, updateListener, looper);
+ mOnClientAvrcpUpdateListener = avrcpUpdateListener;
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnClientAvrcpUpdateListener {
+ public void onClientFolderInfoBrowsedPlayer(String stringUri);
+ public void onClientUpdateNowPlayingEntries(long[] playList);
+ public void onClientNowPlayingContentChange();
+ public void onClientPlayItemResponse(boolean success);
+ };
+
/**
* Interface definition for the callbacks to be invoked whenever media events, metadata
@@ -355,6 +375,7 @@ import java.util.List;
* @throws IllegalArgumentException
*/
public boolean seekTo(long timeMs) throws IllegalArgumentException {
+ Log.e(TAG, "seekTo() in RemoteController");
if (!mEnabled) {
Log.e(TAG, "Cannot use seekTo() from a disabled RemoteController");
return false;
@@ -370,6 +391,69 @@ import java.util.List;
return true;
}
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to play the requested item.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ * @param uid uid of the song to be played.
+ * @scope scope of the file system to use
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ Log.e(TAG, "setRemoteControlClientPlayItem()");
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use setRemoteControlClientPlayItem()" +
+ " from a disabled RemoteController");
+ return;
+ }
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().setRemoteControlClientPlayItem(uid, scope);
+ }
+ }
+ return;
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to provide with the now playing list entries.
+ * @param generationId the RemoteControlClient generation counter for which this request is
+ * issued.
+ */
+ public void getRemoteControlClientNowPlayingEntries() {
+ Log.e(TAG, "getRemoteControlClientNowPlayingEntries()");
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use getRemoteControlClientNowPlayingEntries()" +
+ " from a disabled RemoteController");
+ return;
+ }
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().getRemoteControlClientNowPlayingEntries();
+ }
+ }
+ return;
+ }
+
+ /**
+ * @hide
+ * Request the user of a RemoteControlClient to set the music player as current browsed player.
+ * @param packageName package name of the targeted media player.
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.e(TAG, "setRemoteControlClientBrowsedPlayer()");
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use setRemoteControlClientBrowsedPlayer()" +
+ " from a disabled RemoteController");
+ return;
+ }
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().setRemoteControlClientBrowsedPlayer();
+ }
+ }
+ return;
+ }
/**
* @hide
@@ -704,6 +788,30 @@ import java.util.List;
public void onMetadataChanged(MediaMetadata metadata) {
onNewMediaMetadata(metadata);
}
+
+ @Override
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "MediaControllerCallback: onUpdateFolderInfoBrowsedPlayer");
+ onFolderInfoBrowsedPlayer(stringUri);
+ }
+
+ @Override
+ public void onUpdateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "MediaControllerCallback: onUpdateNowPlayingEntries");
+ onNowPlayingEntriesUpdate(playList);
+ }
+
+ @Override
+ public void onUpdateNowPlayingContentChange() {
+ Log.d(TAG, "MediaControllerCallback: onUpdateNowPlayingContentChange");
+ onNowPlayingContentChange();
+ }
+
+ @Override
+ public void onPlayItemResponse(boolean success) {
+ Log.d(TAG, "MediaControllerCallback: onPlayItemResponse");
+ onSetPlayItemResponse(success);
+ }
}
/**
@@ -980,6 +1088,8 @@ import java.util.List;
synchronized (mInfoLock) {
if (controller == null) {
if (mCurrentSession != null) {
+ Log.v(TAG, "Updating current controller as null");
+ mAudioManager.updateMediaPlayerList(mCurrentSession.getPackageName(), false);
mCurrentSession.unregisterCallback(mSessionCb);
mCurrentSession = null;
sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
@@ -989,13 +1099,21 @@ import java.util.List;
|| !controller.getSessionToken()
.equals(mCurrentSession.getSessionToken())) {
if (mCurrentSession != null) {
+ Log.v(TAG, "Updating current controller package as " +
+ controller.getPackageName() + " from " + mCurrentSession.getPackageName());
mCurrentSession.unregisterCallback(mSessionCb);
+ } else {
+ Log.v(TAG, "Updating current controller package as " +
+ controller.getPackageName() + " from null");
}
+
sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */);
mCurrentSession = controller;
mCurrentSession.registerCallback(mSessionCb, mEventHandler);
+ mAudioManager.updateMediaPlayerList(mCurrentSession.getPackageName(), true);
+
PlaybackState state = controller.getPlaybackState();
sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE,
0 /* genId */, 0, state /* obj */, 0 /* delay */);
@@ -1052,6 +1170,74 @@ import java.util.List;
}
}
+ private void onFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "RemoteController: onFolderInfoBrowsedPlayer");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientFolderInfoBrowsedPlayer(stringUri);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on receiving Browsed player response", e);
+ }
+ }
+
+ private void onNowPlayingEntriesUpdate(long[] playList) {
+ Log.d(TAG, "RemoteController: onUpdateNowPlayingEntries");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientUpdateNowPlayingEntries(playList);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on receiving Now Playing Entries", e);
+ }
+ }
+
+ private void onNowPlayingContentChange() {
+ Log.d(TAG, "RemoteController: onNowPlayingContentChange");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientNowPlayingContentChange();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on Now Playing Content Change", e);
+ }
+ }
+
+ private void onSetPlayItemResponse(boolean success) {
+ Log.d(TAG, "RemoteController: onPlayItemResponse");
+ final OnClientAvrcpUpdateListener l;
+
+ synchronized(mInfoLock) {
+ l = mOnClientAvrcpUpdateListener;
+ }
+
+ try {
+ if (l != null) {
+ l.onClientPlayItemResponse(success);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error Updating AVRCP on receiving Play Item response", e);
+ }
+ }
+
//==================================================
private static class PlaybackInfo {
int mState;
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bd0019f..34eadcb 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -45,6 +45,10 @@ interface ISession {
void setQueueTitle(CharSequence title);
void setExtras(in Bundle extras);
void setRatingType(int type);
+ void playItemResponse(boolean success);
+ void updateNowPlayingEntries(in long[] playList);
+ void updateFolderInfoBrowsedPlayer(String stringUri);
+ void updateNowPlayingContentChange();
// These commands relate to volume handling
void setPlaybackToLocal(in AudioAttributes attributes);
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index adb6b06..ed13ff6 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -41,6 +41,9 @@ oneway interface ISessionCallback {
void onFastForward();
void onRewind();
void onSeekTo(long pos);
+ void setRemoteControlClientBrowsedPlayer();
+ void setRemoteControlClientPlayItem(long uid, int scope);
+ void getRemoteControlClientNowPlayingEntries();
void onRate(in Rating rating);
void onCustomAction(String action, in Bundle args);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 285e5f7..006ffac 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -62,6 +62,9 @@ interface ISessionController {
void fastForward();
void rewind();
void seekTo(long pos);
+ void setRemoteControlClientBrowsedPlayer();
+ void setRemoteControlClientPlayItem(long uid, int scope);
+ void getRemoteControlClientNowPlayingEntries();
void rate(in Rating rating);
void sendCustomAction(String action, in Bundle args);
MediaMetadata getMetadata();
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index cf31767..a5ad913 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -36,4 +36,8 @@ oneway interface ISessionControllerCallback {
void onQueueTitleChanged(CharSequence title);
void onExtrasChanged(in Bundle extras);
void onVolumeInfoChanged(in ParcelableVolumeInfo info);
+ void onPlayItemResponse(boolean success);
+ void onUpdateNowPlayingEntries(in long[] playList);
+ void onUpdateFolderInfoBrowsedPlayer(String stringUri);
+ void onUpdateNowPlayingContentChange();
}
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b1a51a5..f1f9516 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -64,6 +64,10 @@ public final class MediaController {
private static final int MSG_UPDATE_QUEUE_TITLE = 6;
private static final int MSG_UPDATE_EXTRAS = 7;
private static final int MSG_DESTROYED = 8;
+ private static final int MSG_FOLDER_INFO_BROWSED_PLAYER = 9;
+ private static final int MSG_UPDATE_NOWPLAYING_ENTRIES = 10;
+ private static final int MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE = 11;
+ private static final int MSG_PLAY_ITEM_RESPONSE = 12;
private final ISessionController mSessionBinder;
@@ -579,6 +583,31 @@ public final class MediaController {
*/
public void onAudioInfoChanged(PlaybackInfo info) {
}
+
+ /**
+ * @hide
+ */
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
+ }
+
+ /**
+ * @hide
+ */
+ public void onUpdateNowPlayingEntries(long[] playList) {
+ }
+
+ /**
+ * @hide
+ */
+ public void onUpdateNowPlayingContentChange() {
+ }
+
+ /**
+ * @hide
+ */
+ public void onPlayItemResponse(boolean success) {
+ }
+
}
/**
@@ -704,6 +733,7 @@ public final class MediaController {
* @param pos Position to move to, in milliseconds.
*/
public void seekTo(long pos) {
+ Log.d(TAG, "seekTo in TransportControls");
try {
mSessionBinder.seekTo(pos);
} catch (RemoteException e) {
@@ -712,6 +742,42 @@ public final class MediaController {
}
/**
+ * @hide
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer in TransportControls");
+ try {
+ mSessionBinder.setRemoteControlClientBrowsedPlayer();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling setRemoteControlClientBrowsedPlayer.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ Log.d(TAG, "setRemoteControlClientPlayItem in TransportControls");
+ try {
+ mSessionBinder.setRemoteControlClientPlayItem(uid, scope);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling setRemoteControlClientPlayItem.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void getRemoteControlClientNowPlayingEntries() {
+ Log.d(TAG, "getRemoteControlClientNowPlayingEntries in TransportControls");
+ try {
+ mSessionBinder.getRemoteControlClientNowPlayingEntries();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling getRemoteControlClientNowPlayingEntries.", e);
+ }
+ }
+
+ /**
* Start fast forwarding. If playback is already fast forwarding this
* may increase the rate.
*/
@@ -973,6 +1039,42 @@ public final class MediaController {
}
}
+ @Override
+ public void onUpdateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "CallBackStub: onUpdateFolderInfoBrowsedPlayer");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_FOLDER_INFO_BROWSED_PLAYER, stringUri, null);
+ }
+ }
+
+ @Override
+ public void onUpdateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "CallBackStub: onUpdateNowPlayingEntries");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_UPDATE_NOWPLAYING_ENTRIES, playList, null);
+ }
+ }
+
+ @Override
+ public void onUpdateNowPlayingContentChange() {
+ Log.d(TAG, "CallBackStub: onUpdateNowPlayingContentChange");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE, null, null);
+ }
+ }
+
+ @Override
+ public void onPlayItemResponse(boolean success) {
+ Log.d(TAG, "CallBackStub: onPlayItemResponse");
+ MediaController controller = mController.get();
+ if (controller != null) {
+ controller.postMessage(MSG_PLAY_ITEM_RESPONSE, new Boolean(success), null);
+ }
+ }
+
}
private final static class MessageHandler extends Handler {
@@ -1014,6 +1116,18 @@ public final class MediaController {
case MSG_DESTROYED:
mCallback.onSessionDestroyed();
break;
+ case MSG_FOLDER_INFO_BROWSED_PLAYER:
+ mCallback.onUpdateFolderInfoBrowsedPlayer((String) msg.obj);
+ break;
+ case MSG_UPDATE_NOWPLAYING_ENTRIES:
+ mCallback.onUpdateNowPlayingEntries((long[]) msg.obj);
+ break;
+ case MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE:
+ mCallback.onUpdateNowPlayingContentChange();
+ break;
+ case MSG_PLAY_ITEM_RESPONSE:
+ mCallback.onPlayItemResponse(((Boolean)(msg.obj)).booleanValue());
+ break;
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e1e9b79..be89dfc 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -493,6 +493,58 @@ public final class MediaSession {
}
/**
+ * @hide
+ */
+ public void playItemResponse(boolean success) {
+ Log.d(TAG, "MediaSession: playItemResponse");
+
+ try {
+ mBinder.playItemResponse(success);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in playItemResponse.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "MediaSession: updateNowPlayingEntries");
+
+ try {
+ mBinder.updateNowPlayingEntries(playList);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in updateNowPlayingEntries.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "MediaSession: updateFolderInfoBrowsedPlayer");
+
+ try {
+ mBinder.updateFolderInfoBrowsedPlayer(stringUri);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in updateFolderInfoBrowsedPlayer.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void updateNowPlayingContentChange() {
+ Log.d(TAG, "MediaSession: updateNowPlayingContentChange");
+
+ try {
+ mBinder.updateNowPlayingContentChange();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Dead object in updateNowPlayingContentChange.", e);
+ }
+ }
+
+ /**
* Notify the system that the remote volume changed.
*
* @param provider The provider that is handling volume changes.
@@ -572,6 +624,34 @@ public final class MediaSession {
postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
}
+ private void dispatchSetBrowsedPlayerCommand() {
+ postToCallback(CallbackMessageHandler.MSG_SET_BROWSED_PLAYER);
+ }
+
+ private void dispatchSetPlayItemCommand(long uid, int scope) {
+ PlayItemToken playItemToken = new PlayItemToken(uid, scope);
+ postToCallback(CallbackMessageHandler.MSG_SET_PLAY_ITEM, playItemToken);
+ }
+
+ private class PlayItemToken {
+ private long mUid;
+ private int mScope;
+ public PlayItemToken(long uid, int scope) {
+ mUid = uid;
+ mScope = scope;
+ }
+ public int getScope() {
+ return mScope;
+ }
+ public long getUid() {
+ return mUid;
+ }
+ }
+
+ private void dispatchGetNowPlayingItemsCommand() {
+ postToCallback(CallbackMessageHandler.MSG_GET_NOW_PLAYING_ITEMS);
+ }
+
private void dispatchAdjustVolume(int direction) {
postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction);
}
@@ -894,6 +974,25 @@ public final class MediaSession {
*/
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
}
+
+ /**
+ * @hide
+ */
+ public void setBrowsedPlayer() {
+ }
+
+ /**
+ * @hide
+ */
+ public void setPlayItem(int scope, long uid) {
+ }
+
+ /**
+ * @hide
+ */
+ public void getNowPlayingEntries() {
+ }
+
}
/**
@@ -1034,6 +1133,33 @@ public final class MediaSession {
}
@Override
+ public void setRemoteControlClientBrowsedPlayer() throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer in CallbackStub");
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchSetBrowsedPlayerCommand();
+ }
+ }
+
+ @Override
+ public void setRemoteControlClientPlayItem(long uid, int scope) throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientPlayItem in CallbackStub");
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchSetPlayItemCommand(uid, scope);
+ }
+ }
+
+ @Override
+ public void getRemoteControlClientNowPlayingEntries() throws RemoteException {
+ Log.d(TAG, "getRemoteControlClientNowPlayingEntries in CallbackStub");
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchGetNowPlayingItemsCommand();
+ }
+ }
+
+ @Override
public void onCustomAction(String action, Bundle args) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1173,6 +1299,9 @@ public final class MediaSession {
private static final int MSG_ADJUST_VOLUME = 16;
private static final int MSG_SET_VOLUME = 17;
private static final int MSG_PLAY_URI = 18;
+ private static final int MSG_SET_BROWSED_PLAYER = 19;
+ private static final int MSG_SET_PLAY_ITEM = 20;
+ private static final int MSG_GET_NOW_PLAYING_ITEMS = 21;
private MediaSession.Callback mCallback;
@@ -1267,6 +1396,18 @@ public final class MediaSession {
if (vp != null) {
vp.onSetVolumeTo((int) msg.obj);
}
+ case MSG_SET_BROWSED_PLAYER:
+ Log.d(TAG, "MSG_SET_BROWSED_PLAYER received in CallbackMessageHandler");
+ mCallback.setBrowsedPlayer();
+ break;
+ case MSG_SET_PLAY_ITEM:
+ Log.d(TAG, "MSG_SET_PLAY_ITEM received in CallbackMessageHandler");
+ PlayItemToken playItemToken = (PlayItemToken) msg.obj;
+ mCallback.setPlayItem(playItemToken.getScope(), playItemToken.getUid());
+ break;
+ case MSG_GET_NOW_PLAYING_ITEMS:
+ Log.d(TAG, "MSG_GET_NOW_PLAYING_ITEMS received in CallbackMessageHandler");
+ mCallback.getNowPlayingEntries();
break;
}
}
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c61d7ad..22082b9 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -549,6 +549,27 @@ public class MediaSessionLegacyHelper {
mRccListener.onSetRating(rating);
}
}
+
+ @Override
+ public void setBrowsedPlayer() {
+ if (mRccListener != null) {
+ mRccListener.setBrowsedPlayer();
+ }
+ }
+
+ @Override
+ public void setPlayItem(int scope, long uid) {
+ if (mRccListener != null) {
+ mRccListener.setPlayItem(scope, uid);
+ }
+ }
+
+ @Override
+ public void getNowPlayingEntries() {
+ if (mRccListener != null) {
+ mRccListener.getNowPlayingEntries();
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7565e9d..4b618bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -171,6 +171,27 @@ public class AudioService extends IAudioService.Stub {
// the platform type affects volume and silent mode behavior
private final int mPlatformType;
+ private static final ArrayList<MediaPlayerInfo> mMediaPlayers =
+ new ArrayList<MediaPlayerInfo>();
+
+ private class MediaPlayerInfo {
+ private String mPackageName;
+ private boolean mIsfocussed;
+ public MediaPlayerInfo(String packageName, boolean isfocussed) {
+ mPackageName = packageName;
+ mIsfocussed = isfocussed;
+ }
+ public boolean isFocussed() {
+ return mIsfocussed;
+ }
+ public void setFocus(boolean focus) {
+ mIsfocussed = focus;
+ }
+ public String getPackageName() {
+ return mPackageName;
+ }
+ }
+
private boolean isPlatformVoice() {
return mPlatformType == AudioSystem.PLATFORM_VOICE;
}
@@ -861,6 +882,100 @@ public class AudioService extends IAudioService.Stub {
}
}
+ /**
+ * @hide
+ */
+ public void addMediaPlayerAndUpdateRemoteController (String packageName) {
+ Log.v(TAG, "addMediaPlayerAndUpdateRemoteController: size of existing list: " +
+ mMediaPlayers.size());
+ boolean playerToAdd = true;
+ if (mMediaPlayers.size() > 0) {
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo player = rccIterator.next();
+ if (packageName.equals(player.getPackageName())) {
+ Log.e(TAG, "Player entry present, no need to add");
+ playerToAdd = false;
+ player.setFocus(true);
+ } else {
+ Log.e(TAG, "Player: " + player.getPackageName()+ "Lost Focus");
+ player.setFocus(false);
+ }
+ }
+ }
+ if (playerToAdd) {
+ Log.e(TAG, "Adding Player: " + packageName + " to available player list");
+ mMediaPlayers.add(new MediaPlayerInfo(packageName, true));
+ }
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, true);
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "updating focussed RCC change to RCD: CallingPackageName:"
+ + packageName);
+ }
+
+ /**
+ * @hide
+ */
+ public void updateRemoteControllerOnExistingMediaPlayers() {
+ Log.v(TAG, "updateRemoteControllerOnExistingMediaPlayers: size of Player list: " +
+ mMediaPlayers.size());
+ if (mMediaPlayers.size() > 0) {
+ Log.v(TAG, "Inform RemoteController regarding existing RCC entry");
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo player = rccIterator.next();
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME,
+ player.getPackageName());
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE,
+ player.isFocussed());
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "updating RCC change: CallingPackageName:" +
+ player.getPackageName());
+ }
+ } else {
+ Log.e(TAG, "No RCC entry present to update");
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void removeMediaPlayerAndUpdateRemoteController (String packageName) {
+ Log.v(TAG, "removeMediaPlayerAndUpdateRemoteController: size of existing list: " +
+ mMediaPlayers.size());
+ boolean playerToRemove = false;
+ int index = -1;
+ if (mMediaPlayers.size() > 0) {
+ final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ index++;
+ final MediaPlayerInfo player = rccIterator.next();
+ if (packageName.equals(player.getPackageName())) {
+ Log.v(TAG, "Player entry present remove and update RemoteController");
+ playerToRemove = true;
+ break;
+ } else {
+ Log.v(TAG, "Player entry for " + player.getPackageName()+ " is not present");
+ }
+ }
+ }
+ if (playerToRemove) {
+ Log.e(TAG, "Removing Player: " + packageName + " from index" + index);
+ mMediaPlayers.remove(index);
+ }
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, false);
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, false);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "Updated List size: " + mMediaPlayers.size());
+ }
+
private void checkAllAliasStreamVolumes() {
synchronized (VolumeStreamState.class) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -5185,6 +5300,18 @@ public class AudioService extends IAudioService.Stub {
mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
}
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ mMediaFocusControl.setRemoteControlClientPlayItem(uid, scope);
+ }
+
+ public void getRemoteControlClientNowPlayingEntries() {
+ mMediaFocusControl.getRemoteControlClientNowPlayingEntries();
+ }
+
+ public void setRemoteControlClientBrowsedPlayer() {
+ mMediaFocusControl.setRemoteControlClientBrowsedPlayer();
+ }
+
@Override
public void setRemoteStreamVolume(int index) {
enforceVolumeController("set the remote stream volume");
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index f72b598..af880bd 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -335,6 +335,9 @@ public class MediaFocusControl implements OnFinished {
private static final int MSG_RCDISPLAY_INIT_INFO = 9;
private static final int MSG_REEVALUATE_RCD = 10;
private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 11;
+ private static final int MSG_RCC_SET_BROWSED_PLAYER = 12;
+ private static final int MSG_RCC_SET_PLAY_ITEM = 13;
+ private static final int MSG_RCC_GET_NOW_PLAYING_ENTRIES = 14;
// sendMsg() flags
/** If the msg is already queued, replace it with this one. */
@@ -382,6 +385,22 @@ public class MediaFocusControl implements OnFinished {
(IRemoteVolumeObserver)msg.obj /* rvo */);
break;
+ case MSG_RCC_SET_PLAY_ITEM:
+ Log.d(TAG, "MSG_RCC_SET_PLAY_ITEM: "+ ((Long)msg.obj).longValue());
+ onSetRemoteControlClientPlayItem(msg.arg2 /* scope */,
+ ((Long)msg.obj).longValue() /* uid */);
+ break;
+
+ case MSG_RCC_GET_NOW_PLAYING_ENTRIES:
+ Log.d(TAG, "MSG_RCC_GET_NOW_PLAYING_ENTRIES: ");
+ onGetRemoteControlClientNowPlayingEntries();
+ break;
+
+ case MSG_RCC_SET_BROWSED_PLAYER:
+ Log.d(TAG, "MSG_RCC_SET_BROWSED_PLAYER: ");
+ onSetRemoteControlClientBrowsedPlayer();
+ break;
+
case MSG_RCDISPLAY_INIT_INFO:
// msg.obj is guaranteed to be non null
onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
@@ -2052,6 +2071,66 @@ public class MediaFocusControl implements OnFinished {
}
}
+ public void setRemoteControlClientPlayItem(long uid, int scope) {
+ sendMsg(mEventHandler, MSG_RCC_SET_PLAY_ITEM, SENDMSG_REPLACE, 0 /* arg1 */,
+ scope /* arg2*/, new Long(uid) /* obj */, 0 /* delay */);
+ }
+
+ private void onSetRemoteControlClientPlayItem(int scope, Long uid) {
+ Log.d(TAG, "onSetRemoteControlClientPlayItem: "+ uid);
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClient != null) {
+ try {
+ mCurrentRcClient.setPlayItem(scope, uid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+e);
+ mCurrentRcClient = null;
+ }
+ }
+ }
+ }
+
+ public void getRemoteControlClientNowPlayingEntries() {
+ sendMsg(mEventHandler, MSG_RCC_GET_NOW_PLAYING_ENTRIES, SENDMSG_REPLACE,
+ 0 /* arg1 */, 0 /* arg2 ignored*/, 0 /* obj */, 0 /* delay */);
+ }
+
+ private void onGetRemoteControlClientNowPlayingEntries() {
+ Log.d(TAG, "onGetRemoteControlClientNowPlayingEntries: ");
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClient != null) {
+ try {
+ mCurrentRcClient.getNowPlayingEntries();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+e);
+ mCurrentRcClient = null;
+ }
+ }
+ }
+ }
+
+ public void setRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer: ");
+ sendMsg(mEventHandler, MSG_RCC_SET_BROWSED_PLAYER, SENDMSG_REPLACE, 0/* arg1 */,
+ 0 /* arg2 ignored*/, 0 /* obj */, 0 /* delay */);
+ }
+
+ private void onSetRemoteControlClientBrowsedPlayer() {
+ Log.d(TAG, "onSetRemoteControlClientBrowsedPlayer: ");
+ PlayerRecord prse = mPRStack.peek();
+ if (prse.getRcc() == null) {
+ Log.d(TAG, "can not proceed with setBrowsedPlayer");
+ } else {
+ Log.d(TAG, "proceed with setBrowsedPlayer");
+ try {
+ Log.d(TAG, "Calling setBrowsedPlayer");
+ prse.getRcc().setBrowsedPlayer();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+ e);
+ }
+ }
+ }
+
// handler for MSG_RCC_NEW_VOLUME_OBS
private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
synchronized(mPRStack) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index f92f631..bc830f0 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -106,6 +106,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private CharSequence mQueueTitle;
private int mRatingType;
private long mLastActiveTime;
+ private String mBrowsedPlayerURI;
+ private boolean mPlayItemStatus;
+ private long[] mNowPlayingList;
// End TransportPerformer fields
// Volume handling fields
@@ -518,6 +521,86 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ private void pushBrowsePlayerInfo() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushBrowsePlayerInfo");
+ cb.onUpdateFolderInfoBrowsedPlayer(mBrowsedPlayerURI);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushBrowsePlayerInfo. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushBrowsePlayerInfo. ", e);
+ }
+ }
+ }
+ }
+
+ private void pushNowPlayingEntries() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushNowPlayingEntries");
+ cb.onUpdateNowPlayingEntries(mNowPlayingList);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushNowPlayingEntries. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushNowPlayingEntries. ", e);
+ }
+ }
+ }
+ }
+
+ private void pushNowPlayingContentChange() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushNowPlayingContentChange");
+ cb.onUpdateNowPlayingContentChange();
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushNowPlayingContentChange. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushNowPlayingContentChange. ", e);
+ }
+ }
+ }
+ }
+
+ private void pushPlayItemResponse() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
+ try {
+ Log.d(TAG, "pushPlayItemResponse");
+ cb.onPlayItemResponse(mPlayItemStatus);
+ } catch (DeadObjectException e) {
+ Log.w(TAG, "Removing dead callback in pushPlayItemResponse. ", e);
+ mControllerCallbacks.remove(i);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unexpected exception in pushPlayItemResponse. ", e);
+ }
+ }
+ }
+ }
+
private void pushQueueUpdate() {
synchronized (mLock) {
if (mDestroyed) {
@@ -775,6 +858,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void updateFolderInfoBrowsedPlayer(String stringUri) {
+ Log.d(TAG, "SessionStub: updateFolderInfoBrowsedPlayer");
+ mBrowsedPlayerURI = stringUri;
+ mHandler.post(MessageHandler.MSG_FOLDER_INFO_BROWSED_PLAYER);
+ }
+
+ @Override
+ public void updateNowPlayingEntries(long[] playList) {
+ Log.d(TAG, "SessionStub: updateNowPlayingEntries");
+ mNowPlayingList = playList;
+ mHandler.post(MessageHandler.MSG_UPDATE_NOWPLAYING_ENTRIES);
+ }
+
+ @Override
+ public void updateNowPlayingContentChange() {
+ Log.d(TAG, "SessionStub: updateNowPlayingContentChange");
+ mHandler.post(MessageHandler.MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE);
+ }
+
+ @Override
+ public void playItemResponse(boolean success) {
+ Log.d(TAG, "SessionStub: playItemResponse");
+ mPlayItemStatus = success;
+ mHandler.post(MessageHandler.MSG_PLAY_ITEM_RESPONSE);
+ }
+
+ @Override
public void setQueueTitle(CharSequence title) {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
@@ -957,6 +1067,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
public void seekTo(long pos) {
+ Slog.d(TAG, "seekTo in SessionCb");
try {
mCb.onSeekTo(pos);
} catch (RemoteException e) {
@@ -964,6 +1075,42 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ /**
+ * @hide
+ */
+ public void setRemoteControlClientBrowsedPlayer() {
+ Slog.d(TAG, "setRemoteControlClientBrowsedPlayer in SessionCb");
+ try {
+ mCb.setRemoteControlClientBrowsedPlayer();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in setRemoteControlClientBrowsedPlayer.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setRemoteControlClientPlayItem(long uid, int scope) throws RemoteException {
+ Slog.d(TAG, "setRemoteControlClientPlayItem in SessionCb");
+ try {
+ mCb.setRemoteControlClientPlayItem(uid, scope);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in setRemoteControlClientPlayItem.", e);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void getRemoteControlClientNowPlayingEntries() throws RemoteException {
+ Slog.d(TAG, "getRemoteControlClientNowPlayingEntries in SessionCb");
+ try {
+ mCb.getRemoteControlClientNowPlayingEntries();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in getRemoteControlClientNowPlayingEntries.", e);
+ }
+ }
+
public void rate(Rating rating) {
try {
mCb.onRate(rating);
@@ -1157,10 +1304,29 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void seekTo(long pos) throws RemoteException {
+ Log.d(TAG, "seekTo in ControllerStub");
mSessionCb.seekTo(pos);
}
@Override
+ public void setRemoteControlClientBrowsedPlayer() throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientBrowsedPlayer in ControllerStub");
+ mSessionCb.setRemoteControlClientBrowsedPlayer();
+ }
+
+ @Override
+ public void setRemoteControlClientPlayItem(long uid, int scope) throws RemoteException {
+ Log.d(TAG, "setRemoteControlClientPlayItem in ControllerStub");
+ mSessionCb.setRemoteControlClientPlayItem(uid, scope);
+ }
+
+ @Override
+ public void getRemoteControlClientNowPlayingEntries() throws RemoteException {
+ Log.d(TAG, "getRemoteControlClientNowPlayingEntries in ControllerStub");
+ mSessionCb.getRemoteControlClientNowPlayingEntries();
+ }
+
+ @Override
public void rate(Rating rating) throws RemoteException {
mSessionCb.rate(rating);
}
@@ -1224,6 +1390,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private static final int MSG_UPDATE_SESSION_STATE = 7;
private static final int MSG_UPDATE_VOLUME = 8;
private static final int MSG_DESTROYED = 9;
+ private static final int MSG_FOLDER_INFO_BROWSED_PLAYER = 10;
+ private static final int MSG_UPDATE_NOWPLAYING_ENTRIES = 11;
+ private static final int MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE = 12;
+ private static final int MSG_PLAY_ITEM_RESPONSE = 13;
public MessageHandler(Looper looper) {
super(looper);
@@ -1257,6 +1427,18 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
break;
case MSG_DESTROYED:
pushSessionDestroyed();
+ case MSG_FOLDER_INFO_BROWSED_PLAYER:
+ pushBrowsePlayerInfo();
+ break;
+ case MSG_UPDATE_NOWPLAYING_ENTRIES:
+ pushNowPlayingEntries();
+ break;
+ case MSG_UPDATE_NOWPLAYING_CONTENT_CHANGE:
+ pushNowPlayingContentChange();
+ break;
+ case MSG_PLAY_ITEM_RESPONSE:
+ pushPlayItemResponse();
+ break;
}
}