Commit Graph

97 Commits

Author SHA1 Message Date
Hugh Daschbach 6f24535b79 Auto logout on unrecoverable authentication error.
When an unrecoverable authentication error occurs, automatically log
the user out.  This seems better than leaving the user wondering why
the UI is unresponsive or why each track they try to play fails with a
quickly disappearing toast.

Unrecoverable authentication errors typically mean the server has
timed out the session out or the session token has been deleted on the
server.  Tokens expire after 14 days without use.

Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale-android/-/merge_requests/342>
2024-02-22 18:15:04 +00:00
Hugh Daschbach 467556d75c Suppress some authentication noise in the log.
Most of this was added to debug issue !102.  So these are vestigial.

The exception here is the handling of AuthorizationException type 2.
These are produced by racing authentication requests and are
successfully managed.  So we need not report these.

Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale-android/-/merge_requests/342>
2024-02-22 18:15:04 +00:00
Hugh Daschbach 2088e06a68 Do not close NowPlayingBottomSheet between tracks.
If the user opens the NowPlayingBottomSheet whilst playing a non empty
queue, leave the BottomSheet open at the end of the playing track.

Part-of: <https://dev.funkwhale.audio/funkwhale/funkwhale-android/-/merge_requests/343>
2024-02-21 21:59:28 -08:00
Hugh Daschbach c1eb9d6b2a Fix landscape view induced MainActivity leak.
With landscape view enabled (e.g. e06b2c7) in the app and auto
rotation enabled on the phone, switching between portrait and
landscape orientations leaks instances of MainActivity.  This prevents
garbage collection of not just the MainActivity object, but fragments
and other objects referenced by the Activity.

This is caused by repositories, the AppContext instance, the player
service, and authentication code maintaining a reference to the
context which with they are initialized.  So rather than initialize
these with an Activity context, pass them the Application context.

Activities are torn down and rebuilt on screen rotation.  The
Application context is not.

To enable instantiation of the FavoritedRepository with the
Application context, delay that repository’s initialization until
first use.  This ensures the Application context is fully initialized.
It is not fully initialized until the MainActivity has been fully
initialized.
2023-11-07 08:33:36 +00:00
Hugh Daschbach 2133d4a4fb Prevent BottomSheet tap leaking to nav panels.
With the BottomSheet open, while trying to tap one of the
controls (esp. add to playlist and favorite buttons) it is easy to
miss the touch point and tap directly on the BottomSheet.

This tap bleeds through to whatever fragment is currently displayed in
the navigation area (Artist, Album, Playlists, etc.).  That tap
changes the view in the navigation panel.  For example, if the Artist
fragment it current, it will open a list of the artists albums.

That change may be surprising when the BottomSheet is toggled closed.
So, ignore BottomSheet taps outside the active controls.
2023-11-07 08:33:36 +00:00
Hugh Daschbach feb86fe9c0 Refactor CoverArt.withContext().
Having changed the context object in CoverArt from a received function
parameter to an initialization time derived variable, withContext no
longer needs a Context parameter.

