From 6d9734803f15f196a24e0724385dcaf73e28875b Mon Sep 17 00:00:00 2001 From: Christopher Eby Date: Sun, 29 Jan 2012 21:45:49 -0600 Subject: [PATCH] RemoteControlClient --- res/values/translatable.xml | 6 +- src/org/kreed/vanilla/CompatIcs.java | 96 +++++++++++++++++++ .../kreed/vanilla/MediaButtonReceiver.java | 8 ++ src/org/kreed/vanilla/PlaybackService.java | 8 ++ 4 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 src/org/kreed/vanilla/CompatIcs.java diff --git a/res/values/translatable.xml b/res/values/translatable.xml index 5c0d94cf..1b2cfb63 100644 --- a/res/values/translatable.xml +++ b/res/values/translatable.xml @@ -129,10 +129,10 @@ THE SOFTWARE. Audio Output Volume - Use Headset Controls - Single click for play/pause. Double click for next. + Headset/Bluetooth Controls + This is also required for ICS lockscreen controls. External Output Only - Only play music through an external output (e.g. headphones, Bluetooth) + Prevents music from being played through the speakers. Pause When Unplugged Pause when the headphones are unplugged. Play When Plugged diff --git a/src/org/kreed/vanilla/CompatIcs.java b/src/org/kreed/vanilla/CompatIcs.java new file mode 100644 index 00000000..becc59aa --- /dev/null +++ b/src/org/kreed/vanilla/CompatIcs.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 Christopher Eby + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.kreed.vanilla; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaMetadataRetriever; +import android.media.RemoteControlClient; + +/** + * Framework methods only in ICS or above go here. + */ +public class CompatIcs { + /** + * Used with updateRemote method. + */ + private static RemoteControlClient sRemote; + + /** + * Perform initialization required for RemoteControlClient. + * + * @param context A context to use. + * @param am The AudioManager service. + */ + public static void registerRemote(Context context, AudioManager am) + { + if (!MediaButtonReceiver.useHeadsetControls(context)) { + // RemoteControlClient requires MEDIA_BUTTON intent + return; + } + + MediaButtonReceiver.registerMediaButton(context); + + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.setComponent(new ComponentName(context.getPackageName(), MediaButtonReceiver.class.getName())); + PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0); + RemoteControlClient remote = new RemoteControlClient(mediaPendingIntent); + int flags = RemoteControlClient.FLAG_KEY_MEDIA_NEXT + | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS + | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE + | RemoteControlClient.FLAG_KEY_MEDIA_PLAY + | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE; + remote.setTransportControlFlags(flags); + am.registerRemoteControlClient(remote); + sRemote = remote; + } + + /** + * Update the remote with new metadata. + * {@link #registerRemote(Context, AudioManager)} must have been called + * first. + * + * @param context A context to use. + * @param song The song containing the new metadata. + * @param state PlaybackService state, used to determine playback state. + */ + public static void updateRemote(Context context, Song song, int state) + { + RemoteControlClient remote = sRemote; + if (remote == null) + return; + + remote.setPlaybackState((state & PlaybackService.FLAG_PLAYING) != 0 ? RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED); + RemoteControlClient.MetadataEditor editor = remote.editMetadata(true); + if (song != null) { + editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, song.artist); + editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, song.album); + editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, song.title); + editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, song.getCover(context)); + } + editor.apply(); + } +} diff --git a/src/org/kreed/vanilla/MediaButtonReceiver.java b/src/org/kreed/vanilla/MediaButtonReceiver.java index 2f123ce7..b49e40a8 100644 --- a/src/org/kreed/vanilla/MediaButtonReceiver.java +++ b/src/org/kreed/vanilla/MediaButtonReceiver.java @@ -153,6 +153,14 @@ public class MediaButtonReceiver extends BroadcastReceiver { if (action == KeyEvent.ACTION_DOWN) act = PlaybackService.ACTION_PREVIOUS_SONG_AUTOPLAY; break; + case KeyEvent.KEYCODE_MEDIA_PLAY: + if (action == KeyEvent.ACTION_DOWN) + act = PlaybackService.ACTION_PLAY; + break; + case KeyEvent.KEYCODE_MEDIA_PAUSE: + if (action == KeyEvent.ACTION_DOWN) + act = PlaybackService.ACTION_PAUSE; + break; default: return false; } diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index be9a8509..5abef091 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -364,6 +364,10 @@ public final class PlaybackService extends Service getContentResolver().registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mObserver); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + CompatIcs.registerRemote(this, mAudioManager); + } + mLooper = thread.getLooper(); mHandler = new Handler(mLooper, this); @@ -631,6 +635,10 @@ public final class PlaybackService extends Service updateWidgets(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + CompatIcs.updateRemote(this, mCurrentSong, mState); + } + if (mStockBroadcast) stockMusicBroadcast(); if (mScrobble)