We might call timeline.add() with an invalid position if we skipped a song due to being unfilled.
Use 'added' instead of 'j' to calculate the queue position.
If a song somehow ends up with multiple artist, album entries, the view will show the song multiple times (each possible combination).
This is - confusing - and such a song should not exist. We are now deleting such entries during cleanups.
Songs with the same mtime are likely in the same album, so sorting by disc and track doesn't hurt, especially as we sort by disc,track by default anyway when returning songs.
We also do the same for playcount sortings because we can.
No idea how people manage to hit this, but it seems to be a thing on Samsung phones.
Sample stacktrace:
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=12655, uid=10269 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.os.Parcel.readException(Parcel.java:1620)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
at android.content.ContentResolver.query(ContentResolver.java:502)
at android.content.ContentResolver.query(ContentResolver.java:445)
at ch.blinkenlights.android.vanilla.MediaUtils.getAndroidMediaIds(MediaUtils.java:591)
at ch.blinkenlights.android.vanilla.PlaybackService.scrobbleBroadcast(PlaybackService.java:1108)
at ch.blinkenlights.android.vanilla.PlaybackService.broadcastChange(PlaybackService.java:1064)
at ch.blinkenlights.android.vanilla.PlaybackService.handleMessage(PlaybackService.java:1543)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
Note that this happens WHILE we play a song - so claiming to not have READ_EXTERNAL_STORAGE privileges seems to be - strange.
We register ourselfs as a callback receiver BEFORE the adapter has been created.
This crash is unlikely but happens once in a while according to the play store.