Fixed saving position in track, improvement with service binding, temporary new default album art.

This commit is contained in:
Karim Abou Zeid 2015-07-07 02:19:09 +02:00
commit cfa6ddaa2e
12 changed files with 140 additions and 61 deletions

View file

@ -3,15 +3,12 @@ package com.kabouzeid.gramophone;
import android.app.Application; import android.app.Application;
import com.crashlytics.android.Crashlytics; import com.crashlytics.android.Crashlytics;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.utils.L; import com.nostra13.universalimageloader.utils.L;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer; import com.squareup.otto.ThreadEnforcer;
import org.jaudiotagger.tag.TagOptionSingleton;
import io.fabric.sdk.android.Fabric; import io.fabric.sdk.android.Fabric;
/** /**
@ -24,14 +21,11 @@ public class App extends Application {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
if (!BuildConfig.DEBUG) Fabric.with(this, new Crashlytics());
MusicPlayerRemote.startAndBindService(this); if (!BuildConfig.DEBUG) Fabric.with(this, new Crashlytics());
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build(); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build();
ImageLoader.getInstance().init(config); ImageLoader.getInstance().init(config);
L.writeLogs(false); // turns off UILs annoying LogCat output L.writeLogs(false); // turns off UILs annoying LogCat output
TagOptionSingleton.getInstance().isAndroid();
} }
} }

View file

@ -14,7 +14,7 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MusicControllerActivity; import com.kabouzeid.gramophone.ui.activities.MainActivity;
import com.kabouzeid.gramophone.util.MusicUtil; import com.kabouzeid.gramophone.util.MusicUtil;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.FailReason;
@ -117,7 +117,7 @@ public class WidgetMedium extends AppWidgetProvider {
final ComponentName serviceName = new ComponentName(context, MusicService.class); final ComponentName serviceName = new ComponentName(context, MusicService.class);
switch (which) { switch (which) {
case 0: case 0:
action = new Intent(context, MusicControllerActivity.class); action = new Intent(context, MainActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0, action, 0); pendingIntent = PendingIntent.getActivity(context, 0, action, 0);
return pendingIntent; return pendingIntent;
case 1: case 1:

View file

@ -1,7 +1,9 @@
package com.kabouzeid.gramophone.helper; package com.kabouzeid.gramophone.helper;
import android.app.Activity;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.media.audiofx.AudioEffect; import android.media.audiofx.AudioEffect;
@ -15,6 +17,7 @@ import com.kabouzeid.gramophone.service.MusicService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Random; import java.util.Random;
import java.util.WeakHashMap;
/** /**
* @author Karim Abou Zeid (kabouzeid) * @author Karim Abou Zeid (kabouzeid)
@ -23,28 +26,75 @@ public class MusicPlayerRemote {
public static final String TAG = MusicPlayerRemote.class.getSimpleName(); public static final String TAG = MusicPlayerRemote.class.getSimpleName();
public static final String SERVICE_BOUND = "com.kabouzeid.gramophone.SERVICE_BOUND"; public static MusicService musicService;
private static MusicService musicService; private static final WeakHashMap<Context, ServiceBinder> mConnectionMap = new WeakHashMap<>();
private static final ServiceConnection musicConnection = new ServiceConnection() { public static ServiceToken bindToService(final Context context,
@Override final ServiceConnection callback) {
public void onServiceConnected(ComponentName name, IBinder service) { Activity realActivity = ((Activity) context).getParent();
MusicService.MusicBinder binder = (MusicService.MusicBinder) service; if (realActivity == null) {
musicService = binder.getService(); realActivity = (Activity) context;
musicService.sendBroadcast(new Intent(SERVICE_BOUND));
} }
@Override final ContextWrapper contextWrapper = new ContextWrapper(realActivity);
public void onServiceDisconnected(ComponentName name) { contextWrapper.startService(new Intent(contextWrapper, MusicService.class));
final ServiceBinder binder = new ServiceBinder(callback);
if (contextWrapper.bindService(new Intent().setClass(contextWrapper, MusicService.class), binder, Context.BIND_AUTO_CREATE)) {
mConnectionMap.put(contextWrapper, binder);
return new ServiceToken(contextWrapper);
}
return null;
}
public static void unbindFromService(final ServiceToken token) {
if (token == null) {
return;
}
final ContextWrapper mContextWrapper = token.mWrappedContext;
final ServiceBinder mBinder = mConnectionMap.remove(mContextWrapper);
if (mBinder == null) {
return;
}
mContextWrapper.unbindService(mBinder);
if (mConnectionMap.isEmpty()) {
musicService = null; musicService = null;
} }
}; }
public static void startAndBindService(final Context context) { public static final class ServiceBinder implements ServiceConnection {
Intent musicServiceIntent = new Intent(context, MusicService.class); private final ServiceConnection mCallback;
context.bindService(musicServiceIntent, musicConnection, Context.BIND_AUTO_CREATE);
context.startService(musicServiceIntent); public ServiceBinder(final ServiceConnection callback) {
mCallback = callback;
}
@Override
public void onServiceConnected(final ComponentName className, final IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
musicService = binder.getService();
if (mCallback != null) {
mCallback.onServiceConnected(className, service);
}
}
@Override
public void onServiceDisconnected(final ComponentName className) {
if (mCallback != null) {
mCallback.onServiceDisconnected(className);
}
musicService = null;
}
}
public static final class ServiceToken {
public ContextWrapper mWrappedContext;
public ServiceToken(final ContextWrapper context) {
mWrappedContext = context;
}
} }
public static boolean isServiceConnected() { public static boolean isServiceConnected() {

View file

@ -7,7 +7,6 @@ package com.kabouzeid.gramophone.helper;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@ -22,7 +21,7 @@ import android.widget.RemoteViews;
import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MusicControllerActivity; import com.kabouzeid.gramophone.ui.activities.MainActivity;
import com.kabouzeid.gramophone.util.MusicUtil; import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtils; import com.kabouzeid.gramophone.util.PreferenceUtils;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
@ -122,11 +121,7 @@ public class PlayingNotificationHelper {
} }
private PendingIntent getOpenMusicControllerPendingIntent() { private PendingIntent getOpenMusicControllerPendingIntent() {
Intent result = new Intent(service, MusicControllerActivity.class); return PendingIntent.getActivity(service, 0, new Intent(service, MainActivity.class), 0);
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(service);
taskStackBuilder.addParentStack(MusicControllerActivity.class);
taskStackBuilder.addNextIntent(result);
return taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
} }
private void setUpExpandedPlaybackActions() { private void setUpExpandedPlaybackActions() {
@ -263,7 +258,7 @@ public class PlayingNotificationHelper {
this.isPlaying = isPlaying; this.isPlaying = isPlaying;
if (notification == null) { if (notification == null) {
return; updateNotification();
} }
if (notificationLayout != null) { if (notificationLayout != null) {
notificationLayout.setImageViewResource(R.id.action_play_pause, notificationLayout.setImageViewResource(R.id.action_play_pause,

View file

@ -51,6 +51,8 @@ import java.util.List;
* @author Karim Abou Zeid (kabouzeid), Andrew Neal * @author Karim Abou Zeid (kabouzeid), Andrew Neal
*/ */
public class MusicService extends Service { public class MusicService extends Service {
public static final String TAG = MusicService.class.getSimpleName();
public static final String PHONOGRAPH_PACKAGE_NAME = "com.kabouzeid.gramophone"; public static final String PHONOGRAPH_PACKAGE_NAME = "com.kabouzeid.gramophone";
public static final String MUSIC_PACKAGE_NAME = "com.android.music"; public static final String MUSIC_PACKAGE_NAME = "com.android.music";
@ -114,6 +116,7 @@ public class MusicService extends Service {
private RecentlyPlayedStore recentlyPlayedStore; private RecentlyPlayedStore recentlyPlayedStore;
private SongPlayCountStore songPlayCountStore; private SongPlayCountStore songPlayCountStore;
private boolean notNotifiedMetaChangedForCurrentTrack; private boolean notNotifiedMetaChangedForCurrentTrack;
private boolean isServiceInUse;
private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() { private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
@Override @Override
@ -250,8 +253,7 @@ public class MusicService extends Service {
stop(); stop();
break; break;
case ACTION_QUIT: case ACTION_QUIT:
quit(); return quit();
break;
} }
} }
} }
@ -267,9 +269,24 @@ public class MusicService extends Service {
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
isServiceInUse = true;
return musicBind; return musicBind;
} }
@Override
public void onRebind(Intent intent) {
isServiceInUse = true;
}
@Override
public boolean onUnbind(Intent intent) {
isServiceInUse = false;
if (!isPlaying()) {
stopSelf();
}
return true;
}
private void unregisterReceiversAndRemoteControlClient() { private void unregisterReceiversAndRemoteControlClient() {
if (receiversAndRemoteControlClientRegistered) { if (receiversAndRemoteControlClientRegistered) {
unregisterReceiver(becomingNoisyReceiver); unregisterReceiver(becomingNoisyReceiver);
@ -282,12 +299,18 @@ public class MusicService extends Service {
} }
} }
private void quit() { private int quit() {
unregisterReceiversAndRemoteControlClient(); unregisterReceiversAndRemoteControlClient();
closeAudioEffectSession(); pause();
stop();
playingNotificationHelper.killNotification(); playingNotificationHelper.killNotification();
stopSelf();
if (isServiceInUse) {
return START_STICKY;
} else {
closeAudioEffectSession();
stopSelf();
return START_NOT_STICKY;
}
} }
private void releaseResources() { private void releaseResources() {

View file

@ -111,16 +111,7 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color)); setNavigationBarColor(DialogUtils.resolveColor(this, R.attr.default_bar_color));
} }
Bundle intentExtras = getIntent().getExtras(); getAlbumFromIntentExtras();
int albumId = -1;
if (intentExtras != null) {
albumId = intentExtras.getInt(EXTRA_ALBUM_ID);
}
album = AlbumLoader.getAlbum(this, albumId);
if (album.id == -1) {
finish();
}
setUpObservableListViewParams(); setUpObservableListViewParams();
setUpToolBar(); setUpToolBar();
setUpViews(); setUpViews();
@ -180,6 +171,15 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
} }
}; };
private void getAlbumFromIntentExtras() {
Bundle intentExtras = getIntent().getExtras();
final int albumId = intentExtras.getInt(EXTRA_ALBUM_ID);
album = AlbumLoader.getAlbum(this, albumId);
if (album.id == -1) {
finish();
}
}
@Override @Override
public String getTag() { public String getTag() {
return TAG; return TAG;

View file

@ -135,7 +135,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
lastFMRestClient = new LastFMRestClient(this); lastFMRestClient = new LastFMRestClient(this);
getIntentExtras(); getArtistFromIntentExtras();
initViews(); initViews();
setUpObservableListViewParams(); setUpObservableListViewParams();
setUpViews(); setUpViews();
@ -430,11 +430,11 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
notifyTaskColorChange(toolbarColor); notifyTaskColorChange(toolbarColor);
} }
private void getIntentExtras() { private void getArtistFromIntentExtras() {
Bundle intentExtras = getIntent().getExtras(); Bundle intentExtras = getIntent().getExtras();
final int artistId = intentExtras.getInt(EXTRA_ARTIST_ID); final int artistId = intentExtras.getInt(EXTRA_ARTIST_ID);
artist = ArtistLoader.getArtist(this, artistId); artist = ArtistLoader.getArtist(this, artistId);
if (artist == null) { if (artist.id == -1) {
finish(); finish();
} }
} }

