-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some simple refactors & beginning of kotlin conversions of the player classes #11965
base: refactor
Are you sure you want to change the base?
Some simple refactors & beginning of kotlin conversions of the player classes #11965
Conversation
And simplify the code a little
In Kotlin, dealing with nulls works better so we don’t need optional.
The new implementation would throw `ConcurrentModificationExceptions` when destroying the UIs. So let’s play it safe and put the list behind a mutex. Adds a helper class `GuardedByMutex` that can be wrapped around a property to force all use-sites to acquire the lock before doing anything with the data.
No adjustments done yet; only change is that I added an upper bound on `PlayerUi` to the `PlayerUiList` functions, so “everything” is now `null` in `destroyAll`.
This removes a bunch of unncessary checks. We forgo setting player to `null` in onDestroy, because shutting it down and when the service stops should be enough to free it for garbage collection.
Because the class is final, protected does not make sense (Android Studio auto-suggestions)
The `R.id` link from the comment cannot be resolved, so let’s not link it for now. We are using some exoplayer2 resources, let’s silence the warning.
It’s only used in this one place.
Might be a good idea to look into migrating to Media3: https://developer.android.com/media/media3/exoplayer |
@Isira-Seneviratne that’s exactly what newPlayer does. This is the initial work to integrate NewPlayer into NewPipe |
i.e. adjust all the interfaces in a way that we can slot in NewPlayer easily into the existing player logic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good to me, thanks! You can probably ignore my comments in PlayerService
since it will be quite different after the Android Auto PR anyway.
* Saves the stream progress, sets recovery. | ||
* Then destroys the player in all UIs and destroys the UIs as well. | ||
*/ | ||
public void saveAndShutdown() { | ||
if (DEBUG) { | ||
Log.d(TAG, "destroy() called"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log.d(TAG, "destroy() called"); | |
Log.d(TAG, "saveAndShutdown() called"); |
@@ -1970,6 +1976,9 @@ public void setFragmentListener(final PlayerServiceEventListener listener) { | |||
triggerProgressUpdate(); | |||
} | |||
|
|||
/** Remove the listener, if it was set. | |||
* @param listener listener to remove | |||
* */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you write Javadocs this way? In my Android Studio when I type /**
I already get the correctly formatted Javadoc. It's not a big issue, but it's strange you are deviating from the style used throughout the project, especially if it's also the standard style in Android Studio
Log.d( | ||
TAG, | ||
( | ||
"onStartCommand() called with: intent = [" + intent + | ||
"], flags = [" + flags + "], startId = [" + startId + "]" | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log.d( | |
TAG, | |
( | |
"onStartCommand() called with: intent = [" + intent + | |
"], flags = [" + flags + "], startId = [" + startId + "]" | |
) | |
) | |
Log.d(TAG, "onStartCommand() called with: intent = [$intent], flags = [$flags], startId = [$startId]") |
If the service is already started in foreground, requesting it to be started shouldn't | ||
do anything | ||
*/ | ||
player.UIs().get<NotificationPlayerUi>(NotificationPlayerUi::class.java) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
player.UIs().get<NotificationPlayerUi>(NotificationPlayerUi::class.java) | |
player.UIs().get(NotificationPlayerUi::class.java) |
} | ||
|
||
player.handleIntent(intent) | ||
player.UIs().get<MediaSessionPlayerUi>(MediaSessionPlayerUi::class.java) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
player.UIs().get<MediaSessionPlayerUi>(MediaSessionPlayerUi::class.java) | |
player.UIs().get(MediaSessionPlayerUi::class.java) |
import java.util.Optional | ||
|
||
class PlayerUiList(vararg initialPlayerUis: PlayerUi) { | ||
var playerUis = GuardedByMutex(mutableListOf<PlayerUi>()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var playerUis = GuardedByMutex(mutableListOf<PlayerUi>()) | |
private val playerUis = GuardedByMutex(mutableListOf<PlayerUi>()) |
@@ -761,7 +762,7 @@ public boolean isFullscreen() { | |||
} | |||
|
|||
/** | |||
* Update the play/pause button ({@link R.id.playPauseButton}) to reflect the action | |||
* Update the play/pause button (`R.id.playPauseButton`) to reflect the action |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Update the play/pause button (`R.id.playPauseButton`) to reflect the action | |
* Update the play/pause button ({@code R.id.playPauseButton}) to reflect the action |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few minor comments to look into
@@ -244,7 +244,7 @@ public void onServiceConnected(final PlayerService connectedPlayerService, | |||
// It will do nothing if the player is not in fullscreen mode | |||
hideSystemUiIfNeeded(); | |||
|
|||
final Optional<MainPlayerUi> playerUi = player.UIs().get(MainPlayerUi.class); | |||
final Optional<MainPlayerUi> playerUi = player.UIs().getOpt(MainPlayerUi.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest the following rather than creating a deprecated getOpt
function
final Optional<MainPlayerUi> playerUi = player.UIs().getOpt(MainPlayerUi.class); | |
@Nullable final MainPlayerUi playerUi = player.UIs().get(MainPlayerUi.class); |
* destroyed and removed | ||
* @param T the class type parameter </T> | ||
* */ | ||
fun <T : PlayerUi> destroyAllOfType(playerUiType: Class<T?>? = null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this type be Class<T>?
instead of Class<T?>?
import android.os.Binder | ||
import android.os.IBinder | ||
import android.util.Log | ||
import org.schabi.newpipe.player.PlayerService.LocalBinder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to import.
* Allows us this [PlayerService] over the Service boundary | ||
* back to our [org.schabi.newpipe.player.helper.PlayerHolder]. | ||
*/ | ||
class LocalBinder internal constructor(playerService: PlayerService?) : Binder() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class LocalBinder internal constructor(playerService: PlayerService?) : Binder() { | |
class LocalBinder internal constructor(playerService: PlayerService) : Binder() { |
@@ -947,6 +948,7 @@ public void onShuffleClicked() { | |||
player.toggleShuffleModeEnabled(); | |||
} | |||
|
|||
@SuppressLint("PrivateResource") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shold probably stop relying on the exoplayer's private resources.
Can you add a TODO here to replace the exo_controls_repeat_all
, exo_controls_repeat_one
and exo_controls_repeat_off
drawables.
What is it?
Description of the changes in your PR
First few commits are from #11829 (merge first & rebase)
This partially conflicts with #9592
APK testing
The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR. You can find more info and a video demonstration on this wiki page.
Due diligence