RemoteControlClient receives playback position change requests

RemoteControlClient defines two listener interfaces for playback
  position, one to let the framework query the current playback
  position, the other to request playback to seek to a given
  position.

Updated IRemoteControlDisplay interface to support passing info
  about whether the user of RemoteControlClient can provide a
  playback position, and receive a new one.
Updated implementations of IRemoteControlDisplay to new
  interface.

Bug 8120740

Change-Id: I1a5a969da4d0f8c9ad27f691919dd08f8653982b
This commit is contained in:
Jean-Michel Trivi
2013-04-01 14:59:39 -07:00
parent 73882cf489
commit 3261b537c5
9 changed files with 177 additions and 37 deletions

View File

@@ -278,11 +278,14 @@ public class RemoteControlClient
public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
/**
* @hide
* (to be un-hidden and added in javadoc of setTransportControlFlags(int))
* TODO un-hide and add in javadoc of setTransportControlFlags(int)
* Flag indicating a RemoteControlClient can receive changes in the media playback position
* through the {@link #OnPlaybackPositionUpdateListener} interface.
*
* through the {@link #OnPlaybackPositionUpdateListener} interface. This flag must be set
* in order for components that display the RemoteControlClient information, to display and
* let the user control media playback position.
* @see #setTransportControlFlags(int)
* @see #setPlaybackPositionProvider(PlaybackPositionProvider)
* @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
*/
public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
@@ -605,7 +608,7 @@ public class RemoteControlClient
/**
* @hide
* (to be un-hidden)
* TODO un-hide
* Sets the current playback state and the matching media position for the current playback
* speed.
* @param state The current playback state, one of the following values:
@@ -630,11 +633,6 @@ public class RemoteControlClient
*/
public void setPlaybackState(int state, long timeInMs, float playbackSpeed) {
synchronized(mCacheLock) {
if (timeInMs != PLAYBACK_POSITION_INVALID) {
mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
} else {
mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
}
if ((mPlaybackState != state) || (mPlaybackPositionMs != timeInMs)
|| (mPlaybackSpeed != playbackSpeed)) {
// store locally
@@ -670,19 +668,20 @@ public class RemoteControlClient
mTransportControlFlags = transportControlFlags;
// send to remote control display if conditions are met
sendTransportControlFlags_syncCacheLock();
sendTransportControlInfo_syncCacheLock();
}
}
/**
* @hide
* (to be un-hidden)
* TODO un-hide
* Interface definition for a callback to be invoked when the media playback position is
* requested to be updated.
* @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
*/
public interface OnPlaybackPositionUpdateListener {
/**
* Called on the listener to notify it that the playback head should be set at the given
* Called on the implementer to notify it that the playback head should be set at the given
* position. If the position can be changed from its current value, the implementor of
* the interface should also update the playback position using
* {@link RemoteControlClient#setPlaybackState(int, long, int)} to reflect the actual new
@@ -694,8 +693,25 @@ public class RemoteControlClient
/**
* @hide
* (to be un-hidden)
* Sets the listener RemoteControlClient calls whenever the media playback position is requested
* TODO un-hide
* Interface definition for a callback to be invoked when the media playback position is
* queried.
* @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
*/
public interface PlaybackPositionProvider {
/**
* Called on the implementer of the interface to query the current playback position.
* @return a negative value if the current playback position (or the last valid playback
* position) is not known, or a zero or positive value expressed in ms indicating the
* current position, or the last valid known position.
*/
long getPlaybackPosition();
}
/**
* @hide
* TODO un-hide
* Sets the listener to be called whenever the media playback position is requested
* to be updated.
* Notifications will be received in the same thread as the one in which RemoteControlClient
* was created.
@@ -703,16 +719,41 @@ public class RemoteControlClient
*/
public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
synchronized(mCacheLock) {
if ((mPositionUpdateListener == null) && (l != null)) {
int oldCapa = mPlaybackPositionCapabilities;
if (l != null) {
mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
// tell RCDs and AudioService this RCC accepts position updates
// TODO implement
} else if ((mPositionUpdateListener != null) && (l == null)) {
} else {
mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
// tell RCDs and AudioService this RCC doesn't handle position updates
// TODO implement
}
mPositionUpdateListener = l;
if (oldCapa != mPlaybackPositionCapabilities) {
// tell RCDs that this RCC's playback position capabilities have changed
sendTransportControlInfo_syncCacheLock();
}
}
}
/**
* @hide
* TODO un-hide
* Sets the listener to be called whenever the media current playback position is needed.
* Queries will be received in the same thread as the one in which RemoteControlClient
* was created.
* @param l
*/
public void setPlaybackPositionProvider(PlaybackPositionProvider l) {
synchronized(mCacheLock) {
int oldCapa = mPlaybackPositionCapabilities;
if (l != null) {
mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
} else {
mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
}
mPositionProvider = l;
if (oldCapa != mPlaybackPositionCapabilities) {
// tell RCDs that this RCC's playback position capabilities have changed
sendTransportControlInfo_syncCacheLock();
}
}
}
@@ -895,6 +936,10 @@ public class RemoteControlClient
* update requests.
*/
private OnPlaybackPositionUpdateListener mPositionUpdateListener;
/**
* Provider registered by user of RemoteControlClient to provide the current playback position.
*/
private PlaybackPositionProvider mPositionProvider;
/**
* The current remote control client generation ID across the system, as known by this object
*/
@@ -957,14 +1002,14 @@ public class RemoteControlClient
*/
private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
public void onInformationRequested(int clientGeneration, int infoFlags) {
public void onInformationRequested(int generationId, int infoFlags) {
// only post messages, we can't block here
if (mEventHandler != null) {
// signal new client
mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
mEventHandler.dispatchMessage(
mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
/*arg1*/ clientGeneration, /*arg2, ignored*/ 0));
/*arg1*/ generationId, /*arg2, ignored*/ 0));
// send the information
mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
mEventHandler.removeMessages(MSG_REQUEST_METADATA);
@@ -1011,6 +1056,16 @@ public class RemoteControlClient
MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
}
}
public void seekTo(int generationId, long timeMs) {
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.removeMessages(MSG_SEEK_TO);
mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
new Long(timeMs)));
}
}
};
/**
@@ -1051,6 +1106,7 @@ public class RemoteControlClient
private final static int MSG_PLUG_DISPLAY = 7;
private final static int MSG_UNPLUG_DISPLAY = 8;
private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
private final static int MSG_SEEK_TO = 10;
private class EventHandler extends Handler {
public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1072,7 +1128,7 @@ public class RemoteControlClient
break;
case MSG_REQUEST_TRANSPORTCONTROL:
synchronized (mCacheLock) {
sendTransportControlFlags_syncCacheLock();
sendTransportControlInfo_syncCacheLock();
}
break;
case MSG_REQUEST_ARTWORK:
@@ -1095,6 +1151,8 @@ public class RemoteControlClient
case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
break;
case MSG_SEEK_TO:
onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
}
@@ -1136,14 +1194,14 @@ public class RemoteControlClient
}
}
private void sendTransportControlFlags_syncCacheLock() {
private void sendTransportControlInfo_syncCacheLock() {
if (mCurrentClientGenId == mInternalClientGenId) {
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
try {
di.mRcDisplay.setTransportControlFlags(mInternalClientGenId,
mTransportControlFlags);
di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
mTransportControlFlags, mPlaybackPositionCapabilities);
} catch (RemoteException e) {
Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
e);
@@ -1325,6 +1383,14 @@ public class RemoteControlClient
}
}
private void onSeekTo(int generationId, long timeMs) {
synchronized (mCacheLock) {
if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
mPositionUpdateListener.onPlaybackPositionUpdate(timeMs);
}
}
}
//===========================================================
// Internal utilities