diff options
Diffstat (limited to 'subsonic-android')
17 files changed, 327 insertions, 196 deletions
diff --git a/subsonic-android/AndroidManifest.xml b/subsonic-android/AndroidManifest.xml index 30010066..8956ef8d 100644 --- a/subsonic-android/AndroidManifest.xml +++ b/subsonic-android/AndroidManifest.xml @@ -2,8 +2,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="github.daneren2005.dsub"
android:installLocation="auto"
- android:versionCode="7"
- android:versionName="3.3.4">
+ android:versionCode="10"
+ android:versionName="3.3.5.1">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
@@ -100,7 +100,7 @@ </intent-filter>
</receiver>
- <receiver android:name="github.daneren2005.dsub.provider.SubsonicAppWidgetProvider1" >
+ <receiver android:name="github.daneren2005.dsub.provider.DSubWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
diff --git a/subsonic-android/res/drawable-hdpi-v4/appwidget_bg.9.png b/subsonic-android/res/drawable-hdpi-v4/appwidget_bg.9.png Binary files differindex 3b29eae7..d8f892c3 100644 --- a/subsonic-android/res/drawable-hdpi-v4/appwidget_bg.9.png +++ b/subsonic-android/res/drawable-hdpi-v4/appwidget_bg.9.png diff --git a/subsonic-android/res/drawable/appwidget_bg.9.png b/subsonic-android/res/drawable/appwidget_bg.9.png Binary files differdeleted file mode 100644 index afe41b67..00000000 --- a/subsonic-android/res/drawable/appwidget_bg.9.png +++ /dev/null diff --git a/subsonic-android/res/drawable/btn_bg.xml b/subsonic-android/res/drawable/btn_bg.xml new file mode 100644 index 00000000..79d40784 --- /dev/null +++ b/subsonic-android/res/drawable/btn_bg.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2010 The Android Open Source Project Licensed under the
+ Apache License, Version 2.0 (the "License"); you may not use this file except
+ in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software distributed
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+ OR CONDITIONS OF ANY KIND, either express or implied. See the License for
+ the specific language governing permissions and limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+ <item android:drawable="@color/ics_opaque" android:state_pressed="true"/>
+ <item android:drawable="@color/ics_opaque" android:state_enabled="true" android:state_focused="true"/>
+
+</selector>
\ No newline at end of file diff --git a/subsonic-android/res/drawable/notification_play.png b/subsonic-android/res/drawable/notification_play.png Binary files differnew file mode 100644 index 00000000..8c95b6a5 --- /dev/null +++ b/subsonic-android/res/drawable/notification_play.png diff --git a/subsonic-android/res/drawable/widget_background.xml b/subsonic-android/res/drawable/widget_background.xml new file mode 100644 index 00000000..fe641900 --- /dev/null +++ b/subsonic-android/res/drawable/widget_background.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" + android:drawable="@drawable/appwidget_overlay" /> + + <item android:state_focused="true" android:state_enabled="true" + android:state_window_focused="true" + android:drawable="@drawable/appwidget_overlay" /> + + <item android:drawable="@drawable/appwidget_bg" /> +</selector> + diff --git a/subsonic-android/res/layout/appwidget.xml b/subsonic-android/res/layout/appwidget.xml index 233bc93f..6b3c892e 100644 --- a/subsonic-android/res/layout/appwidget.xml +++ b/subsonic-android/res/layout/appwidget.xml @@ -3,7 +3,7 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" - android:background="@drawable/appwidget_bg"> + android:background="@drawable/widget_background"> <ImageView android:id="@+id/appwidget_coverart" android:layout_height="fill_parent" @@ -43,7 +43,7 @@ android:id="@+id/artist" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:textColor="@color/appwidget_text" + android:textColor="@color/cyan" android:minHeight="12sp" android:textSize="12sp" android:singleLine="true" diff --git a/subsonic-android/res/layout/notification.xml b/subsonic-android/res/layout/notification.xml index a234f71e..22e2cb63 100644 --- a/subsonic-android/res/layout/notification.xml +++ b/subsonic-android/res/layout/notification.xml @@ -3,93 +3,101 @@ android:id="@+id/statusbar" android:layout_width="fill_parent" android:layout_height="fill_parent" - android:orientation="vertical" > + android:orientation="horizontal" > + + <ImageView + android:id="@+id/notification_image" + android:layout_width="64.0dip" + android:layout_height="64.0dip" + android:layout_weight="0.0" + android:gravity="center" /> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" - android:orientation="horizontal" > + android:orientation="vertical" + android:paddingLeft="11.0dip"> + + <TextView + android:id="@+id/notification_title" + style="@android:style/TextAppearance.StatusBar.EventContent.Title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:ellipsize="marquee" + android:focusable="true" + android:singleLine="true" /> + + <LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="horizontal" > - <ImageView - android:id="@+id/notification_image" - android:layout_width="64.0dip" - android:layout_height="64.0dip" - android:layout_weight="0.0" - android:gravity="center" /> + <LinearLayout + android:layout_width="0.0dp" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1.0" + android:orientation="vertical"> - <LinearLayout - android:layout_width="0.0dp" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_weight="1.0" - android:orientation="vertical" - android:paddingLeft="11.0dip" > + <TextView + android:id="@+id/notification_artist" + style="@android:style/TextAppearance.StatusBar.EventContent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:ellipsize="end" + android:scrollHorizontally="true" + android:singleLine="true" /> - <TextView - android:id="@+id/notification_title" - style="@android:style/TextAppearance.StatusBar.EventContent.Title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left" - android:ellipsize="marquee" - android:focusable="true" - android:singleLine="true" /> + <TextView + android:id="@+id/notification_album" + style="@android:style/TextAppearance.StatusBar.EventContent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:ellipsize="end" + android:scrollHorizontally="true" + android:singleLine="true" /> + </LinearLayout> - <TextView - android:id="@+id/notification_artist" - style="@android:style/TextAppearance.StatusBar.EventContent" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left" - android:ellipsize="end" - android:scrollHorizontally="true" - android:singleLine="true" /> + <ImageButton + android:id="@+id/control_previous" + android:src="@drawable/notification_prev" + android:background="@drawable/btn_bg" + android:layout_width="34dip" + android:layout_height="34dip" + android:layout_gravity="center|right" + android:layout_marginRight="10dip" + android:layout_marginTop="2dip" + android:layout_weight="0.0" + android:scaleType="fitXY"/> - <TextView - android:id="@+id/notification_album" - style="@android:style/TextAppearance.StatusBar.EventContent" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left" - android:ellipsize="end" - android:scrollHorizontally="true" - android:singleLine="true" /> - </LinearLayout> - - <ImageButton - android:id="@+id/control_previous" - android:src="@drawable/notification_prev" - android:background="@android:color/transparent" - android:layout_width="40dip" - android:layout_height="40dip" - android:layout_gravity="center|right" - android:layout_marginRight="5dip" - android:layout_marginTop="2dip" - android:layout_weight="0.0"/> - - <ImageButton - android:id="@+id/control_pause" - android:src="@drawable/notification_pause" - android:background="@android:color/transparent" - android:layout_width="40dip" - android:layout_height="40dip" - android:layout_gravity="center|right" - android:layout_marginRight="5dip" - android:layout_marginTop="2dip" - android:layout_weight="0.0"/> - - <ImageButton - android:id="@+id/control_next" - android:src="@drawable/notification_next" - android:background="@android:color/transparent" - android:layout_width="40dip" - android:layout_height="40dip" - android:layout_gravity="center|right" - android:layout_marginRight="5dip" - android:layout_marginTop="2dip" - android:layout_weight="0.0"/> + <ImageButton + android:id="@+id/control_pause" + android:src="@drawable/notification_pause" + android:background="@drawable/btn_bg" + android:layout_width="34dip" + android:layout_height="34dip" + android:layout_gravity="center|right" + android:layout_marginRight="10dip" + android:layout_marginTop="2dip" + android:layout_weight="0.0" + android:scaleType="fitXY"/> + <ImageButton + android:id="@+id/control_next" + android:src="@drawable/notification_next" + android:background="@drawable/btn_bg" + android:layout_width="34dip" + android:layout_height="34dip" + android:layout_gravity="center|right" + android:layout_marginRight="10dip" + android:layout_marginTop="2dip" + android:layout_weight="0.0" + android:scaleType="fitXY"/> + </LinearLayout> </LinearLayout> - </LinearLayout> diff --git a/subsonic-android/res/values/colors.xml b/subsonic-android/res/values/colors.xml index 67bb3933..69ab22a1 100644 --- a/subsonic-android/res/values/colors.xml +++ b/subsonic-android/res/values/colors.xml @@ -10,4 +10,7 @@ <color name="wheatBackground">#F1F0E6</color> <color name="wheatForeground1">#494B26</color> <color name="wheatForeground2">#830009</color> + + <color name="ics_opaque">#8033b5e5</color> + <color name="cyan">#ff0099cc</color> </resources>
\ No newline at end of file diff --git a/subsonic-android/res/xml/appwidget_info.xml b/subsonic-android/res/xml/appwidget_info.xml index f1e8e308..7ad17ef9 100644 --- a/subsonic-android/res/xml/appwidget_info.xml +++ b/subsonic-android/res/xml/appwidget_info.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" - android:minWidth="294dip" - android:minHeight="72dip" + android:minWidth="272dip" + android:minHeight="56dip" android:updatePeriodMillis="0" + android:resizeMode="horizontal|vertical" android:initialLayout="@layout/appwidget"/>
\ No newline at end of file diff --git a/subsonic-android/res/xml/searchable.xml b/subsonic-android/res/xml/searchable.xml index fd68a3ed..80276434 100644 --- a/subsonic-android/res/xml/searchable.xml +++ b/subsonic-android/res/xml/searchable.xml @@ -4,6 +4,6 @@ android:hint="@string/search.title" android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" android:voiceLanguageModel="web_search" - android:searchSuggestAuthority="github.daneren2005.dsub.provider.SearchSuggestionProvider" + android:searchSuggestAuthority="github.daneren2005.dsub.provider.SearchSuggestionProvider1" android:searchSuggestSelection=" ?" > </searchable>
\ No newline at end of file diff --git a/subsonic-android/src/github/daneren2005/dsub/provider/SubsonicAppWidgetProvider1.java b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java index 40655b9d..c6861f0a 100644 --- a/subsonic-android/src/github/daneren2005/dsub/provider/SubsonicAppWidgetProvider1.java +++ b/subsonic-android/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java @@ -53,14 +53,14 @@ import github.daneren2005.dsub.util.FileUtil; * * @author Sindre Mehus */ -public class SubsonicAppWidgetProvider1 extends AppWidgetProvider { +public class DSubWidgetProvider extends AppWidgetProvider { - private static SubsonicAppWidgetProvider1 instance; - private static final String TAG = SubsonicAppWidgetProvider1.class.getSimpleName(); + private static DSubWidgetProvider instance; + private static final String TAG = DSubWidgetProvider.class.getSimpleName(); - public static synchronized SubsonicAppWidgetProvider1 getInstance() { + public static synchronized DSubWidgetProvider getInstance() { if (instance == null) { - instance = new SubsonicAppWidgetProvider1(); + instance = new DSubWidgetProvider(); } return instance; } diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java index bce1cca8..2de8eb46 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java @@ -18,22 +18,14 @@ */ package github.daneren2005.dsub.service; -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.app.Service; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.media.MediaMetadataRetriever; -import android.media.MediaPlayer; -import android.media.RemoteControlClient; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.os.PowerManager; -import android.util.Log; +import static github.daneren2005.dsub.domain.PlayerState.COMPLETED; +import static github.daneren2005.dsub.domain.PlayerState.DOWNLOADING; +import static github.daneren2005.dsub.domain.PlayerState.IDLE; +import static github.daneren2005.dsub.domain.PlayerState.PAUSED; +import static github.daneren2005.dsub.domain.PlayerState.PREPARED; +import static github.daneren2005.dsub.domain.PlayerState.PREPARING; +import static github.daneren2005.dsub.domain.PlayerState.STARTED; +import static github.daneren2005.dsub.domain.PlayerState.STOPPED; import github.daneren2005.dsub.audiofx.EqualizerController; import github.daneren2005.dsub.audiofx.VisualizerController; import github.daneren2005.dsub.domain.MusicDirectory; @@ -41,10 +33,12 @@ import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RepeatMode; import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; import github.daneren2005.dsub.util.CancellableTask; +import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.LRUCache; import github.daneren2005.dsub.util.ShufflePlayBuffer; import github.daneren2005.dsub.util.SimpleServiceBinder; import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.util.compat.RemoteControlClientHelper; import java.io.File; import java.util.ArrayList; @@ -52,8 +46,17 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import static github.daneren2005.dsub.domain.PlayerState.*; -import github.daneren2005.dsub.util.*; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.Handler; +import android.os.IBinder; +import android.os.PowerManager; +import android.util.Log; /** * @author Sindre Mehus @@ -71,8 +74,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { public static final String CMD_NEXT = "github.daneren2005.dsub.CMD_NEXT"; - private RemoteControlClient mRemoteControlClient; - private ImageLoader imageLoader; + private RemoteControlClientHelper mRemoteControl; private final IBinder binder = new SimpleServiceBinder<DownloadService>(this); private MediaPlayer mediaPlayer; @@ -121,12 +123,9 @@ public class DownloadServiceImpl extends Service implements DownloadService { } } - @TargetApi(14) @Override public void onCreate() { super.onCreate(); - - imageLoader = new ImageLoader(this); mediaPlayer = new MediaPlayer(); mediaPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK); @@ -138,73 +137,48 @@ public class DownloadServiceImpl extends Service implements DownloadService { return false; } }); - -// try { -// Class.forName("android.media.RemoteControlClient"); - if (Build.VERSION.SDK_INT >= 14) { - - Util.requestAudioFocus(this); - Util.registerMediaButtonEventReceiver(this); - - // Use the remote control APIs (if available) to set the playback state - if (mRemoteControlClient == null) { - AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - ComponentName mediaButtonReceiverComponent = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName()); -// audioManager.registerMediaButtonEventReceiver(mediaButtonReceiverComponent); - // build the PendingIntent for the remote control client - Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); - mediaButtonIntent.setComponent(mediaButtonReceiverComponent); - PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0); - // create and register the remote control client - mRemoteControlClient = new RemoteControlClient(mediaPendingIntent); - audioManager.registerRemoteControlClient(mRemoteControlClient); - } - - mRemoteControlClient.setPlaybackState( - RemoteControlClient.PLAYSTATE_STOPPED); - - mRemoteControlClient.setTransportControlFlags( - RemoteControlClient.FLAG_KEY_MEDIA_PLAY | - RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | - RemoteControlClient.FLAG_KEY_MEDIA_NEXT | - RemoteControlClient.FLAG_KEY_MEDIA_STOP); - } -// } catch (ClassNotFoundException x) { -// // Ignored. -// } - - if (equalizerAvailable) { - equalizerController = new EqualizerController(this, mediaPlayer); - if (!equalizerController.isAvailable()) { - equalizerController = null; - } else { - equalizerController.loadSettings(); - } - } - if (visualizerAvailable) { - visualizerController = new VisualizerController(this, mediaPlayer); - if (!visualizerController.isAvailable()) { - visualizerController = null; - } + + Util.requestAudioFocus(this); + Util.registerMediaButtonEventReceiver(this); + + if (mRemoteControl == null) { + // Use the remote control APIs (if available) to set the playback state + mRemoteControl = RemoteControlClientHelper.createInstance(); + ComponentName mediaButtonReceiverComponent = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName()); + mRemoteControl.register(this, mediaButtonReceiverComponent); } - PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); - wakeLock.setReferenceCounted(false); + if (equalizerAvailable) { + equalizerController = new EqualizerController(this, mediaPlayer); + if (!equalizerController.isAvailable()) { + equalizerController = null; + } else { + equalizerController.loadSettings(); + } + } + if (visualizerAvailable) { + visualizerController = new VisualizerController(this, mediaPlayer); + if (!visualizerController.isAvailable()) { + visualizerController = null; + } + } + + PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); + wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); + wakeLock.setReferenceCounted(false); - instance = this; - lifecycleSupport.onCreate(); + instance = this; + lifecycleSupport.onCreate(); } @Override - public void onStart(Intent intent, int startId) { - super.onStart(intent, startId); + public int onStartCommand(Intent intent, int flags, int startId) { + super.onStartCommand(intent, flags, startId); lifecycleSupport.onStart(intent); + return START_NOT_STICKY; } - @Override + @Override public void onDestroy() { super.onDestroy(); lifecycleSupport.onDestroy(); @@ -216,6 +190,10 @@ public class DownloadServiceImpl extends Service implements DownloadService { if (visualizerController != null) { visualizerController.release(); } + if (mRemoteControl != null) { + mRemoteControl.unregister(this); + mRemoteControl = null; + } instance = null; } @@ -445,7 +423,6 @@ public class DownloadServiceImpl extends Service implements DownloadService { } } - @TargetApi(14) synchronized void setCurrentPlaying(DownloadFile currentPlaying, boolean showNotification) { this.currentPlaying = currentPlaying; @@ -462,23 +439,9 @@ public class DownloadServiceImpl extends Service implements DownloadService { Util.hidePlayingNotification(this, this, handler); } - if (mRemoteControlClient != null) { - MusicDirectory.Entry currentSong = currentPlaying == null ? null: currentPlaying.getSong(); - // Update the remote controls - mRemoteControlClient.editMetadata(true) - .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, currentSong == null ? null : currentSong.getArtist()) - .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, currentSong == null ? null : currentSong.getAlbum()) - .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, currentSong == null ? null : currentSong.getTitle()) - .putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, currentSong == null ? 0 : currentSong.getDuration()) - .apply(); - if (currentSong == null) { - mRemoteControlClient.editMetadata(true) - .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null) - .apply(); - } else { - imageLoader.loadImage(this, mRemoteControlClient, currentSong); - } - } + MusicDirectory.Entry currentSong = (currentPlaying == null) ? null: currentPlaying.getSong(); + mRemoteControl.updateMetadata(this, currentSong); + } @Override @@ -688,7 +651,6 @@ public class DownloadServiceImpl extends Service implements DownloadService { return playerState; } - @TargetApi(14) synchronized void setPlayerState(PlayerState playerState) { Log.i(TAG, this.playerState.name() + " -> " + playerState.name() + " (" + currentPlaying + ")"); @@ -701,9 +663,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { Util.broadcastPlaybackStatusChange(this, playerState); this.playerState = playerState; - if (mRemoteControlClient != null) { - mRemoteControlClient.setPlaybackState(playerState.getRemoteControlClientPlayState()); - } + mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState()); if (show) { Util.showPlayingNotification(this, this, handler, currentPlaying.getSong()); diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Util.java b/subsonic-android/src/github/daneren2005/dsub/util/Util.java index 37dfc6f5..cf3b6ca4 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Util.java @@ -54,7 +54,7 @@ import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RepeatMode; import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.provider.SubsonicAppWidgetProvider1; +import github.daneren2005.dsub.provider.DSubWidgetProvider; import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; import github.daneren2005.dsub.service.DownloadServiceImpl; import org.apache.http.HttpEntity; @@ -644,7 +644,7 @@ public final class Util { }); // Update widget - SubsonicAppWidgetProvider1.getInstance().notifyChange(context, downloadService, true); + DSubWidgetProvider.getInstance().notifyChange(context, downloadService, true); } public static void hidePlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler) { @@ -658,7 +658,7 @@ public final class Util { }); // Update widget - SubsonicAppWidgetProvider1.getInstance().notifyChange(context, downloadService, false); + DSubWidgetProvider.getInstance().notifyChange(context, downloadService, false); } public static void sleepQuietly(long millis) { diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java new file mode 100644 index 00000000..c3f3f70c --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java @@ -0,0 +1,32 @@ +package github.daneren2005.dsub.util.compat; + +import github.daneren2005.dsub.domain.MusicDirectory.Entry; +import android.content.ComponentName; +import android.content.Context; +import android.util.Log; + +public class RemoteControlClientBase extends RemoteControlClientHelper { + + private static final String TAG = RemoteControlClientBase.class.getSimpleName(); + + @Override + public void register(Context context, ComponentName mediaButtonReceiverComponent) { + Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); + } + + @Override + public void unregister(Context context) { + Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); + } + + @Override + public void setPlaybackState(int state) { + Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); + } + + @Override + public void updateMetadata(Context context, Entry currentSong) { + Log.w(TAG, "RemoteControlClient requires Android API level 14 or higher."); + } + +} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java new file mode 100644 index 00000000..ddaa9f43 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java @@ -0,0 +1,27 @@ +package github.daneren2005.dsub.util.compat; + +import github.daneren2005.dsub.domain.MusicDirectory; +import android.content.ComponentName; +import android.content.Context; +import android.os.Build; + +public abstract class RemoteControlClientHelper { + + public static RemoteControlClientHelper createInstance() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return new RemoteControlClientBase(); + } else { + return new RemoteControlClientICS(); + } + } + + protected RemoteControlClientHelper() { + // Avoid instantiation + } + + public abstract void register(final Context context, final ComponentName mediaButtonReceiverComponent); + public abstract void unregister(final Context context); + public abstract void setPlaybackState(final int state); + public abstract void updateMetadata(final Context context, final MusicDirectory.Entry currentSong); + +} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java new file mode 100644 index 00000000..c5b09876 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java @@ -0,0 +1,71 @@ +package github.daneren2005.dsub.util.compat; + +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.util.ImageLoader; +import android.annotation.TargetApi; +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; + +@TargetApi(14) +public class RemoteControlClientICS extends RemoteControlClientHelper { + + private RemoteControlClient mRemoteControl; + + public void register(final Context context, final ComponentName mediaButtonReceiverComponent) { + AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + + // build the PendingIntent for the remote control client + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.setComponent(mediaButtonReceiverComponent); + PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, mediaButtonIntent, 0); + + // create and register the remote control client + mRemoteControl = new RemoteControlClient(mediaPendingIntent); + audioManager.registerRemoteControlClient(mRemoteControl); + + mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); + + mRemoteControl.setTransportControlFlags( + RemoteControlClient.FLAG_KEY_MEDIA_PLAY | + RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | + RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | + RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | + RemoteControlClient.FLAG_KEY_MEDIA_NEXT | + RemoteControlClient.FLAG_KEY_MEDIA_STOP); + } + + public void unregister(final Context context) { + if (mRemoteControl != null) { + AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + audioManager.unregisterRemoteControlClient(mRemoteControl); + } + } + + public void setPlaybackState(final int state) { + mRemoteControl.setPlaybackState(state); + } + + public void updateMetadata(final Context context, final MusicDirectory.Entry currentSong) { + // Update the remote controls + mRemoteControl.editMetadata(true) + .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) + .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, (currentSong == null) ? null : currentSong.getAlbum()) + .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, (currentSong) == null ? null : currentSong.getTitle()) + .putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, (currentSong == null) ? + 0 : ((currentSong.getDuration() == null) ? 0 : currentSong.getDuration())) + .apply(); + if (currentSong == null) { + mRemoteControl.editMetadata(true) + .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null) + .apply(); + } else { + new ImageLoader(context).loadImage(context, mRemoteControl, currentSong); + } + } + +} |