Merge "RemoteControlClient receives playback position change requests" into jb-mr2-dev

This commit is contained in:
Jean-Michel Trivi
2013-04-03 21:11:12 +00:00
committed by Android (Google) Code Review
9 changed files with 177 additions and 37 deletions

View File

@@ -158,7 +158,7 @@ public class TransportControlView extends FrameLayout implements OnClickListener
}
}
public void setTransportControlFlags(int generationId, int flags) {
public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)

View File

@@ -2273,6 +2273,26 @@ public class AudioManager {
}
}
/**
* @hide
* Request the user of a RemoteControlClient to seek to the given playback position.
* @param generationId the RemoteControlClient generation counter for which this request is
* issued. Requests for an older generation than current one will be ignored.
* @param timeMs the time in ms to seek to, must be positive.
*/
public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
if (timeMs < 0) {
return;
}
IAudioService service = getService();
try {
service.setRemoteControlClientPlaybackPosition(generationId, timeMs);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setRccPlaybackPosition("+ generationId + ", "
+ timeMs + ")", e);
}
}
/**
* @hide
* Reload audio settings. This method is called by Settings backup

View File

@@ -167,7 +167,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 30;
private static final int MSG_UNLOAD_SOUND_EFFECTS = 31;
private static final int MSG_RCC_NEW_PLAYBACK_STATE = 32;
private static final int MSG_RCC_SEEK_REQUEST = 33;
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
// Timeout for connection to bluetooth headset service
@@ -4708,6 +4708,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
};
/**
* Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
*/
private final Object mCurrentRcLock = new Object();
/**
* The one remote control client which will receive a request for display information.
@@ -4979,6 +4982,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
" -- volMax: " + rcse.mPlaybackVolumeMax +
" -- volObs: " + rcse.mRemoteVolumeObs);
}
synchronized(mCurrentRcLock) {
pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
}
}
synchronized (mMainRemote) {
pw.println("\nRemote Volume State:");
@@ -5813,6 +5819,29 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_QUEUE, generationId /* arg1 */,
0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
}
public void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
", timeMs=" + timeMs + ")");
synchronized(mRCStack) {
synchronized(mCurrentRcLock) {
if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
// tell the current client to seek to the requested location
try {
mCurrentRcClient.seekTo(generationId, timeMs);
} catch (RemoteException e) {
Log.e(TAG, "Current valid remote client is dead: "+e);
mCurrentRcClient = null;
}
}
}
}
}
public void setPlaybackInfoForRcc(int rccId, int what, int value) {
sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);

View File

@@ -126,11 +126,6 @@ interface IAudioService {
oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c);
oneway void unregisterMediaButtonEventReceiverForCalls();
int registerRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient, in String callingPackageName);
oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient);
/**
* Register an IRemoteControlDisplay.
* Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
@@ -157,9 +152,29 @@ interface IAudioService {
* display doesn't need to receive artwork.
*/
oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h);
/**
* Request the user of a RemoteControlClient to seek to the given playback position.
* @param generationId the RemoteControlClient generation counter for which this request is
* issued. Requests for an older generation than current one will be ignored.
* @param timeMs the time in ms to seek to, must be positive.
*/
void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
/**
* Do not use directly, use instead
* {@link android.media.AudioManager#registerRemoteControlClient(RemoteControlClient)}
*/
int registerRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient, in String callingPackageName);
/**
* Do not use directly, use instead
* {@link android.media.AudioManager#unregisterRemoteControlClient(RemoteControlClient)}
*/
oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
in IRemoteControlClient rcClient);
oneway void setPlaybackInfoForRcc(int rccId, int what, int value);
void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed);
void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed);
int getRemoteStreamMaxVolume();
int getRemoteStreamVolume();
oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);

View File

@@ -47,4 +47,5 @@ oneway interface IRemoteControlClient
void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
void seekTo(int clientGeneration, long timeMs);
}

View File

@@ -43,7 +43,16 @@ oneway interface IRemoteControlDisplay
void setPlaybackState(int generationId, int state, long stateChangeTimeMs, long currentPosMs,
float speed);
void setTransportControlFlags(int generationId, int transportControlFlags);
/**
* Sets the transport control flags and playback position capabilities of a client.
* @param generationId the current generation ID as known by this client
* @param transportControlFlags bitmask of the transport controls this client supports, see
* {@link RemoteControlClient#setTransportControlFlags(int)}
* @param posCapabilities a bit mask for playback position capabilities, see
* {@link RemoteControlClient#MEDIA_POSITION_READABLE} and
* {@link RemoteControlClient#MEDIA_POSITION_WRITABLE}
*/
void setTransportControlInfo(int generationId, int transportControlFlags, int posCapabilities);
void setMetadata(int generationId, in Bundle metadata);

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

View File

@@ -147,7 +147,7 @@ public class KeyguardTransportControlView extends FrameLayout implements OnClick
}
}
public void setTransportControlFlags(int generationId, int flags) {
public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
Handler handler = mLocalHandler.get();
if (handler != null) {
handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)

View File

@@ -211,7 +211,7 @@ public class KeyguardUpdateMonitor {
}
public void setTransportControlFlags(int generationId, int flags) {
public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
}