use a normal service instead of a bound service

This commit is contained in:
tibbi 2016-02-13 12:23:41 +01:00
parent d35e0ddcd7
commit 788e9fa52d
10 changed files with 194 additions and 261 deletions

View file

@ -9,6 +9,7 @@
<application
android:allowBackup="true"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
@ -32,7 +33,21 @@
</intent-filter>
</activity>
<service android:name="musicplayer.simplemobiletools.com.MusicService"/>
<service
android:name="musicplayer.simplemobiletools.com.MusicService"
android:exported="false">
<intent-filter>
<action android:name="musicplayer.simplemobiletools.com.action.INIT"/>
<action android:name="musicplayer.simplemobiletools.com.action.PREVIOUS"/>
<action android:name="musicplayer.simplemobiletools.com.action.PAUSE"/>
<action android:name="musicplayer.simplemobiletools.com.action.PLAYPAUSE"/>
<action android:name="musicplayer.simplemobiletools.com.action.NEXT"/>
<action android:name="musicplayer.simplemobiletools.com.action.STOP"/>
<action android:name="musicplayer.simplemobiletools.com.action.PLAYPOS"/>
<action android:name="musicplayer.simplemobiletools.com.action.INCOMING_CALL_START"/>
<action android:name="musicplayer.simplemobiletools.com.action.INCOMING_CALL_STOP"/>
</intent-filter>
</service>
<receiver android:name=".MyWidgetProvider">
<intent-filter>

View file

@ -4,4 +4,15 @@ public class Constants {
public static final String PREFS = "prefs";
public static final String WIDGET_BG_COLOR = "widget_bg_color";
public static final String WIDGET_TEXT_COLOR = "widget_text_color";
public static final String SONG_POS = "song_position";
public static final String INIT = "musicplayer.simplemobiletools.com.action.INIT";
public static final String PREVIOUS = "musicplayer.simplemobiletools.com.action.PREVIOUS";
public static final String PAUSE = "musicplayer.simplemobiletools.com.action.PAUSE";
public static final String PLAYPAUSE = "musicplayer.simplemobiletools.com.action.PLAYPAUSE";
public static final String NEXT = "musicplayer.simplemobiletools.com.action.NEXT";
public static final String STOP = "musicplayer.simplemobiletools.com.action.STOP";
public static final String PLAYPOS = "musicplayer.simplemobiletools.com.action.PLAYPOS";
public static final String CALL_START = "musicplayer.simplemobiletools.com.action.INCOMING_CALL_START";
public static final String CALL_STOP = "musicplayer.simplemobiletools.com.action.INCOMING_CALL_STOP";
}

View file

@ -1,21 +1,8 @@
package musicplayer.simplemobiletools.com;
import java.util.ArrayList;
public class Events {
public static class PreviousSong {
}
public static class PlayPauseSong {
}
public static class PauseSong {
}
public static class NextSong {
}
public static class StopSong {
}
public static class IncomingCallStart {
}
@ -45,4 +32,16 @@ public class Events {
return isPlaying;
}
}
public static class PlaylistUpdated {
private ArrayList<Song> songs;
PlaylistUpdated(ArrayList<Song> songs) {
this.songs = songs;
}
public ArrayList<Song> getSongs() {
return songs;
}
}
}

View file

@ -4,8 +4,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.squareup.otto.Bus;
public class HeadsetPlugReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@ -13,8 +11,7 @@ public class HeadsetPlugReceiver extends BroadcastReceiver {
int state = intent.getIntExtra("state", -1);
// we care only about the case where the headphone gets unplugged
if (state == 0) {
final Bus bus = BusProvider.getInstance();
bus.post(new Events.PauseSong());
context.startService(new Intent(Constants.PAUSE));
}
}
}

View file

@ -1,20 +1,25 @@
package musicplayer.simplemobiletools.com;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import com.squareup.otto.Bus;
public class IncomingCallReceiver extends PhoneStateListener {
private Context cxt;
public IncomingCallReceiver(Context context) {
cxt = context;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
final Bus bus = BusProvider.getInstance();
if (state == TelephonyManager.CALL_STATE_RINGING) {
bus.post(new Events.IncomingCallStart());
cxt.startService(new Intent(Constants.CALL_START));
} else if (state == TelephonyManager.CALL_STATE_IDLE || state == TelephonyManager.CALL_STATE_OFFHOOK) {
bus.post(new Events.IncomingCallStop());
cxt.startService(new Intent(Constants.CALL_STOP));
}
}
}

View file

