diff options
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; } } |