diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6a1ae96f..e0b1e821 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -126,14 +126,17 @@
-
+
+ android:resource="@xml/app_widget_small_info" />
restoredQueue = MusicPlaybackQueueStore.getInstance(context).getSavedPlayingQueue();
- int restoredPosition = PreferenceManager.getDefaultSharedPreferences(context).getInt(MusicService.SAVED_POSITION, -1);
- if (!restoredQueue.isEmpty() && restoredPosition >= 0 && restoredPosition < restoredQueue.size()) {
- song = restoredQueue.get(restoredPosition);
- }
- }
- linkButtons(context, widgetLayout);
- widgetLayout.setTextViewText(R.id.title, song.title);
- String separator = TextUtils.isEmpty(song.artistName) || TextUtils.isEmpty(song.albumName) ? "" : " | ";
- widgetLayout.setTextViewText(R.id.song_secondary_information, song.artistName + separator + song.albumName);
-
- updateWidgetsPlayState(context, isPlaying);
- loadAlbumCover(context, song);
- }
-
- public static void updateWidgetsPlayState(@NonNull final Context context, boolean isPlaying) {
- initLayoutIfNecessary(context);
- int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
- widgetLayout.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedDrawable(context, playPauseRes, MaterialValueHelper.getPrimaryTextColor(context, true)), 1.5f));
- updateWidgets(context);
- }
-
- private static void initLayoutIfNecessary(Context context) {
- if (widgetLayout == null)
- widgetLayout = new RemoteViews(context.getPackageName(), R.layout.widget_medium);
- widgetLayout.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, true)), 1.5f));
- widgetLayout.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, true)), 1.5f));
- }
-
- private static void updateWidgets(@NonNull final Context context) {
- // this is only a temporary solution until we rewrote this whole class.
- try {
- AppWidgetManager man = AppWidgetManager.getInstance(context);
- int[] ids = man.getAppWidgetIds(
- new ComponentName(context, WidgetMedium.class));
- for (int widgetId : ids) {
- man.updateAppWidget(widgetId, widgetLayout);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private static Handler uiThreadHandler;
- private static Target target;
-
- private static void loadAlbumCover(@NonNull final Context context, @Nullable final Song song) {
- if (song == null) return;
-
- if (uiThreadHandler == null) {
- uiThreadHandler = new Handler(Looper.getMainLooper());
- }
- if (target == null) {
- int widgetImageSize = context.getResources().getDimensionPixelSize(R.dimen.widget_medium_image_size);
- target = new SimpleTarget(widgetImageSize, widgetImageSize) {
- @Override
- public void onLoadFailed(Exception e, Drawable errorDrawable) {
- super.onLoadFailed(e, errorDrawable);
- setAlbumCover(context, null);
- }
-
- @Override
- public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) {
- setAlbumCover(context, resource);
- }
- };
- }
-
- uiThreadHandler.post(new Runnable() {
- @Override
- public void run() {
- SongGlideRequest.Builder.from(Glide.with(context), song)
- .checkIgnoreMediaStore(context)
- .asBitmap().build()
- .into(target);
- }
- });
- }
-
- private static void setAlbumCover(@NonNull final Context context, @Nullable final Bitmap albumArt) {
- if (albumArt != null) {
- widgetLayout.setImageViewBitmap(R.id.image, albumArt);
- } else {
- widgetLayout.setImageViewResource(R.id.image, R.drawable.default_album_art);
- }
- updateWidgets(context);
- }
-
- private static void linkButtons(@NonNull final Context context, @NonNull final RemoteViews views) {
- views.setOnClickPendingIntent(R.id.content, retrievePlaybackActions(context, 0));
- views.setOnClickPendingIntent(R.id.button_toggle_play_pause, retrievePlaybackActions(context, 1));
- views.setOnClickPendingIntent(R.id.button_next, retrievePlaybackActions(context, 2));
- views.setOnClickPendingIntent(R.id.button_prev, retrievePlaybackActions(context, 3));
- }
-
- private static PendingIntent retrievePlaybackActions(@NonNull final Context context, final int which) {
- final ComponentName serviceName = new ComponentName(context, MusicService.class);
- Intent intent;
- switch (which) {
- case 0:
- intent = new Intent(context, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- case 1:
- intent = new Intent(MusicService.ACTION_TOGGLE_PAUSE);
- intent.setComponent(serviceName);
- return PendingIntent.getService(context, 1, intent, 0);
- case 2:
- intent = new Intent(MusicService.ACTION_SKIP);
- intent.setComponent(serviceName);
- return PendingIntent.getService(context, 2, intent, 0);
- case 3:
- intent = new Intent(MusicService.ACTION_REWIND);
- intent.setComponent(serviceName);
- return PendingIntent.getService(context, 3, intent, 0);
- }
- return null;
- }
-
- @Override
- public void onUpdate(@NonNull Context context, @NonNull AppWidgetManager appWidgetManager, @NonNull int[] appWidgetIds) {
- updateWidgets(context, MusicPlayerRemote.getCurrentSong(), MusicPlayerRemote.isPlaying());
- }
-
- private static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) {
- Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier), (int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(bitmap);
- drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
- drawable.draw(c);
- return bitmap;
- }
-}
-
-
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java
new file mode 100644
index 00000000..ca0f3be8
--- /dev/null
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java
@@ -0,0 +1,189 @@
+package com.kabouzeid.gramophone.appwidgets;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.animation.GlideAnimation;
+import com.bumptech.glide.request.target.SimpleTarget;
+import com.bumptech.glide.request.target.Target;
+import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
+import com.kabouzeid.gramophone.R;
+import com.kabouzeid.gramophone.glide.SongGlideRequest;
+import com.kabouzeid.gramophone.model.Song;
+import com.kabouzeid.gramophone.service.MusicService;
+import com.kabouzeid.gramophone.ui.activities.MainActivity;
+import com.kabouzeid.gramophone.util.Util;
+
+/**
+ * @author Karim Abou Zeid (kabouzeid)
+ */
+public class AppWidgetSmall extends BaseAppWidget {
+ public static final String NAME = "app_widget_small";
+
+ private static AppWidgetSmall mInstance;
+
+ public static synchronized AppWidgetSmall getInstance() {
+ if (mInstance == null) {
+ mInstance = new AppWidgetSmall();
+ }
+ return mInstance;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onUpdate(final Context context, final AppWidgetManager appWidgetManager,
+ final int[] appWidgetIds) {
+ defaultAppWidget(context, appWidgetIds);
+ final Intent updateIntent = new Intent(MusicService.APP_WIDGET_UPDATE);
+ updateIntent.putExtra(MusicService.EXTRA_APP_WIDGET_NAME, NAME);
+ updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+ updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ context.sendBroadcast(updateIntent);
+ }
+
+ /**
+ * Initialize given widgets to default state, where we launch Music on
+ * default click and hide actions if service not running.
+ */
+ private void defaultAppWidget(final Context context, final int[] appWidgetIds) {
+ final RemoteViews appWidgetView = new RemoteViews(context.getPackageName(), R.layout.app_widget_small);
+
+ appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
+ appWidgetView.setViewVisibility(R.id.image, View.INVISIBLE);
+ appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, true)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, true)), 1f));
+
+ linkButtons(context, appWidgetView);
+ pushUpdate(context, appWidgetIds, appWidgetView);
+ }
+
+ private void pushUpdate(final Context context, final int[] appWidgetIds, final RemoteViews views) {
+ final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+ if (appWidgetIds != null) {
+ appWidgetManager.updateAppWidget(appWidgetIds, views);
+ } else {
+ appWidgetManager.updateAppWidget(new ComponentName(context, getClass()), views);
+ }
+ }
+
+ /**
+ * Check against {@link AppWidgetManager} if there are any instances of this
+ * widget.
+ */
+ private boolean hasInstances(final Context context) {
+ final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+ final int[] mAppWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context,
+ getClass()));
+ return mAppWidgetIds.length > 0;
+ }
+
+ /**
+ * Handle a change notification coming over from
+ * {@link MusicService}
+ */
+ public void notifyChange(final MusicService service, final String what) {
+ if (hasInstances(service)) {
+ if (MusicService.META_CHANGED.equals(what) || MusicService.PLAY_STATE_CHANGED.equals(what)) {
+ performUpdate(service, null);
+ }
+ }
+ }
+
+ /**
+ * Update all active widget instances by pushing changes
+ */
+ public void performUpdate(final MusicService service, final int[] appWidgetIds) {
+ final RemoteViews appWidgetView = new RemoteViews(service.getPackageName(), R.layout.app_widget_small);
+
+ final boolean isPlaying = service.isPlaying();
+ final Song song = service.getCurrentSong();
+
+ // Set the titles and artwork
+ if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
+ appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
+ } else {
+ appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE);
+ appWidgetView.setTextViewText(R.id.title, song.title);
+ appWidgetView.setTextViewText(R.id.text, song.artistName);
+ }
+
+ // Set correct drawable for pause state
+ int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedDrawable(service, playPauseRes, MaterialValueHelper.getPrimaryTextColor(service, true)), 1f));
+
+ // Link actions buttons to intents
+ linkButtons(service, appWidgetView);
+
+ // load the album cover async and push the update on completion
+ final Context appContext = service.getApplicationContext();
+ final int widgetImageSize = service.getResources().getDimensionPixelSize(R.dimen.app_widget_small_image_size);
+ service.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (target != null) {
+ Glide.clear(target);
+ }
+ target = SongGlideRequest.Builder.from(Glide.with(appContext), song)
+ .checkIgnoreMediaStore(appContext)
+ .asBitmap().build()
+ .into(new SimpleTarget(widgetImageSize, widgetImageSize) {
+ @Override
+ public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) {
+ appWidgetView.setViewVisibility(R.id.image, View.VISIBLE);
+ appWidgetView.setImageViewBitmap(R.id.image, resource);
+ pushUpdate(appContext, appWidgetIds, appWidgetView);
+ }
+
+ @Override
+ public void onLoadFailed(Exception e, Drawable errorDrawable) {
+ super.onLoadFailed(e, errorDrawable);
+ appWidgetView.setViewVisibility(R.id.image, View.VISIBLE);
+ appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
+ pushUpdate(appContext, appWidgetIds, appWidgetView);
+ }
+ });
+ }
+ });
+ }
+
+ private Target target; // for cancellation
+
+ /**
+ * Link up various button actions using {@link PendingIntent}.
+ */
+ private void linkButtons(final Context context, final RemoteViews views) {
+ Intent action;
+ PendingIntent pendingIntent;
+
+ final ComponentName serviceName = new ComponentName(context, MusicService.class);
+
+ // Home
+ action = new Intent(context, MainActivity.class);
+ action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
+ views.setOnClickPendingIntent(R.id.content, pendingIntent);
+
+ // Previous track
+ pendingIntent = buildPendingIntent(context, MusicService.ACTION_REWIND, serviceName);
+ views.setOnClickPendingIntent(R.id.button_prev, pendingIntent);
+
+ // Play and pause
+ pendingIntent = buildPendingIntent(context, MusicService.ACTION_TOGGLE_PAUSE, serviceName);
+ views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent);
+
+ // Next track
+ pendingIntent = buildPendingIntent(context, MusicService.ACTION_SKIP, serviceName);
+ views.setOnClickPendingIntent(R.id.button_next, pendingIntent);
+ }
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/BaseAppWidget.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/BaseAppWidget.java
new file mode 100644
index 00000000..c44f0bf6
--- /dev/null
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/BaseAppWidget.java
@@ -0,0 +1,30 @@
+package com.kabouzeid.gramophone.appwidgets;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetProvider;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+
+/**
+ * @author Karim Abou Zeid (kabouzeid)
+ */
+public class BaseAppWidget extends AppWidgetProvider {
+
+ protected PendingIntent buildPendingIntent(Context context, final String action, final ComponentName serviceName) {
+ Intent intent = new Intent(action);
+ intent.setComponent(serviceName);
+ return PendingIntent.getService(context, 0, intent, 0);
+ }
+
+ protected static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) {
+ Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier), (int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(bitmap);
+ drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
+ drawable.draw(c);
+ return bitmap;
+ }
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java
index f76b0bf9..bcd9b734 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/service/MusicService.java
@@ -2,6 +2,7 @@ package com.kabouzeid.gramophone.service;
import android.app.PendingIntent;
import android.app.Service;
+import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -36,7 +37,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.kabouzeid.gramophone.R;
-import com.kabouzeid.gramophone.appwidget.WidgetMedium;
+import com.kabouzeid.gramophone.appwidgets.AppWidgetSmall;
import com.kabouzeid.gramophone.glide.BlurTransformation;
import com.kabouzeid.gramophone.glide.SongGlideRequest;
import com.kabouzeid.gramophone.helper.PlayingNotificationHelper;
@@ -72,6 +73,9 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
public static final String ACTION_REWIND = PHONOGRAPH_PACKAGE_NAME + ".rewind";
public static final String ACTION_QUIT = PHONOGRAPH_PACKAGE_NAME + ".quitservice";
+ public static final String APP_WIDGET_UPDATE = PHONOGRAPH_PACKAGE_NAME + ".appwidgetupdate";
+ public static final String EXTRA_APP_WIDGET_NAME = PHONOGRAPH_PACKAGE_NAME + "app_widget_name";
+
// do not change these three strings as it will break support with other apps (e.g. last.fm scrobbling)
public static final String META_CHANGED = PHONOGRAPH_PACKAGE_NAME + ".metachanged";
public static final String QUEUE_CHANGED = PHONOGRAPH_PACKAGE_NAME + ".queuechanged";
@@ -108,6 +112,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private final IBinder musicBind = new MusicBinder();
+ private AppWidgetSmall appWidgetSmall = AppWidgetSmall.getInstance();
+
private Playback playback;
private ArrayList playingQueue = new ArrayList<>();
private ArrayList originalPlayingQueue = new ArrayList<>();
@@ -115,6 +121,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private int nextPosition = -1;
private int shuffleMode;
private int repeatMode;
+ private boolean queuesRestored;
private boolean audioDucking;
private boolean pausedByTransientLossOfFocus;
private boolean receiversAndRemoteControlClientRegistered;
@@ -181,6 +188,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
registerReceiversAndRemoteControlClient();
+ registerReceiver(widgetIntentReceiver, new IntentFilter(APP_WIDGET_UPDATE));
+
mediaStoreObserver = new MediaStoreObserver(playerHandler);
throttledPublicPlayStateChangedNotifier = new ThrottledPublicPlayStateChangedNotifier(playerHandler);
getContentResolver().registerContentObserver(
@@ -196,7 +205,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private void registerReceiversAndRemoteControlClient() {
if (!receiversAndRemoteControlClientRegistered) {
registerReceiver(becomingNoisyReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
- //noinspection deprecation
getAudioManager().registerMediaButtonEventReceiver(new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class));
initRemoteControlClient();
receiversAndRemoteControlClientRegistered = true;
@@ -227,6 +235,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
if (intent != null) {
if (intent.getAction() != null) {
+ restoreQueuesAndPositionIfNecessary();
String action = intent.getAction();
switch (action) {
case ACTION_TOGGLE_PAUSE:
@@ -261,6 +270,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
@Override
public void onDestroy() {
+ unregisterReceiver(widgetIntentReceiver);
quit();
releaseResources();
getContentResolver().unregisterContentObserver(mediaStoreObserver);
@@ -291,9 +301,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private void unregisterReceiversAndRemoteControlClient() {
if (receiversAndRemoteControlClientRegistered) {
unregisterReceiver(becomingNoisyReceiver);
- //noinspection deprecation
getAudioManager().unregisterRemoteControlClient(remoteControlClient);
- //noinspection deprecation
getAudioManager().unregisterMediaButtonEventReceiver(new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class));
receiversAndRemoteControlClientRegistered = false;
}
@@ -345,34 +353,36 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private void restoreState() {
shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_SHUFFLE_MODE, 0);
repeatMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_REPEAT_MODE, 0);
- notifyPrivateChange(SHUFFLE_MODE_CHANGED);
- notifyPrivateChange(REPEAT_MODE_CHANGED);
+ handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED);
+ handleAndSendChangeInternal(REPEAT_MODE_CHANGED);
playerHandler.removeMessages(RESTORE_QUEUES);
playerHandler.sendEmptyMessage(RESTORE_QUEUES);
}
- private void restoreQueuesAndPositionImpl() {
- ArrayList restoredQueue = MusicPlaybackQueueStore.getInstance(this).getSavedPlayingQueue();
- ArrayList restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).getSavedOriginalPlayingQueue();
- int restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1);
- int restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1);
+ private synchronized void restoreQueuesAndPositionIfNecessary() {
+ if (!queuesRestored && playingQueue.isEmpty()) {
+ ArrayList restoredQueue = MusicPlaybackQueueStore.getInstance(this).getSavedPlayingQueue();
+ ArrayList restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).getSavedOriginalPlayingQueue();
+ int restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1);
+ int restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1);
- if (restoredQueue.size() > 0 && restoredQueue.size() == restoredOriginalQueue.size() && restoredPosition != -1) {
- this.originalPlayingQueue = restoredOriginalQueue;
- this.playingQueue = restoredQueue;
+ if (restoredQueue.size() > 0 && restoredQueue.size() == restoredOriginalQueue.size() && restoredPosition != -1) {
+ this.originalPlayingQueue = restoredOriginalQueue;
+ this.playingQueue = restoredQueue;
- position = restoredPosition;
- openCurrent();
- prepareNext();
+ position = restoredPosition;
+ openCurrent();
+ prepareNext();
- if (restoredPositionInTrack > 0) seek(restoredPositionInTrack);
+ if (restoredPositionInTrack > 0) seek(restoredPositionInTrack);
- notHandledMetaChangedForCurrentTrack = true;
- sendPrivateIntent(META_CHANGED);
- sendPrivateIntent(QUEUE_CHANGED);
- updateWidgets();
+ notHandledMetaChangedForCurrentTrack = true;
+ sendChangeInternal(META_CHANGED);
+ sendChangeInternal(QUEUE_CHANGED);
+ }
}
+ queuesRestored = true;
}
private int quit() {
@@ -415,7 +425,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
public boolean isPlaying() {
- return playback.isPlaying();
+ return playback != null && playback.isPlaying();
}
public int getPosition() {
@@ -567,10 +577,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
playingNotificationHelper.updateNotification();
}
- private void updateWidgets() {
- WidgetMedium.updateWidgets(this, getCurrentSong(), isPlaying());
- }
-
public int getNextPosition(boolean force) {
int position = getPosition() + 1;
switch (getRepeatMode()) {
@@ -620,7 +626,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
.putInt(SAVED_REPEAT_MODE, repeatMode)
.apply();
prepareNext();
- notifyPrivateChange(REPEAT_MODE_CHANGED);
+ handleAndSendChangeInternal(REPEAT_MODE_CHANGED);
break;
}
}
@@ -775,7 +781,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
registerReceiversAndRemoteControlClient();
playback.start();
if (notHandledMetaChangedForCurrentTrack) {
- handleChange(META_CHANGED);
+ handleChangeInternal(META_CHANGED);
notHandledMetaChangedForCurrentTrack = false;
}
notifyChange(PLAY_STATE_CHANGED);
@@ -900,18 +906,18 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
position = newPosition;
break;
}
- notifyPrivateChange(SHUFFLE_MODE_CHANGED);
+ handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED);
notifyChange(QUEUE_CHANGED);
}
private void notifyChange(@NonNull final String what) {
- notifyPrivateChange(what);
+ handleAndSendChangeInternal(what);
sendPublicIntent(what);
}
- private void notifyPrivateChange(@NonNull final String what) {
- handleChange(what);
- sendPrivateIntent(what);
+ private void handleAndSendChangeInternal(@NonNull final String what) {
+ handleChangeInternal(what);
+ sendChangeInternal(what);
}
// to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch
@@ -936,16 +942,16 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
sendStickyBroadcast(intent);
}
- private void sendPrivateIntent(final String what) {
+ private void sendChangeInternal(final String what) {
sendBroadcast(new Intent(what));
+ appWidgetSmall.notifyChange(this, what);
}
- private void handleChange(@NonNull final String what) {
+ private void handleChangeInternal(@NonNull final String what) {
switch (what) {
case PLAY_STATE_CHANGED:
final boolean isPlaying = isPlaying();
playingNotificationHelper.updatePlayState(isPlaying);
- WidgetMedium.updateWidgetsPlayState(this, isPlaying);
//noinspection deprecation
remoteControlClient.setPlaybackState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED);
if (!isPlaying && getSongProgressMillis() > 0) {
@@ -955,7 +961,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
break;
case META_CHANGED:
updateNotification();
- updateWidgets();
updateRemoteControlClient();
savePosition();
savePositionInTrack();
@@ -1110,7 +1115,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
break;
case RESTORE_QUEUES:
- service.restoreQueuesAndPositionImpl();
+ service.restoreQueuesAndPositionIfNecessary();
break;
case FOCUS_CHANGE:
@@ -1159,6 +1164,18 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
}
}
+ private final BroadcastReceiver widgetIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ final String command = intent.getStringExtra(EXTRA_APP_WIDGET_NAME);
+
+ if (AppWidgetSmall.NAME.equals(command)) {
+ final int[] small = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ appWidgetSmall.performUpdate(MusicService.this, small);
+ }
+ }
+ };
+
private class MediaStoreObserver extends ContentObserver implements Runnable {
// milliseconds to delay before calling refresh to aggregate events
private static final long REFRESH_DELAY = 500;
@@ -1182,7 +1199,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
public void run() {
// actually call refresh when the delayed callback fires
// do not send a sticky broadcast here
- notifyPrivateChange(MEDIA_STORE_CHANGED);
+ handleAndSendChangeInternal(MEDIA_STORE_CHANGED);
}
}
diff --git a/app/src/main/res/layout/widget_medium.xml b/app/src/main/res/layout/app_widget_small.xml
similarity index 80%
rename from app/src/main/res/layout/widget_medium.xml
rename to app/src/main/res/layout/app_widget_small.xml
index d8515d25..6b5bdaca 100644
--- a/app/src/main/res/layout/widget_medium.xml
+++ b/app/src/main/res/layout/app_widget_small.xml
@@ -2,14 +2,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="96dp"
+ android:layout_height="@dimen/app_widget_small_image_size"
android:background="#AAFFFFFF"
+ android:orientation="horizontal"
tools:ignore="ContentDescription">
@@ -18,6 +19,7 @@
android:layout_height="match_parent">
+ android:background="@drawable/notification_selector"
+ tools:src="@drawable/ic_skip_previous_white_24dp"
+ tools:tint="#000" />
+ android:background="@drawable/notification_selector"
+ tools:src="@drawable/ic_play_arrow_white_24dp"
+ tools:tint="#000" />
+ android:background="@drawable/notification_selector"
+ tools:src="@drawable/ic_skip_next_white_24dp"
+ tools:tint="#000" />
@@ -65,17 +73,19 @@
android:gravity="center_vertical"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
- android:textColor="@color/ate_primary_text_light" />
+ android:textColor="@color/ate_primary_text_light"
+ tools:text="Title" />
+ android:textColor="@color/ate_primary_text_light"
+ tools:text="Text" />
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index d29838fe..bc5f7e22 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -33,7 +33,6 @@ http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-17dp
2dp
- 96dp
128dp
8dp
@@ -59,4 +58,9 @@ http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
56dp
+
+ 96dp
+ 250dp
+ 40dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9239b489..20048c40 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -245,4 +245,5 @@
Could not scan %d files.
Listing files
%s is the new start directory.
+ small
diff --git a/app/src/main/res/xml/app_widget_small_info.xml b/app/src/main/res/xml/app_widget_small_info.xml
new file mode 100644
index 00000000..98dacbab
--- /dev/null
+++ b/app/src/main/res/xml/app_widget_small_info.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/widget_medium_info.xml b/app/src/main/res/xml/widget_medium_info.xml
deleted file mode 100644
index b260851e..00000000
--- a/app/src/main/res/xml/widget_medium_info.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file