-
-
Save daniel-c05/308d878b5539933f6541 to your computer and use it in GitHub Desktop.
Some bits of code on a Music playback service, and on an Application class that helps ACRA logs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ReportsCrashes(formKey = "myFormId...", | |
mode = ReportingInteractionMode.TOAST, | |
mailTo = "my.email@gmail.com", | |
resToastText = R.string.app_crashed_prompt | |
) | |
public class MyApplication extends Application{ | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
// The following line triggers the initialization of ACRA | |
ACRA.init(this); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MyMusicService extends Service { | |
@Override | |
public void onCreate () { | |
Log.v(HomeActivity.TAG, "Service Created"); | |
mContext = getApplicationContext(); | |
IntentFilter commandFilter = new IntentFilter(); | |
commandFilter.addAction(ACTION_PLAY); | |
//..May other filters | |
registerReceiver(mReceiver, commandFilter); | |
mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); | |
if(mgr != null) { | |
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); | |
} | |
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); | |
curQueue = new ArrayList<Long>(); | |
restoreQueue(); | |
initiatePlayer(); //Here we do not call prepare yet | |
} | |
@Override | |
public void onDestroy () { | |
Log.v(HomeActivity.TAG, "Service Destroyed"); | |
//Save the songs on queue | |
saveQueue(); | |
if (mCursor != null) { | |
//close the cursor if not null | |
mCursor.close(); | |
} | |
//cancel notification if any | |
mNotificationManager.cancel(mId); | |
//unregister the broadcast receiver | |
unregisterReceiver(mReceiver); | |
//stop listening to phone state | |
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); | |
} | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
Log.v(HomeActivity.TAG, "Received start id " + startId + ": " + intent); | |
return START_STICKY; | |
} | |
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { | |
@Override | |
public void onReceive(Context context, Intent intent) { | |
String action = intent.getAction(); | |
if (action.equals(Intent.ACTION_HEADSET_PLUG)) { | |
if (mPlayer != null && mPlayer.isPlaying()) { | |
mPlayer.pause(); | |
} | |
} | |
else if (action.equals(ACTION_PLAYLIST)) { | |
changePlaylist(intent.getLongExtra(EXTRA_PLAYLIST_ID, 0)); | |
} | |
else if (action.equals(ACTION_DISPLAY_PENDING_NOTIFICATION)) { | |
if (isPlaying()) { | |
Log.v(HomeActivity.TAG, "Attempting to show notification"); | |
showNotifaction = true; | |
showNotification(); | |
} | |
} | |
else if (action.equals(ACTION_CANCEL_NOTIFICATION)) { | |
Log.v(HomeActivity.TAG, "Attempting to cancel notification"); | |
showNotifaction = false; | |
stopForeground(true); //This somehow doesn't cancel the notification | |
mNotificationManager.cancel(mId); //This has to be called too | |
} | |
else if (action.equals(ACTION_ENQUEUE)) { | |
final long [] songs = intent.getLongArrayExtra(EXTRA_QUEUE_SONGS); | |
final boolean play = intent.getBooleanExtra(EXTRA_QUEUE_PLAY, false); | |
updateCurQueue(songs, play); | |
} | |
else if (action.equals(ACTION_CLEAR_QUEUE)) { | |
clearQueue(); | |
} | |
else if (action.equals(ACTION_NEXT)) { | |
playNextSong(true, intent.getBooleanExtra(EXTRA_BOOL_FORCE, true)); | |
} | |
else if (action.equals(ACTION_PREVIOUS)) { | |
playPreviousSong(intent.getBooleanExtra(EXTRA_BOOL_FORCE, true)); | |
} | |
else if (action.equals(ACTION_STOP)) { | |
stopPlayBack(); | |
} | |
else if (action.equals(ACTION_PLAY_PAUSE)) { | |
playOrPause(intent.getBooleanExtra(EXTRA_BOOL_FORCE, true)); | |
} | |
else if (action.equals(ACTION_PLAY)) { | |
curSongId = intent.getExtras().getLong("_id"); | |
if (curQueue.contains(curSongId)) { | |
mCurPosition = curQueue.indexOf(curSongId); | |
} | |
else { | |
mCurPosition = 0; | |
} | |
playSong(curSongId, intent.getBooleanExtra(EXTRA_NOTIFY, false)); | |
} | |
} | |
}; | |
protected void playSong(long songId, boolean show) { | |
if (!curQueue.contains(songId)) { | |
curQueue.add(songId); | |
notifyQueueChanged(); | |
} | |
mCurPosition = curQueue.indexOf(songId); | |
curSongId = songId; | |
try { | |
String selection = Audio.Media._ID + "=" + String.valueOf(songId); | |
//The cursor I talked about | |
mCursor = mContext.getContentResolver().query(MusicManager.URI_SONGS, MusicManager.ALL_MEDIA_COLS, selection, null, null); | |
if (mCursor.moveToFirst()) { | |
if (mPlayer == null) { | |
initiatePlayer(); | |
} | |
mPlayer.reset(); | |
mPlayer.setDataSource(mCursor.getString((mCursor.getColumnIndex(Audio.Media.DATA)))); | |
//I know I should use prepareAsync, bite me lol | |
mPlayer.prepare(); | |
mPlayer.start(); | |
getCurTrackDetails(); | |
if (show) { | |
showNotification(); | |
} | |
} | |
} catch (Exception e) { | |
Log.v(HomeActivity.TAG, e.toString()); | |
} | |
} | |
protected void playPreviousSong(boolean show) { | |
if (mPlayer == null) { | |
return; | |
} | |
if (curQueue.size() == 0) { | |
return; | |
} | |
if (mPlayer.getCurrentPosition() < MIN_MILSECS_TO_REPEAT && mCurPosition > 0) { | |
mCurPosition--; | |
} | |
playSong(curQueue.get(mCurPosition), show); | |
} | |
protected void playNextSong(boolean force, boolean show) { | |
if (mPlayer == null) { | |
return; | |
} | |
if (curQueue.size() == 0) { | |
return; | |
} | |
if(mCurRepeatStatus == REPEAT_ON) { | |
if (!force) { | |
repeatSong(show); | |
return; | |
} | |
} | |
else if (mCurRepeatStatus == REPEAT_ALL) { | |
if (!force) { | |
repeatQueue(show); | |
return; | |
} | |
} | |
if (mCurPosition == (curQueue.size() - 1)) { | |
if (!mPlayer.isPlaying()) { | |
if (showNotifaction) { | |
mNotification.contentView.setImageViewResource(R.id.notification_button_play, R.drawable.button_play_holo); | |
//mNotification.bigContentView.setImageViewResource(R.id.expanded_notification_button_play, R.drawable.ic_play_holo_dark); | |
mNotificationManager.notify(mId, mNotification); | |
} | |
Intent songFinishedIntent = new Intent(ACTION_PLAYBACK_FINISHED); | |
getApplication().sendBroadcast(songFinishedIntent); | |
startSelfDestroySequence(KILL_ME_TIMEOUT); | |
} | |
else { | |
repeatQueue(show); | |
} | |
return; | |
} | |
mCurPosition++; | |
playSong(curQueue.get(mCurPosition), show); | |
} | |
public static void toggleShuffle() { | |
switch (mCurShuffleStatus) { | |
case SHUFFLE_OFF: | |
mCurShuffleStatus = SHUFFLE_ON; | |
break; | |
case SHUFFLE_ON: | |
mCurShuffleStatus = SHUFFLE_OFF; | |
default: | |
break; | |
} | |
} | |
public static void toggleRepeat() { | |
switch (mCurRepeatStatus) { | |
case REPEAT_OFF: | |
mCurRepeatStatus = REPEAT_ON; | |
break; | |
case REPEAT_ON: | |
mCurRepeatStatus = REPEAT_ALL; | |
break; | |
case REPEAT_ALL: | |
mCurRepeatStatus = REPEAT_OFF; | |
break; | |
default: | |
break; | |
} | |
} | |
public static boolean isPlaying() { | |
if (mPlayer != null) { | |
return mPlayer.isPlaying(); | |
} | |
return false; | |
} | |
/** | |
* Probably the most memory-demanding method. | |
*/ | |
@SuppressLint("NewApi") | |
public void showNotification() { | |
Log.v(HomeActivity.TAG, "Call to show notification received, building"); | |
if (mCursor.isClosed() || mCursor == null) { | |
return; | |
} | |
if (mPlayer == null) { | |
return; | |
} | |
//Build small notification | |
RemoteViews views = new RemoteViews(getPackageName(), R.layout.player_notification); | |
Bitmap bitmap = null; | |
Drawable d; | |
Log.v(HomeActivity.TAG, "Current song Id is: " + curSongId); | |
//Get the cached drawable if any | |
d = UrlImageViewHelper.getImmediateMutableDrawable(getImageUrl(""+ curSongId)); | |
if (d != null) { | |
Log.v(HomeActivity.TAG, "Drawable found for: " + curSongId); | |
//Conver the drawable to a bitmap in order to set the ImageBitmap on the RemoteView | |
bitmap = ((BitmapDrawable)d).getBitmap(); | |
} | |
if (bitmap != null) { | |
Log.v(HomeActivity.TAG, "Updated bitmap"); | |
//This works fine, like I said, crash is while playing the same song, | |
//not when switching to another. | |
views.setImageViewBitmap(R.id.notification_default_drawable, bitmap); | |
} | |
else { | |
views.setImageViewResource(R.id.notification_default_drawable, R.drawable.dummy_thumb); | |
} | |
Intent mediaButtonIntent = new Intent(ACTION_PLAY_PAUSE); | |
mediaButtonIntent.putExtra(EXTRA_BOOL_FORCE, true); | |
PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), | |
1, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT); | |
views.setOnClickPendingIntent(R.id.notification_button_play, mediaPendingIntent); | |
mediaButtonIntent = new Intent(ACTION_NEXT); | |
mediaButtonIntent.putExtra(EXTRA_NOTIFY, true); | |
mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 2, | |
mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT); | |
views.setOnClickPendingIntent(R.id.notification_button_next, mediaPendingIntent); | |
mediaButtonIntent = new Intent(ACTION_STOP); | |
mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 3, | |
mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT); | |
views.setOnClickPendingIntent(R.id.notification_button_exit, mediaPendingIntent); | |
mediaButtonIntent = new Intent(ACTION_PREVIOUS); | |
mediaButtonIntent.putExtra(EXTRA_NOTIFY, true); | |
mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 4, | |
mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT); | |
int playIconResource; | |
if (isPlaying()) { | |
playIconResource = R.drawable.button_pause_holo; | |
} | |
else { | |
playIconResource = R.drawable.button_play_holo; | |
} | |
views.setImageViewResource(R.id.notification_button_play, playIconResource); | |
views.setTextViewText(R.id.notification_song_artist, mCursor.getString(mCursor.getColumnIndex(Audio.Media.ARTIST))); | |
views.setTextViewText(R.id.notification_song_title, mCursor.getString(mCursor.getColumnIndex(Audio.Media.TITLE))); | |
mNotification = new Notification(); | |
mNotification.flags = Notification.FLAG_ONGOING_EVENT; | |
mNotification.icon = R.drawable.ic_launcher; | |
mNotification.contentIntent = PendingIntent | |
.getActivity(this, 0, new Intent(this, PlayerHolder.class) | |
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), 0); | |
mNotification.contentView = views; | |
startForeground(mId, mNotification); //Like before, this seems not to "show" notification | |
mNotificationManager.notify(mId, mNotification); //I have to manually call notify | |
} | |
private void initiatePlayer () { | |
mPlayer = new MediaPlayer(); | |
mPlayer.setOnCompletionListener(new OnCompletionListener() { | |
@Override | |
public void onCompletion(MediaPlayer mp) { | |
playNextSong(false); | |
} | |
}); | |
} | |
/** | |
* I use this method every time a song changes to notify the activities listening | |
* that changes to the UI need to be done. | |
*/ | |
public static void getCurTrackDetails() { | |
if (mCursor == null || curQueue.size() == 0) { | |
return; | |
} | |
Bundle bundle = new Bundle(); | |
bundle.putString(PlayerFragment.TRACK_TITLE, mCursor.getString(mCursor.getColumnIndex(Audio.Media.TITLE))); | |
bundle.putLong(PlayerFragment.TRACK_DURATION, mPlayer.getDuration()); | |
bundle.putString(PlayerFragment.TRACK_ARTIST, mCursor.getString(mCursor.getColumnIndex(Audio.Media.ARTIST))); | |
bundle.putString(PlayerFragment.TRACK_ART, mCursor.getString(mCursor.getColumnIndex(Audio.Media._ID))); | |
bundle.putString(PlayerFragment.TRACK_ID, mCursor.getString(mCursor.getColumnIndex(Audio.Media._ID))); | |
Intent songFinishedIntent = new Intent(ACTION_SONG_CHANGED); | |
songFinishedIntent.putExtras(bundle); | |
mContext.sendBroadcast(songFinishedIntent); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment