diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index ef02cfdb8ed8b..1b9043a9f5688 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2372,6 +2372,24 @@ public class AudioManager { } } + /** + * @hide + * Notify the user of a RemoteControlClient that it should update its metadata + * @param generationId the RemoteControlClient generation counter for which this request is + * issued. Requests for an older generation than current one will be ignored. + * @param key the metadata key for which a new value exists + * @param value the new metadata value + */ + public void updateRemoteControlClientMetadata(int generationId, int key, long value) { + IAudioService service = getService(); + try { + service.updateRemoteControlClientMetadata(generationId, key, value); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in updateRemoteControlClientMetadata("+ generationId + ", " + + key +", " + value + ")", e); + } + } + /** * @hide * Reload audio settings. This method is called by Settings backup diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 470c571b151f2..7269f0cad3e4c 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -4203,7 +4203,7 @@ public class AudioService extends IAudioService.Stub { public void unregisterMediaButtonIntent(PendingIntent pi) { mMediaFocusControl.unregisterMediaButtonIntent(pi); } - + public int registerRemoteControlClient(PendingIntent mediaIntent, IRemoteControlClient rcClient, String callingPckg) { return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg); @@ -4218,6 +4218,10 @@ public class AudioService extends IAudioService.Stub { mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs); } + public void updateRemoteControlClientMetadata(int generationId, int key, long value) { + mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value); + } + public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 903927b3430a1..c7a749aac3384 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -181,6 +181,14 @@ interface IAudioService { * @param timeMs the time in ms to seek to, must be positive. */ void setRemoteControlClientPlaybackPosition(int generationId, long timeMs); + /** + * Notify the user of a RemoteControlClient that it should update its metadata + * @param generationId the RemoteControlClient generation counter for which this request is + * issued. Requests for an older generation than current one will be ignored. + * @param key the metadata key for which a new value exists + * @param value the new metadata value + */ + void updateRemoteControlClientMetadata(int generationId, int key, long value); /** * Do not use directly, use instead diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl index 223612940bbd5..dd729b4011c86 100644 --- a/media/java/android/media/IRemoteControlClient.aidl +++ b/media/java/android/media/IRemoteControlClient.aidl @@ -49,4 +49,5 @@ oneway interface IRemoteControlClient void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h); void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync); void seekTo(int clientGeneration, long timeMs); + void updateMetadata(int clientGeneration, int key, long value); } \ No newline at end of file diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java index 60a84a6420ee3..ab686e6d43a31 100644 --- a/media/java/android/media/MediaFocusControl.java +++ b/media/java/android/media/MediaFocusControl.java @@ -138,6 +138,7 @@ public class MediaFocusControl implements OnFinished { private static final int MSG_PROMOTE_RCC = 6; private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7; private static final int MSG_RCC_SEEK_REQUEST = 8; + private static final int MSG_RCC_UPDATE_METADATA_LONG = 9; // sendMsg() flags /** If the msg is already queued, replace it with this one. */ @@ -188,18 +189,27 @@ public class MediaFocusControl implements OnFinished { onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, ((Integer)msg.obj).intValue() /* value */); break; + case MSG_RCC_NEW_VOLUME_OBS: onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, (IRemoteVolumeObserver)msg.obj /* rvo */); break; + case MSG_RCC_NEW_PLAYBACK_STATE: onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */, (RccPlaybackState)msg.obj /* newState */); break; + case MSG_RCC_SEEK_REQUEST: onSetRemoteControlClientPlaybackPosition( msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */); + break; + + case MSG_RCC_UPDATE_METADATA_LONG: + onUpdateRemoteControlClientMetadataLong(msg.arg1 /*genId*/, msg.arg2 /*key*/, + ((Long)msg.obj).longValue() /* value */); + break; case MSG_PROMOTE_RCC: onPromoteRcc(msg.arg1); @@ -2070,6 +2080,36 @@ public class MediaFocusControl implements OnFinished { } } + protected void updateRemoteControlClientMetadata(int genId, int key, long value) { + sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA_LONG, SENDMSG_QUEUE, + genId /* arg1 */, key /* arg2 */, Long.valueOf(value) /* obj */, 0 /* delay */); + } + + private void onUpdateRemoteControlClientMetadataLong(int genId, int key, long value) { + if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadataLong(genId=" + genId + + ", what=" + key + ",val=" + value + ")"); + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) { + try { + switch (key) { + case RemoteControlClient.MetadataEditor.LONG_KEY_RATING_BY_USER: + mCurrentRcClient.updateMetadata(genId, key, value); + break; + default: + Log.e(TAG, "unhandled metadata key " + key + " update for RCC " + + genId); + break; + } + } catch (RemoteException e) { + Log.e(TAG, "Current valid remote client is dead", e); + mCurrentRcClient = null; + } + } + } + } + } + protected void setPlaybackInfoForRcc(int rccId, int what, int value) { sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 7379438360ab1..2c211ccf79130 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -293,6 +293,18 @@ public class RemoteControlClient * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener) */ public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8; + /** + * @hide + * CANDIDATE FOR PUBLIC API + * Flag indicating a RemoteControlClient supports ratings. + * This flag must be set in order for components that display the RemoteControlClient + * information, to display ratings information, and, if ratings are declared editable + * (by calling {@link MetadataEditor#addEditableKey(int)} with the + * {@link MetadataEditor#LONG_KEY_RATING_BY_USER} key), it will enable the user to rate + * the media. + * @see #setTransportControlFlags(int) + */ + public final static int FLAG_KEY_MEDIA_RATING = 1 << 9; /** * @hide @@ -389,7 +401,10 @@ public class RemoteControlClient private static final int[] METADATA_KEYS_TYPE_LONG = { MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, - MediaMetadataRetriever.METADATA_KEY_DURATION }; + MediaMetadataRetriever.METADATA_KEY_DURATION, + MetadataEditor.LONG_KEY_RATING_TYPE, + MetadataEditor.LONG_KEY_RATING_BY_OTHERS, + MetadataEditor.LONG_KEY_RATING_BY_USER}; /** * Class used to modify metadata in a {@link RemoteControlClient} object. @@ -400,6 +415,10 @@ public class RemoteControlClient * instance of the MetadataEditor. */ public class MetadataEditor { + /** + * Mask of editable keys. + */ + private long mEditableKeys; /** * @hide */ @@ -431,6 +450,78 @@ public class RemoteControlClient * The metadata key for the content artwork / album art. */ public final static int BITMAP_KEY_ARTWORK = 100; + /** + * @hide + * CANDIDATE FOR PUBLIC API + * The metadata key qualifying the content rating. + * The value associated with this key may be: {@link #RATING_HEART}, + * {@link #RATING_THUMB_UP_DOWN}, or a non-null positive integer expressing a maximum + * number of "stars" for the rating, for which a typical value is 3 or 5. + */ + public final static int LONG_KEY_RATING_TYPE = 101; + /** + * @hide + * CANDIDATE FOR PUBLIC API + * The metadata key for the content's average rating, not the user's rating. + * The value associated with this key may be: an integer value between 0 and 100, + * or {@link #RATING_NOT_RATED} to express that no average rating is available. + *
+ * Note that a rating value up to 100 is not incompatible with a rating type using up + * to 5 stars for instance, as the average may be an non-integer number of stars. + * + * When the rating type is: + *