@ -1,25 +1,26 @@
package musicplayer.simplemobiletools.com;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
private MusicService musicService;
private boolean isMusicBound;
private Bus bus;
@Bind(R.id.playPauseBtn) ImageView playPauseBtn;
@Bind(R.id.songs) ListView songsList;
@ -31,16 +32,15 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
final Intent intent = new Intent(this, MusicService.class);
bindService(intent, musicConnection, Context.BIND_AUTO_CREATE);
startService(intent);
bus = BusProvider.getInstance();
bus.register(this);
startService(new Intent(Constants.INIT));
}
private void songPicked(int pos) {
musicService.setSong(pos, true);
updateSongInfo(musicService.getCurrSong());
setPauseIcon();
final Intent intent = new Intent(Constants.PLAYPOS);
intent.putExtra(Constants.SONG_POS, pos);
startService(intent);
}
private void updateSongInfo(Song song) {
@ -50,27 +50,8 @@ public class MainActivity extends AppCompatActivity {
}
}
private ServiceConnection musicConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
final MusicService.MyBinder binder = (MusicService.MyBinder) iBinder;
musicService = binder.getService();
isMusicBound = true;
updateSongInfo(musicService.getCurrSong());
if (musicService.isPlaying())
setPauseIcon();
fillSongsListView();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
isMusicBound = false;
}
};
private void fillSongsListView() {
final SongAdapter adapter = new SongAdapter(this, musicService.getSongs());
private void fillSongsListView(ArrayList<Song> songs) {
final SongAdapter adapter = new SongAdapter(this, songs);
songsList.setAdapter(adapter);
songsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
@ -80,127 +61,48 @@ public class MainActivity extends AppCompatActivity {
});
}
@Override
protected void onResume() {
super.onResume();
if (musicService != null) {
updateSongInfo(musicService.getCurrSong());
if (musicService.isPlaying()) {
setPauseIcon();
} else {
setPlayIcon();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isMusicBound) {
isMusicBound = false;
unbindService(musicConnection);
}
bus.unregister(this);
}
@OnClick(R.id.previousBtn)
public void previousClicked() {
if (isPlaylistEmpty())
return;
playPreviousSong();
startService(new Intent(Constants.PREVIOUS));
}
@OnClick(R.id.playPauseBtn)
public void playPauseClicked() {
if (isPlaylistEmpty())
return;
resumePauseSong();
startService(new Intent(Constants.PLAYPAUSE));
}
@OnClick(R.id.nextBtn)
public void nextClicked() {
if (isPlaylistEmpty())
return;
playNextSong();
startService(new Intent(Constants.NEXT));
}
@OnClick(R.id.stopBtn)
public void stopClicked() {
if (isPlaylistEmpty())
return;
stopMusic();
startService(new Intent(Constants.STOP));
}
public void stopMusic() {
if (musicService != null) {
musicService.stopSong();
setPlayIcon();
}
@Subscribe
public void songChangedEvent(Events.SongChanged event) {
updateSongInfo(event.getSong());
}
public void resumePauseSong() {
if (musicService == null)
return;
@Subscribe
public void songStateChanged(Events.SongStateChanged event) {
int id = R.mipmap.play;
if (event.getIsPlaying())
id = R.mipmap.pause;
if (musicService.isPlaying()) {
pauseSong();
} else {
resumeSong();
}
// in case we just launched the app and pressed play, also update the song and artist name
if (artistTV.getText().toString().trim().isEmpty())
updateSongInfo(musicService.getCurrSong());
playPauseBtn.setImageDrawable(getResources().getDrawable(id));
}
private void resumeSong() {
musicService.resumeSong();
setPauseIcon();
}
private void pauseSong() {
if (musicService == null)
return;
musicService.pauseSong();
setPlayIcon();
}
private void playPreviousSong() {
if (musicService == null)
return;
musicService.playPreviousSong();
setPauseIcon();
updateSongInfo(musicService.getCurrSong());
}
private void playNextSong() {
if (musicService == null)
return;
musicService.playNextSong();
updateSongInfo(musicService.getCurrSong());
setPauseIcon();
}
private void setPlayIcon() {
playPauseBtn.setImageDrawable(getResources().getDrawable(R.mipmap.play));
}
private void setPauseIcon() {
playPauseBtn.setImageDrawable(getResources().getDrawable(R.mipmap.pause));
}
private boolean isPlaylistEmpty() {
if (musicService == null || musicService.getSongs().isEmpty()) {
Utils.showToast(this, R.string.playlist_empty);
return true;
}
return false;
@Subscribe
public void playlistUpdated(Events.PlaylistUpdated event) {
fillSongsListView(event.getSongs());
}
}

View file

@ -10,17 +10,14 @@ import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import java.io.IOException;
import java.util.ArrayList;
@ -32,7 +29,6 @@ public class MusicService extends Service
implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
private static final String TAG = MusicService.class.getSimpleName();
private static final int MIN_DURATION_MS = 20000;
private final IBinder musicBind = new MyBinder();
private HeadsetPlugReceiver headsetPlugReceiver;
private IncomingCallReceiver incomingCallReceiver;
private ArrayList<Song> songs;
@ -55,11 +51,56 @@ public class MusicService extends Service
getSortedSongs();
headsetPlugReceiver = new HeadsetPlugReceiver();
incomingCallReceiver = new IncomingCallReceiver();
incomingCallReceiver = new IncomingCallReceiver(this);
wasPlayingAtCall = false;
initMediaPlayer();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case Constants.INIT:
bus.post(new Events.PlaylistUpdated(songs));
bus.post(new Events.SongChanged(currSong));
songStateChanged(isPlaying());
break;
case Constants.PREVIOUS:
playPreviousSong();
break;
case Constants.PAUSE:
pauseSong();
break;
case Constants.PLAYPAUSE:
if (isPlaying())
pauseSong();
else
resumeSong();
break;
case Constants.NEXT:
playNextSong();
break;
case Constants.STOP:
stopSong();
break;
case Constants.PLAYPOS:
playSong(intent);
break;
case Constants.CALL_START:
incomingCallStart();
break;
case Constants.CALL_STOP:
incomingCallStop();
break;
default:
break;
}
}
return START_NOT_STICKY;
}
public void initMediaPlayer() {
player = new MediaPlayer();
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
@ -151,6 +192,10 @@ public class MusicService extends Service
}
public void resumeSong() {
if (songs.isEmpty()) {
fillPlaylist();
}
if (songs.isEmpty())
return;
@ -182,10 +227,16 @@ public class MusicService extends Service
player.seekTo(0);
}
private void playSong(Intent intent) {
final int pos = intent.getIntExtra(Constants.SONG_POS, 0);
setSong(pos, true);
}
public void setSong(int songId, boolean addNewSong) {
if (songs.isEmpty())
return;
final boolean wasPlaying = isPlaying();
if (player == null)
initMediaPlayer();
@ -204,32 +255,15 @@ public class MusicService extends Service
player.prepareAsync();
bus.post(new Events.SongChanged(currSong));
songStateChanged(true);
if (!wasPlaying) {
songStateChanged(true);
}
}
public Song getCurrSong() {
return currSong;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return musicBind;
}
@Override
public boolean onUnbind(Intent intent) {
bus.post(new Events.SongChanged(null));
songStateChanged(false);
if (player != null && !player.isPlaying()) {
destroyPlayer();
}
return false;
}
public ArrayList<Song> getSongs() {
return songs;
return null;
}
@Override
@ -260,20 +294,32 @@ public class MusicService extends Service
}
private void destroyPlayer() {
player.stop();
player.release();
player = null;
if (player != null) {
player.stop();
player.release();
player = null;
}
final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(incomingCallReceiver, PhoneStateListener.LISTEN_NONE);
}
public class MyBinder extends Binder {
MusicService getService() {
return MusicService.this;
public void incomingCallStart() {
if (isPlaying()) {
wasPlayingAtCall = true;
pauseSong();
} else {
wasPlayingAtCall = false;
}
}
public void incomingCallStop() {
if (wasPlayingAtCall)
resumeSong();
wasPlayingAtCall = false;
}
private void songStateChanged(boolean isPlaying) {
bus.post(new Events.SongStateChanged(isPlaying));
@ -287,54 +333,8 @@ public class MusicService extends Service
try {
unregisterReceiver(headsetPlugReceiver);
} catch (IllegalArgumentException e) {
Log.e(TAG, "IllegalArgumentException " + e.getMessage());
}
}
}
@Subscribe
public void previousSongEvent(Events.PreviousSong event) {
playPreviousSong();
}
@Subscribe
public void playPauseSongEvent(Events.PlayPauseSong event) {
if (isPlaying())
pauseSong();
else
resumeSong();
}
@Subscribe
public void nextSongEvent(Events.NextSong event) {
playNextSong();
}
@Subscribe
public void stopSongEvent(Events.StopSong event) {
stopSong();
}
@Subscribe
public void pauseSongEvent(Events.PauseSong event) {
// if the headset is unplugged, pause the song
pauseSong();
}
@Subscribe
public void incomingCallStart(Events.IncomingCallStart event) {
if (isPlaying()) {
wasPlayingAtCall = true;
pauseSong();
} else {
wasPlayingAtCall = false;
}
}
@Subscribe
public void incomingCallStop(Events.IncomingCallStop event) {
if (wasPlayingAtCall)
resumeSong();
wasPlayingAtCall = false;
}
}