View file

@ -27,7 +27,7 @@ import butterknife.Optional;
/** /**
* @author Karim Abou Zeid (kabouzeid) * @author Karim Abou Zeid (kabouzeid)
*/ */
public abstract class AbsFabActivity extends AbsPlaybackStatusActivity { public abstract class AbsFabActivity extends AbsPlaybackControlActivity {
public static final String TAG = AbsFabActivity.class.getSimpleName(); public static final String TAG = AbsFabActivity.class.getSimpleName();
@Optional @Optional

View file

@ -1,9 +1,13 @@
package com.kabouzeid.gramophone.ui.activities.base; package com.kabouzeid.gramophone.ui.activities.base;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.service.MusicService;
@ -13,7 +17,8 @@ import java.lang.ref.WeakReference;
/** /**
* @author Karim Abou Zeid (kabouzeid) * @author Karim Abou Zeid (kabouzeid)
*/ */
public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity { public abstract class AbsPlaybackControlActivity extends AbsBaseActivity {
private MusicPlayerRemote.ServiceToken serviceToken;
private PlaybackStatusReceiver playbackStatusReceiver; private PlaybackStatusReceiver playbackStatusReceiver;
public void onPlayingMetaChanged() { public void onPlayingMetaChanged() {
@ -36,23 +41,32 @@ public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity {
} }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
serviceToken = MusicPlayerRemote.bindToService(this, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
AbsPlaybackControlActivity.this.onServiceConnected();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
});
playbackStatusReceiver = new PlaybackStatusReceiver(this);
}
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
playbackStatusReceiver = new PlaybackStatusReceiver(this);
// ensures that onServiceConnected() is called even if the service is already connected and wont sent the Intent again.
if (MusicPlayerRemote.isServiceConnected()) {
onServiceConnected();
}
final IntentFilter filter = new IntentFilter(); final IntentFilter filter = new IntentFilter();
filter.addAction(MusicService.PLAY_STATE_CHANGED); filter.addAction(MusicService.PLAY_STATE_CHANGED);
filter.addAction(MusicService.SHUFFLE_MODE_CHANGED); filter.addAction(MusicService.SHUFFLE_MODE_CHANGED);
filter.addAction(MusicService.REPEAT_MODE_CHANGED); filter.addAction(MusicService.REPEAT_MODE_CHANGED);
filter.addAction(MusicService.META_CHANGED); filter.addAction(MusicService.META_CHANGED);
filter.addAction(MusicPlayerRemote.SERVICE_BOUND);
registerReceiver(playbackStatusReceiver, filter); registerReceiver(playbackStatusReceiver, filter);
} }
@ -66,11 +80,17 @@ public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity {
} }
} }
@Override
protected void onDestroy() {
super.onDestroy();
MusicPlayerRemote.unbindFromService(serviceToken);
}
private static final class PlaybackStatusReceiver extends BroadcastReceiver { private static final class PlaybackStatusReceiver extends BroadcastReceiver {
private final WeakReference<AbsPlaybackStatusActivity> reference; private final WeakReference<AbsPlaybackControlActivity> reference;
public PlaybackStatusReceiver(final AbsPlaybackStatusActivity activity) { public PlaybackStatusReceiver(final AbsPlaybackControlActivity activity) {
reference = new WeakReference<>(activity); reference = new WeakReference<>(activity);
} }
@ -90,9 +110,6 @@ public abstract class AbsPlaybackStatusActivity extends AbsBaseActivity {
case MusicService.SHUFFLE_MODE_CHANGED: case MusicService.SHUFFLE_MODE_CHANGED:
reference.get().onShuffleModeChanged(); reference.get().onShuffleModeChanged();
break; break;
case MusicPlayerRemote.SERVICE_BOUND:
reference.get().onServiceConnected();
break;
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 KiB