summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAyan Ghosh <abghosh@codeaurora.org>2014-07-25 18:07:23 +0530
committerLinux Build Service Account <lnxbuild@localhost>2015-10-06 03:27:00 -0600
commit620c100fe78ccfd67d3ea1aa230c772d32d96e60 (patch)
treeb08132e3704eae03e1000154a5c7f00199d11429
parent6d08e0ed29fc9ac9ebb96c5cecf8a2787c8a0ed8 (diff)
downloadframeworks_base-620c100fe78ccfd67d3ea1aa230c772d32d96e60.zip
frameworks_base-620c100fe78ccfd67d3ea1aa230c772d32d96e60.tar.gz
frameworks_base-620c100fe78ccfd67d3ea1aa230c772d32d96e60.tar.bz2
AVRCP 1.5 implementation
AVRCP 1.5 Implementation Change-Id: I9a21348ec7e0c21735448ea29b781167f01e1580 Bluetooth: Add Total track number. Add support to add total number of tracks in Meta-data Change-Id: I5b1287f791615adcd4f920fe5c7cae0c7c7b04ea CRs-Fixed: 627869 Bluetooth: Modify Avrcp 1.5 implementation to adapt to latest AOSP changes Modify Avrcp 1.5 implementation to adapt to latest AOSP changes. CRs-Fixed: 719567 Change-Id: I0958fb12f573054f1da16df0ac46f3bec7374222 Move media player list management to Audioservice Move media player list management to Audioservice so that list is retained even after BT restart. Change-Id: Ia2455e6def1900b4af2225c50e1b5325a7ce1a98 Update RemoteController on Session update Update RemoteController on Session update in order to update AVRCP player list to honor peer initiated browsing command. This change fixes AVRCP browing failure due stale entry of player session upated to AVRCP player list after device reboot. Change-Id: I529a13e2c8a70e4b53319798c952b41f369b8bec Introduce new interface class for Avrcp Browsing feature Separate out Avrcp Browsing Apis from SDK interface class to ensure compatibility with all available apps implementing the mentioned SDK interface class. Change-Id: I713527ee3622ba28fe92d5bc743b9471632299b3
-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;
}
}