That leaves the method misnamed.  So rename withContext ->
requestCreator and drop the first parameter.
2023-11-07 08:33:36 +00:00
Hugh Daschbach f65e29af39 Do not create unnecessary Picasso objects.
Address "java.lang.IllegalStateException: Too many receivers"
exceptions.  (See Issue #145).  Each new Picasso object registers its
own NetworkBroadcastReceiver.  Worse, we create a new Picasso object
each time we transform an AlbumCover image.  So do not create
unnecessary Picasso objects.

Rather than depend on receiving a Context object when called to load
an cover art, fetch the Application context as returned from FFA.get()
at singleton construction time.  The Application context is long
lived.

This has an additional advantage.  Not generation new Picasso objects
for each CoverArt image avoids holding a reference to an object that
cannot, later, be garbage collected.
2023-11-07 08:33:36 +00:00
Christophe Henry 31908b6175 Fix buffering progress bar display 2023-10-02 20:30:09 +02:00
Christophe Henry 1a050c2d73 Fixes form peer review 2023-09-28 17:32:53 +02:00
Christophe Henry 056e3a4d66 Use MotionLayout to animate bottom sheet opening 2023-09-27 15:56:15 +02:00
Christophe Henry b924a0c655 Fix bottom sheet being hidden in certain conditions 2023-09-18 20:18:52 +02:00
Christophe Henry 822adcac4a Fix overlap between main fragment and player bottom bar 2023-09-18 17:35:26 +02:00
Christophe Henry fbbd90111d Fix a few regressions with the new bottom sheet 2023-09-18 17:35:26 +02:00
Christophe Henry 45773aac8d Improve player bottom sheet, in particular fling support 2023-09-18 17:35:26 +02:00
Dylan Gageot 8e09dccb9f Transcode at 320kbps when bandwidth limitation is enabled 2023-04-23 17:50:32 +00:00
Dylan Gageot 45ad4bdb8e Add summary for bandwidth limitation 2023-04-23 17:50:32 +00:00
Christophe Henry d25f29b4c1 Prevent IllegalSeekPositionException when initializing the player 2023-04-03 14:51:10 +00:00
Ryan Harg f1947f3b88
Sort Favourites by time 2023-01-13 12:52:52 +01:00
Ryan Harg b4b988da48 Use track cover over album cover if present 2023-01-11 12:41:04 +00:00
Ryan Harg c10b3d4a75 Keep the player always on top 2023-01-10 12:56:20 +00:00
Ryan Harg a810e13cfb Custom cache layer for cover art which ignores (pre-signed URL) query 2023-01-10 10:00:41 +00:00
RenovateBot 7abbd8dbaa Update dependency org.jetbrains.kotlin:kotlin-stdlib-jdk7 to v1.8.0 2023-01-05 13:09:31 +00:00
Hugh Daschbach 1566d1fbcf Open queue scrolled to current track. 2023-01-04 13:28:44 +00:00
RenovateBot 7f0671b055 Update dependency io.insert-koin:koin-core to v3.3.2 2023-01-04 12:35:33 +00:00
Hugh Daschbach ec6187aeac Allow automatic backward skip of a configurable number of seconds on pause (#134). 2022-12-20 09:13:36 +00:00
Ryan Harg 87a0ef5a42 Filter favorites 2022-12-09 08:49:41 +00:00
Ryan Harg 566dca1518 Use Picasso stableKey for better caching against pre-signed URLs 2022-12-08 13:29:34 +00:00
RenovateBot 9f7f0294f6 Update dependency com.google.android.material:material to v1.7.0 2022-12-08 09:23:58 +00:00
RenovateBot 159c7d8d47 Update dependency io.insert-koin:koin-core to v3.2.2 2022-12-07 11:00:49 +00:00
Ryan Harg fa48937b56
Set required flag for pendingIntent 2022-12-06 09:37:20 +01:00
Ryan Harg 2de6ca303e
Necessary upgrades to compileSdk and targetSdk and adjusting code 2022-12-06 09:35:33 +01:00
Hugh Daschbach d734953b54
Replace deprecated SimpleExoPlayer with ExoPlayer.
This is part of an effort to resolve deprecation warnings.

Most of this is simple refactoring of interfaces that change between
the two Player implementations.  There are a few other changes that
deserve further explanation.

Testing indicated that the play/pause button was being reset to pause
in MainActivity:refreshCurrentTrack.  In the past this was likely
masked by the ordering of other callbacks.  We have removed the
nowPlayingToggle.icon update from MainActivity, leaving that UI update
to PlayerService.

One of the bigger refactorings in PlayerService was forced by the
deprecation of Player.EventListener.onPlayerStateChanged.  That forced
separation of handling playWhenReady and playbackState transitions.
In the SimpleExoPlayer implementations, where these transitions were
combined, the module attempted to work out playing state from a
combination of these two state variables.

In addition to separating the reaction to these state changes, we have
added a listener to onIsPlayingChanged, eliminating the need for some
of the earlier logic in Player.EventListener.onPlayerStateChanged.
This addition, along with the separation of state transition
processing, seems to provide a simpler implementation.  But it is,
certainly, a possible source of bugs.
2022-12-06 09:35:33 +01:00
Hugh Daschbach 24de54c7e0
MainActivity: startActivityForResult deprecated.
Migrate startActivityForResult/onActivityResult to
StartActivityForResult/registerForActivityResult in MainActivity.
2022-12-06 09:35:33 +01:00
Hugh Daschbach bea1d1f397
LoginActivity: startActivityForResult deprecated.
Migrate startActivityForResult/onActivityResult to
StartActivityForResult/registerForActivityResult in
LoginActivity/OAuth.

This moves responsibility for scheduling the starting Intent from
OAuth to LoginActivity.

OAuth still generates the Intent.  But instead of starting the intent
directly in OAuth, the intent is returned to LoginActivity.  This
better associates processing the activity result with its invocation.

OAuthTest module updated to accommodate internal API change.
2022-12-06 09:35:33 +01:00
Hugh Daschbach 38a3183b9d
Resolve warning: FragmentPagerAdapter deprecated.
Replace FragmentPagerAdapter with FragmentStateAdapter in
BrowseTabsAdapter.kt.  Refactored getPageTitle as a function that
returns tab name.  Tab text update moved to BrowseFragment.

This requires replacement of setupWithViewPager with
TabMediator.attach in BrowseFragment.

Also requires replacing widget declaration
androidx.viewpager.widget.ViewPager with
androidx.viewpager2.widget.ViewPager2 in fragment_browwse.xml.
2022-12-06 09:35:32 +01:00
Hugh Daschbach 8878e3e68f
Resolve warning: ExoDatabaseProvider deprecated.
Replace ExoDatabaseProvider with StandaloneDatabaseProvider.
2022-12-06 09:35:32 +01:00
Hugh Daschbach 7d49819450
Resolve warning "Unnecessary safe call". 2022-12-06 09:35:32 +01:00
Hugh Daschbach 4827fbccc1
RequentBus: replace deprecated implementation.
Convert RequestBus from deprecated BroadcastChannel to a SharedFlow.
2022-12-06 09:35:32 +01:00
Hugh Daschbach 1a038b2355
CommandBus: replace deprecated implementation.
Convert CommandBus from deprecated BroadcastChannel to a SharedFlow.
2022-12-06 09:35:32 +01:00
Hugh Daschbach be8901390e
EventBus: replace deprecated implementation.
Convert EventBus from deprecated BroadcastChannel to a SharedFlow.
2022-12-06 09:35:32 +01:00
Hugh Daschbach 6d1ad9cd78
ProgressBus: replace deprecated implementation.
Convert Progress from deprecated BroadcastChannel to a StateFlow.
2022-12-06 09:35:31 +01:00
Hugh Daschbach 72b4aea35a
Resolve deprecation warning in MediaSession.
Remove setting of MediaSession flags that are now mandatory and
assumed set.
2022-12-06 09:35:31 +01:00
Hugh Daschbach 48570e24ea Minor cleanup: consistent deserialization. 2022-09-03 11:09:21 +00:00
Ryan Harg bfdac03d0c Upgrade to Kotlin 1.7.0 2022-08-26 12:06:41 +00:00
Ryan Harg 7c91e819c9 Remove Versions object 2022-08-25 12:58:19 +00:00
Hugh Daschbach 79e27578e5 Fix issue #124 - empty queue on restart.
The Gson deserializer required parameter is a reader object.  It
silently fails when passed a string.
2022-07-21 11:15:54 +00:00
Ryan Harg 8f1f565652 Bugfix/122 fix resource leakage 2022-06-21 08:03:46 +00:00
Ryan Harg c43baae8e8 #117: Use the same contentId when adding and removing downloads 2022-06-17 09:50:39 +00:00
Ryan Harg 1b0381fde4 #119: Default deserializer has no string deserialization implementation 2022-06-16 13:10:10 +00:00
Hugh Daschbach 37e270071a
Fix Bluetooth control button unresponsiveness.
With Oreo and later, Bluetooth control buttons may kill FFA if it is
not the foreground application.  Once this happens to resume playback,
one needs to restart playback from the phone, rather than the
play/pause action of Bluetooth headset.

For example:
    D MediaSessionService: Sending KeyEvent { action=ACTION_UP, keyCode=KEYCODE_MEDIA_PLAY, scanCode=0, metaState=0, flags=0x0, repeatCount=0, eventTime=0, downTime=0, deviceId=-1, source=0x0 } to audio.funkwhale.ffa.dev/audio.funkwhale.ffa.dev (

    W ActivityManager: Background start not allowed: service Intent { act=android.intent.action.MEDIA_BUTTON cmp=audio.funkwhale.ffa.dev/audio.funkwhale.ffa.playback.PlayerService (has extras) } to audio.funkwhale.ffa.dev/audio.funkwhale.ffa.play
   549 uid=10149 pkg=audio.funkwhale.ffa.dev startFg?=false
    D AndroidRuntime: Shutting down VM
   --------- beginning of crash
    E AndroidRuntime: FATAL EXCEPTION: main
    E AndroidRuntime: Process: audio.funkwhale.ffa.dev, PID: 14549
    E AndroidRuntime: java.lang.IllegalStateException: Not allowed to start service Intent { act=android.intent.action.MEDIA_BUTTON cmp=audio.funkwhale.ffa.dev/audio.funkwhale.ffa.playback.PlayerService (has extras) }: app is in background uid UidRecord{72fa8f8 u0a149 CAC  bg:+11m56s597ms idle change:cached procs:1 seq(0,0,0)}
    E AndroidRuntime:        at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1577)
    E AndroidRuntime:        at android.app.ContextImpl.startService(ContextImpl.java:1532)
    E AndroidRuntime:        at android.content.ContextWrapper.startService(ContextWrapper.java:664)
    E AndroidRuntime:        at audio.funkwhale.ffa.playback.MediaSession$connector$2.invoke$lambda-3$lambda-2(MediaSession.kt:47)
    E AndroidRuntime:        at audio.funkwhale.ffa.playback.MediaSession$connector$2.$r8$lambda$jU84j_zRyeYuvwLrRY0b6XyQBMs(Unknown Source:0)
    E AndroidRuntime:        at audio.funkwhale.ffa.playback.MediaSession$connector$2$$ExternalSyntheticLambda0.onMediaButtonEvent(Unknown Source:2)
    E AndroidRuntime:        at com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector$ComponentListener.onMediaButtonEvent(MediaSessionConnector.java:1396)
    E AndroidRuntime:        at android.support.v4.media.session.MediaSessionCompat$Callback$MediaSessionCallbackApi21.onMediaButtonEvent(MediaSessionCompat.java:1602)
    E AndroidRuntime:        at android.media.session.MediaSession$CallbackMessageHandler.handleMessage(MediaSession.java:1471)
    E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
    E AndroidRuntime:        at android.os.Looper.loop(Looper.java:193)
    E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:6718)
    E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
    E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
    E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
    W ActivityManager:   Force finishing activity audio.funkwhale.ffa.dev/audio.funkwhale.ffa.activities.MainActivity

xref: https://stackoverflow.com/questions/46445265/android-8-0-java-lang-illegalstateexception-not-allowed-to-start-service-inten
2022-06-16 14:02:20 +02:00