package org.lineageos.eleven;
import android.Manifest.permission;
-import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.Notification;
+import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.AlbumColumns;
import android.provider.MediaStore.Audio.AudioColumns;
+import android.support.annotation.NonNull;
+import android.support.v4.os.BuildCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.LongSparseArray;
/**
* A backbround {@link Service} used to keep music playing between activities
- * and when the user moves Apollo into the background.
+ * and when the user moves Eleven into the background.
*/
@SuppressLint("NewApi")
public class MusicPlaybackService extends Service {
/**
* Indicates that the music has paused or resumed
*/
- public static final String PLAYSTATE_CHANGED = "org.lineageos.eleven.playstatechanged";
+ public static final String PLAYSTATE_CHANGED = BuildConstants.PACKAGE_NAME + ".playstatechanged";
/**
* Indicates that music playback position within
* a title was changed
*/
- public static final String POSITION_CHANGED = "org.lineageos.eleven.positionchanged";
+ public static final String POSITION_CHANGED = BuildConstants.PACKAGE_NAME + ".positionchanged";
/**
* Indicates the meta data has changed in some way, like a track change
*/
- public static final String META_CHANGED = "org.lineageos.eleven.metachanged";
+ public static final String META_CHANGED = BuildConstants.PACKAGE_NAME + ".metachanged";
/**
* Indicates the queue has been updated
*/
- public static final String QUEUE_CHANGED = "org.lineageos.eleven.queuechanged";
+ public static final String QUEUE_CHANGED = BuildConstants.PACKAGE_NAME + ".queuechanged";
/**
* Indicates the queue has been updated
*/
- public static final String PLAYLIST_CHANGED = "org.lineageos.eleven.playlistchanged";
+ public static final String PLAYLIST_CHANGED = BuildConstants.PACKAGE_NAME + ".playlistchanged";
/**
* Indicates the repeat mode changed
*/
- public static final String REPEATMODE_CHANGED = "org.lineageos.eleven.repeatmodechanged";
+ public static final String REPEATMODE_CHANGED = BuildConstants.PACKAGE_NAME + ".repeatmodechanged";
/**
* Indicates the shuffle mode changed
*/
- public static final String SHUFFLEMODE_CHANGED = "org.lineageos.eleven.shufflemodechanged";
+ public static final String SHUFFLEMODE_CHANGED = BuildConstants.PACKAGE_NAME + ".shufflemodechanged";
/**
* Indicates the track fails to play
*/
- public static final String TRACK_ERROR = "org.lineageos.eleven.trackerror";
+ public static final String TRACK_ERROR = BuildConstants.PACKAGE_NAME + ".trackerror";
/**
* For backwards compatibility reasons, also provide sticky
* broadcasts under the music package
*/
- public static final String ELEVEN_PACKAGE_NAME = "org.lineageos.eleven";
+ public static final String ELEVEN_PACKAGE_NAME = BuildConstants.PACKAGE_NAME;
public static final String MUSIC_PACKAGE_NAME = "com.android.music";
/**
* Called to indicate a general service commmand. Used in
* {@link MediaButtonIntentReceiver}
*/
- public static final String SERVICECMD = "org.lineageos.eleven.musicservicecommand";
+ public static final String SERVICECMD = BuildConstants.PACKAGE_NAME + ".musicservicecommand";
/**
* Called to go toggle between pausing and playing the music
*/
- public static final String TOGGLEPAUSE_ACTION = "org.lineageos.eleven.togglepause";
+ public static final String TOGGLEPAUSE_ACTION = BuildConstants.PACKAGE_NAME + ".togglepause";
/**
* Called to go to pause the playback
*/
- public static final String PAUSE_ACTION = "org.lineageos.eleven.pause";
+ public static final String PAUSE_ACTION = BuildConstants.PACKAGE_NAME + ".pause";
/**
* Called to go to stop the playback
*/
- public static final String STOP_ACTION = "org.lineageos.eleven.stop";
+ public static final String STOP_ACTION = BuildConstants.PACKAGE_NAME + ".stop";
/**
* Called to go to the previous track or the beginning of the track if partway through the track
*/
- public static final String PREVIOUS_ACTION = "org.lineageos.eleven.previous";
+ public static final String PREVIOUS_ACTION = BuildConstants.PACKAGE_NAME + ".previous";
/**
* Called to go to the previous track regardless of how far in the current track the playback is
*/
- public static final String PREVIOUS_FORCE_ACTION = "org.lineageos.eleven.previous.force";
+ public static final String PREVIOUS_FORCE_ACTION = BuildConstants.PACKAGE_NAME + ".previous.force";
/**
* Called to go to the next track
*/
- public static final String NEXT_ACTION = "org.lineageos.eleven.next";
+ public static final String NEXT_ACTION = BuildConstants.PACKAGE_NAME + ".next";
/**
* Called to change the repeat mode
*/
- public static final String REPEAT_ACTION = "org.lineageos.eleven.repeat";
+ public static final String REPEAT_ACTION = BuildConstants.PACKAGE_NAME + ".repeat";
/**
* Called to change the shuffle mode
*/
- public static final String SHUFFLE_ACTION = "org.lineageos.eleven.shuffle";
+ public static final String SHUFFLE_ACTION = BuildConstants.PACKAGE_NAME + ".shuffle";
public static final String FROM_MEDIA_BUTTON = "frommediabutton";
* Used to easily notify a list that it should refresh. i.e. A playlist
* changes
*/
- public static final String REFRESH = "org.lineageos.eleven.refresh";
+ public static final String REFRESH = BuildConstants.PACKAGE_NAME + ".refresh";
/**
* Used by the alarm intent to shutdown the service after being idle
*/
- private static final String SHUTDOWN = "org.lineageos.eleven.shutdown";
+ private static final String SHUTDOWN = BuildConstants.PACKAGE_NAME + ".shutdown";
/**
* Called to notify of a timed text
*/
- public static final String NEW_LYRICS = "org.lineageos.eleven.lyrics";
+ public static final String NEW_LYRICS = BuildConstants.PACKAGE_NAME + ".lyrics";
/**
* Called to update the remote control client
*/
- public static final String UPDATE_LOCKSCREEN = "org.lineageos.eleven.updatelockscreen";
+ public static final String UPDATE_LOCKSCREEN = BuildConstants.PACKAGE_NAME + ".updatelockscreen";
public static final String CMDNAME = "command";
/**
* The max size allowed for the track history
* TODO: Comeback and rewrite/fix all the whole queue code bugs after demo
- * https://cyanogen.atlassian.net/browse/MUSIC-175
- * https://cyanogen.atlassian.net/browse/MUSIC-44
*/
public static final int MAX_HISTORY_SIZE = 1000;
+ private static final String ACTION_AUDIO_PLAYER = BuildConstants.PACKAGE_NAME + ".AUDIO_PLAYER";
+
+ private static final String CHANNEL_NAME = "eleven_playback";
+
public interface TrackErrorExtra {
/**
* Name of the track that was unable to play
private String mLyrics;
- private ArrayList<MusicPlaybackTrack> mPlaylist = new ArrayList<MusicPlaybackTrack>(100);
+ private ArrayList<MusicPlaybackTrack> mPlaylist = new ArrayList<>(100);
private long[] mAutoShuffleList = null;
// Make sure we don't indefinitely hold the wake lock under any circumstances
mHeadsetHookWakeLock.acquire(10000);
- Message msg = mPlayerHandler.obtainMessage(HEADSET_HOOK_EVENT, Long.valueOf(timestamp));
+ Message msg = mPlayerHandler.obtainMessage(HEADSET_HOOK_EVENT, timestamp);
msg.sendToTarget();
}
// remove the items from the history
// this is not ideal as the history shouldn't be impacted by this
// but since we are removing items from the array, it will throw
- // an exception if we keep it around. Idealistically with the queue
- // rewrite this should be all be fixed
- // https://cyanogen.atlassian.net/browse/MUSIC-44
+ // an exception if we keep it around.
ListIterator<Integer> positionIterator = mHistory.listIterator();
while (positionIterator.hasNext()) {
int pos = positionIterator.next();
position = mPlaylist.size();
}
- final ArrayList<MusicPlaybackTrack> arrayList = new ArrayList<MusicPlaybackTrack>(addlen);
+ final ArrayList<MusicPlaybackTrack> arrayList = new ArrayList<>(addlen);
for (int i = 0; i < list.length; i++) {
arrayList.add(new MusicPlaybackTrack(list[i], sourceId, sourceType, i));
}
// has been played
final int numHistory = mHistory.size();
for (int i = 0; i < numHistory; i++) {
- final int idx = mHistory.get(i).intValue();
+ final int idx = mHistory.get(i);
if (idx >= 0 && idx < numTracks) {
trackNumPlays[idx]++;
}
// how many tracks share that count
int minNumPlays = Integer.MAX_VALUE;
int numTracksWithMinNumPlays = 0;
- for (int i = 0; i < trackNumPlays.length; i++) {
+ for (final int trackNumPlay : trackNumPlays) {
// if we found a new track that has less number of plays, reset the counters
- if (trackNumPlays[i] < minNumPlays) {
- minNumPlays = trackNumPlays[i];
+ if (trackNumPlay < minNumPlays) {
+ minNumPlays = trackNumPlay;
numTracksWithMinNumPlays = 1;
- } else if (trackNumPlays[i] == minNumPlays) {
+ } else if (trackNumPlay == minNumPlays) {
// increment this track shares the # of tracks
numTracksWithMinNumPlays++;
}
musicIntent.setAction(what.replace(ELEVEN_PACKAGE_NAME, MUSIC_PACKAGE_NAME));
sendStickyBroadcast(musicIntent);
- if (what.equals(META_CHANGED)) {
- // Add the track to the recently played list.
- mRecentsCache.addSongId(getAudioId());
-
- mSongPlayCountCache.bumpSongCount(getAudioId());
- } else if (what.equals(QUEUE_CHANGED)) {
- saveQueue(true);
- if (isPlaying()) {
- // if we are in shuffle mode and our next track is still valid,
- // try to re-use the track
- // We need to reimplement the queue to prevent hacky solutions like this
- // https://cyanogen.atlassian.net/browse/MUSIC-175
- // https://cyanogen.atlassian.net/browse/MUSIC-44
- if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size()
- && getShuffleMode() != SHUFFLE_NONE) {
- setNextTrack(mNextPlayPos);
- } else {
- setNextTrack();
+ switch (what) {
+ case META_CHANGED:
+ // Add the track to the recently played list.
+ mRecentsCache.addSongId(getAudioId());
+
+ mSongPlayCountCache.bumpSongCount(getAudioId());
+ break;
+ case QUEUE_CHANGED:
+ saveQueue(true);
+ if (isPlaying()) {
+ // if we are in shuffle mode and our next track is still valid,
+ // try to re-use the track
+ // We need to reimplement the queue to prevent hacky solutions like this
+ if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size()
+ && getShuffleMode() != SHUFFLE_NONE) {
+ setNextTrack(mNextPlayPos);
+ } else {
+ setNextTrack();
+ }
}
- }
- } else {
- saveQueue(false);
+ break;
+ default:
+ saveQueue(false);
+ break;
}
if (what.equals(PLAYSTATE_CHANGED)) {
.setMediaSession(mSession.getSessionToken())
.setShowActionsInCompactView(0, 1, 2);
- Intent nowPlayingIntent = new Intent("org.lineageos.eleven.AUDIO_PLAYER")
+ Intent nowPlayingIntent = new Intent(ACTION_AUDIO_PLAYER)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent clickIntent = PendingIntent.getActivity(this, 0, nowPlayingIntent, 0);
BitmapWithColors artwork = getAlbumArt(false);
mNotificationPostTime = System.currentTimeMillis();
}
- Notification.Builder builder = new Notification.Builder(this)
+ Notification.Builder builder = new Notification.Builder(this, CHANNEL_NAME)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(artwork.getBitmap())
.setContentIntent(clickIntent)
builder.setColor(artwork.getVibrantDarkColor());
+ if (BuildCompat.isAtLeastO()) {
+ NotificationChannel channel = mNotificationManager
+ .getNotificationChannel(CHANNEL_NAME);
+
+ if (channel == null) {
+ String name = getString(R.string.channel_music);
+
+ channel = new NotificationChannel(CHANNEL_NAME, name,
+ mNotificationManager.IMPORTANCE_DEFAULT);
+ channel.setShowBadge(false);
+ channel.enableVibration(false);
+ channel.setSound(null, null);
+ mNotificationManager.createNotificationChannel(channel);
+ }
+
+ builder.setChannelId(channel.getId());
+ }
+
return builder.build();
}
/**
* Reloads the queue as the user left it the last time they stopped using
- * Apollo
+ * Eleven
*/
private void reloadQueue() {
int id = mCardId;
*/
private String getValueForDownloadedFile(Context context, Uri uri, String column) {
- Cursor cursor = null;
final String[] projection = {
column
};
-
- try {
- cursor = context.getContentResolver().query(uri, projection, null, null, null);
+ try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
return cursor.getString(0);
}
- } finally {
- if (cursor != null) {
- cursor.close();
- }
}
return null;
}
if (removeFromHistory) {
mHistory.remove(histsize - 1);
}
- return pos.intValue();
+ return pos;
} else {
if (mPlayPos > 0) {
return mPlayPos - 1;
*/
public MusicPlayerHandler(final MusicPlaybackService service, final Looper looper) {
super(looper);
- mService = new WeakReference<MusicPlaybackService>(service);
+ mService = new WeakReference<>(service);
}
/**
private static final class Shuffler {
- private final LinkedList<Integer> mHistoryOfNumbers = new LinkedList<Integer>();
+ private final LinkedList<Integer> mHistoryOfNumbers = new LinkedList<>();
- private final TreeSet<Integer> mPreviousNumbers = new TreeSet<Integer>();
+ private final TreeSet<Integer> mPreviousNumbers = new TreeSet<>();
private final Random mRandom = new Random();
int next;
do {
next = mRandom.nextInt(interval);
- } while (next == mPrevious && interval > 1
- && !mPreviousNumbers.contains(Integer.valueOf(next)));
+ } while (next == mPrevious && interval > 1 && !mPreviousNumbers.contains(next));
mPrevious = next;
mHistoryOfNumbers.add(mPrevious);
mPreviousNumbers.add(mPrevious);
* Constructor of <code>MultiPlayer</code>
*/
public MultiPlayer(final MusicPlaybackService service) {
- mService = new WeakReference<MusicPlaybackService>(service);
+ mService = new WeakReference<>(service);
mSrtManager = new SrtManager() {
@Override
public void onTimedText(String text) {
* @return The duration in milliseconds
*/
public long duration() {
- return mCurrentMediaPlayer.getDuration();
+ try {
+ return mCurrentMediaPlayer.getDuration();
+ } catch (IllegalStateException exc) {
+ Log.e(TAG, "Could not get duration", exc);
+ }
+ return 0L;
}
/**
* @return The current position in milliseconds
*/
public long position() {
- return mCurrentMediaPlayer.getCurrentPosition();
+ try {
+ return mCurrentMediaPlayer.getCurrentPosition();
+ } catch (IllegalStateException exc) {
+ Log.e(TAG, "Could not get current position", exc);
+ }
+ return 0L;
}
/**
private final WeakReference<MusicPlaybackService> mService;
private ServiceStub(final MusicPlaybackService service) {
- mService = new WeakReference<MusicPlaybackService>(service);
+ mService = new WeakReference<>(service);
}
/**