View file

@ -40,6 +40,7 @@ public class MyWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
initVariables(cxt);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
private void setupIntent(String action, int id) {
@ -52,15 +53,14 @@ public class MyWidgetProvider extends AppWidgetProvider {
private void initVariables(Context context) {
cxt = context;
intent = new Intent(cxt, MyWidgetProvider.class);
final ComponentName component = new ComponentName(cxt, MyWidgetProvider.class);
widgetManager = AppWidgetManager.getInstance(cxt);
widgetIds = widgetManager.getAppWidgetIds(component);
if (widgetIds.length == 0)
return;
for (int widgetId : widgetIds) {
remoteViews = getRemoteViews(widgetManager, cxt, widgetId);
}
remoteViews = getRemoteViews(widgetManager, cxt, widgetIds[0]);
intent = new Intent(cxt, MyWidgetProvider.class);
setupViews(cxt);
if (bus == null) {
@ -77,7 +77,7 @@ public class MyWidgetProvider extends AppWidgetProvider {
public void songChangedEvent(Events.SongChanged event) {
currSong = event.getSong();
updateSongInfo();
updateWidget();
updateWidgets();
}
private void updateSongInfo() {
@ -99,7 +99,7 @@ public class MyWidgetProvider extends AppWidgetProvider {
public void songStateChanged(Events.SongStateChanged event) {
isPlaying = event.getIsPlaying();
updatePlayPauseButton();
updateWidget();
updateWidgets();
}
private void updatePlayPauseButton() {
@ -111,8 +111,10 @@ public class MyWidgetProvider extends AppWidgetProvider {
remoteViews.setImageViewBitmap(R.id.playPauseBtn, bmp);
}
private void updateWidget() {
widgetManager.updateAppWidget(widgetIds, remoteViews);
private void updateWidgets() {
for (int widgetId : widgetIds) {
widgetManager.updateAppWidget(widgetId, remoteViews);
}
}
private void updateColors(Context context) {
@ -153,22 +155,23 @@ public class MyWidgetProvider extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {
if (remoteViews == null || widgetManager == null || widgetIds == null || bus == null)
if (remoteViews == null || widgetManager == null || bus == null) {
initVariables(context);
}
final String action = intent.getAction();
switch (action) {
case PREVIOUS:
bus.post(new Events.PreviousSong());
context.startService(new Intent(Constants.PREVIOUS));
break;
case PLAYPAUSE:
bus.post(new Events.PlayPauseSong());
context.startService(new Intent(Constants.PLAYPAUSE));
break;
case NEXT:
bus.post(new Events.NextSong());
context.startService(new Intent(Constants.NEXT));
break;
case STOP:
bus.post(new Events.StopSong());
context.startService(new Intent(Constants.STOP));
break;
default:
super.onReceive(context, intent);
@ -193,7 +196,7 @@ public class MyWidgetProvider extends AppWidgetProvider {
setupButtons();
updateSongInfo();
updatePlayPauseButton();
updateWidget();
updateWidgets();
}
@Override

View file

@ -6,15 +6,15 @@ import android.content.Intent;
import android.os.Handler;
import android.view.KeyEvent;
import com.squareup.otto.Bus;
public class RemoteControlReceiver extends BroadcastReceiver {
private static final int MAX_CLICK_DURATION = 1000;
private static int clicksCnt;
private static Context cxt;
private static Handler handler = new Handler();
@Override
public void onReceive(Context context, Intent intent) {
cxt = context;
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event.getAction() == KeyEvent.ACTION_UP && KeyEvent.KEYCODE_HEADSETHOOK == event.getKeyCode()) {
@ -36,13 +36,12 @@ public class RemoteControlReceiver extends BroadcastReceiver {
if (clicksCnt == 0)
return;
final Bus bus = BusProvider.getInstance();
if (clicksCnt == 1) {
bus.post(new Events.PlayPauseSong());
cxt.startService(new Intent(Constants.PLAYPAUSE));
} else if (clicksCnt == 2) {
bus.post(new Events.NextSong());
cxt.startService(new Intent(Constants.NEXT));
} else {
bus.post(new Events.PreviousSong());
cxt.startService(new Intent(Constants.PREVIOUS));
}
clicksCnt = 0;
}

View file

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/black"
android:gravity="center_horizontal">
<RelativeLayout
android:id="@+id/widget_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/black"
android:gravity="center_horizontal">
<include layout="@layout/widget_controls"/>
</RelativeLayout>