Skip to content

Conversation

Stypox
Copy link
Member

@Stypox Stypox commented Feb 16, 2025

What is it?

  • Bugfix (user facing)
  • Feature (user facing)
  • Codebase improvement (dev facing)
  • Meta improvement to the project (dev facing)

Description of the changes in your PR

Exposes media controls and playback status on Android Auto, as well as a basic browsing interface, showing playlists, history, and supporting basic searches.

This PR supersedes #9592, and the important differences lie in these commits: b764ad3, 6eb2920, dd29b73. Moreover, the MediaBrowserConnector was split into two mostly independent classes (MediaBrowserImpl and MediaBrowserPlaybackPreparer) which also have less confusing names. You can tell my new commits apart from what was already there in #9592 by looking at the commit Co-Authors.

I tested with desktop-head-unit (also used for the screenshots below) and there do not seem to be player issues anymore (in particular, the player closes correctly in all ways it can be closed and never leaved behind an empty notification). I also tested a few other player use-cases and the behavior seems to be the same as current NewPipe.

Issues, bugs, and missing features

  • When closing the player from its mini view, playback continues. It should be stopped instead. Fixed with the player changes
  • When starting playback on Android Auto then opening the app, the mini player doesn't appear and isn't synchronized with the current state when "opened" (opening the details page of a content with autoplay disabled, pressing the play button plays the content on the details page) Fixed in 6558794
  • Remote playlists are limited to their first page - This is unsolvable since Android Auto does not support pagination, but if you start playing a playlist (e.g. by clicking on a specific item) then the next pages will load in the queue.
  • when starting the app then connecting to an Desktop Head Unit. The DHU was blocked on the loading step happening before showing playback controls normally, the app was playing the audio in the meantime then the app crashed. Fixed with the player changes
  • Integration with voice search - voice search from within the app works, but search from the google assistant (e.g., "play on NewPipe") only supports applications from the Google Play Store.

Future enhancements

  • Show progress bars for played items and for the one currently playing, if applicable (see https://developer.android.com/training/cars/media?hl=en#browse-progress-bar for the latter).
  • Add more content to Android Auto.
  • Items (playlists and streams) are not updated in Android Auto when they are in the app.
  • Non square thumbnails seems to forced to the square format in the miniplayer commands if you enable the setting of the Desktop Head Unit.

Before/After Screenshots/Screen Record

Player Queue
Home (bookmarked playlists) Home (history)
A local playlist Search screen

Fixes the following issue(s)

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

Read the comments in the lines changed to understand more
@github-actions github-actions bot added the size/giant PRs with more than 750 changed lines label Feb 16, 2025
@Stypox Stypox mentioned this pull request Feb 16, 2025
5 tasks
@ShareASmile ShareASmile added feature request Issue is related to a feature in the app device/software specific Issues that only happen on some devices or with some specific hardware/software labels Feb 16, 2025
@haggaie
Copy link
Contributor

haggaie commented Feb 16, 2025

Thanks @Stypox for this rewrite. I had a look at the code, and it looks good to me. I also tried testing it (so far only with the desktop head unit) and it seems to work well. I saw that it fixed the issues you originally raised e.g., with closing the player on the phone after starting it on android auto. At one attempt restarting playback didn't work, but in all other attempts it worked fine.

Another thing I noticed (though I'm not sure if this wasn't happening before) is that if the player is paused, and I select a different item in Android Auto, in some cases it plays a couple of seconds from the old song before switching to the new one. Could this be related to the fix of onPrepare?

Stypox and others added 14 commits February 16, 2025 21:36
This changes significantly how the MediaSessionCompat and MediaSessionConnector objects are used:
- now they are tied to the service and not to the player, and so they might be reused with multiple players (which should be allowed)
- now they can exist even if there is no player (which is fundamental to be able to answer media browser queries)
This class will receive the media URLs generated by [MediaBrowserImpl] and will start playback of the corresponding streams or playlists.

Co-authored-by: Haggai Eran <[email protected]>
Co-authored-by: Profpatsch <[email protected]>
This class implements the media browser service interface as a standalone class for clearer separation of concerns (otherwise everything would need to go in PlayerService, since PlayerService overrides MediaBrowserServiceCompat)

Co-authored-by: Haggai Eran <[email protected]>
Co-authored-by: Profpatsch <[email protected]>
Now the media browser queries are replied to by MediaBrowserImpl

Co-authored-by: Haggai Eran <[email protected]>
If a playbackPreparer is set, then instead of calling `player.prepare()`, the MediaSessionConnector will call `playbackPreparer.onPrepare(true)` instead, as seen below.
This commit makes it so that playbackPreparer.onPrepare(true) restores the original behavior of just calling player.prepare().

From MediaSessionConnector -> MediaSessionCompat.Callback implementation:
```java
    @OverRide
    public void onPlay() {
      if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_PLAY)) {
        if (player.getPlaybackState() == Player.STATE_IDLE) {
          if (playbackPreparer != null) {
            playbackPreparer.onPrepare(/* playWhenReady= */ true);
          } else {
            player.prepare();
          }
        } else if (player.getPlaybackState() == Player.STATE_ENDED) {
          seekTo(player, player.getCurrentMediaItemIndex(), C.TIME_UNSET);
        }
        Assertions.checkNotNull(player).play();
      }
    }
```
This commit is a consequence of the commit "Drop some assumptions on how PlayerService is started and reused". Since the assumptions on how the PlayerService is started and reused have changed, we also need to adapt the way it is stopped. This means allowing the service to remain alive even after the player is destroyed, in case the system is still accessing PlayerService e.g. through the media browser interface. The foreground service needs to be stopped and the notification removed in any case.
Non-item errors, i.e. critical parsing errors of the page, are still handled properly.
@Stypox
Copy link
Member Author

Stypox commented Feb 16, 2025

Another thing I noticed (though I'm not sure if this wasn't happening before) is that if the player is paused, and I select a different item in Android Auto, in some cases it plays a couple of seconds from the old song before switching to the new one. Could this be related to the fix of onPrepare?

I can't reproduce, but I have noticed this too in the current version of NewPipe (before this PR). I doubt it is caused by onPrepare, since I just rewired onPrepare() to call exoPlayer.prepare(), as would have happened if no PlaybackPreparer was used.

@notbasa
Copy link

notbasa commented Feb 17, 2025

I can confirm that this works on actual HW, at least on Peugeot e2008. Really looking forward to the release.

One improvment suggestion: When playing songs from the history list, the player displays the Prev and next arrows on the UI but they don't cause any action when pressed. Ideally they should change the song to next/prev on the history list or they should be grayed out if this is not feasible for some reason.

@haggaie
Copy link
Contributor

haggaie commented Feb 18, 2025

Hi, I noticed a crash this morning that might be related to the changes in the service lifecycle. If I understand correctly, the video fragment's onDestroy triggers player service shutdown, which then attempts accessing the same fragment:

Exception

  • User Action: ui error
  • Request: ACRA report
  • Content Country: IL
  • Content Language: en-IL
  • App Language: en_IL_#u-fw-sun-mu-celsius
  • Service: none
  • Timestamp: 2025-02-18T06:55:03.431+02:00
  • Package: org.schabi.newpipe.debug.androidauto
  • Service: none
  • Version: 0.27.6
  • OS: Linux Android 15 - 35
Crash log

java.lang.RuntimeException: Unable to destroy activity {org.schabi.newpipe.debug.androidauto/org.schabi.newpipe.MainActivity}: java.lang.NullPointerException: Attempt to read from field 'android.widget.ImageButton org.schabi.newpipe.databinding.FragmentVideoDetailBinding.overlayPlayPauseButton' on a null object reference in method 'void org.schabi.newpipe.fragments.detail.VideoDetailFragment.setOverlayPlayPauseImage(boolean)'
	at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:6044)
	at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:6076)
	at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:52)
	at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:63)
	at android.app.servertransaction.TransactionExecutor.executeLifecycleItem(TransactionExecutor.java:169)
	at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:101)
	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2719)
	at android.os.Handler.dispatchMessage(Handler.java:109)
	at android.os.Looper.loopOnce(Looper.java:232)
	at android.os.Looper.loop(Looper.java:317)
	at android.app.ActivityThread.main(ActivityThread.java:8787)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:591)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:871)
Caused by: java.lang.NullPointerException: Attempt to read from field 'android.widget.ImageButton org.schabi.newpipe.databinding.FragmentVideoDetailBinding.overlayPlayPauseButton' on a null object reference in method 'void org.schabi.newpipe.fragments.detail.VideoDetailFragment.setOverlayPlayPauseImage(boolean)'
	at org.schabi.newpipe.fragments.detail.VideoDetailFragment.setOverlayPlayPauseImage(VideoDetailFragment.java:2414)
	at org.schabi.newpipe.fragments.detail.VideoDetailFragment.onServiceStopped(VideoDetailFragment.java:1851)
	at org.schabi.newpipe.player.helper.PlayerHolder$1.onServiceStopped(PlayerHolder.java:312)
	at org.schabi.newpipe.player.Player.stopActivityBinding(Player.java:2038)
	at org.schabi.newpipe.player.Player.destroy(Player.java:608)
	at org.schabi.newpipe.player.PlayerService.cleanup(PlayerService.java:207)
	at org.schabi.newpipe.player.PlayerService.destroyPlayerAndStopService(PlayerService.java:231)
	at org.schabi.newpipe.player.helper.PlayerHolder.stopService(PlayerHolder.java:145)
	at org.schabi.newpipe.fragments.detail.VideoDetailFragment.onDestroy(VideoDetailFragment.java:396)
	at androidx.fragment.app.Fragment.performDestroy(Fragment.java:3376)
	at androidx.fragment.app.FragmentStateManager.destroy(FragmentStateManager.java:812)
	at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:346)
	at androidx.fragment.app.SpecialEffectsController$FragmentStateManagerOperation.complete(SpecialEffectsController.kt:664)
	at androidx.fragment.app.SpecialEffectsController$Operation.cancel(SpecialEffectsController.kt:507)
	at androidx.fragment.app.SpecialEffectsController.forceCompleteAllOperations(SpecialEffectsController.kt:293)
	at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3037)
	at androidx.fragment.app.FragmentManager.dispatchDestroy(FragmentManager.java:2988)
	at androidx.fragment.app.FragmentController.dispatchDestroy(FragmentController.java:346)
	at androidx.fragment.app.FragmentActivity.onDestroy(FragmentActivity.java:258)
	at androidx.appcompat.app.AppCompatActivity.onDestroy(AppCompatActivity.java:283)
	at org.schabi.newpipe.MainActivity.onDestroy(MainActivity.java:460)
	at android.app.Activity.performDestroy(Activity.java:9310)
	at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1563)
	at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:6031)
	... 14 more


Note that this is from the first version of this PR, so maybe it was already fixed?

@notbasa
Copy link

notbasa commented Feb 18, 2025

Got this while testing new android auto implementation, but I have no idea if this is in any way related to the AA code.
User perceived effect is just that the playing seems to stop, and user needs to repress the play button for it to continue.

Exception

  • User Action: play stream
  • Request: Player error[type=ERROR_CODE_IO_BAD_HTTP_STATUS] occurred while playing https://www.youtube.com/watch?v=13m5-0EOwIM
  • Content Country: US
  • Content Language: en-US
  • App Language: en_US
  • Service: YouTube
  • Timestamp: 2025-02-17T20:36:13.019+02:00
  • Package: org.schabi.newpipe.debug.androidauto
  • Service: YouTube
  • Version: 0.27.6
  • OS: Linux Nokia/TheThing_00EEA/TTG_sprout:14/UKQ1.231003.002/00WW_4_170:user/release-keys 14 - 34
Crash log
com.google.android.exoplayer2.ExoPlaybackException: Source error	at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:644)	at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:616)	at android.os.Handler.dispatchMessage(Handler.java:102)	at android.os.Looper.loopOnce(Looper.java:205)	at android.os.Looper.loop(Looper.java:294)	at android.os.HandlerThread.run(HandlerThread.java:67)Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 403	at org.schabi.newpipe.player.datasource.YoutubeHttpDataSource.open(YoutubeHttpDataSource.java:425)	at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:263)	at com.google.android.exoplayer2.upstream.TeeDataSource.open(TeeDataSource.java:52)	at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:796)	at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:609)	at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:84)	at com.google.android.exoplayer2.source.chunk.ContainerMediaChunk.load(ContainerMediaChunk.java:124)	at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)	at java.lang.Thread.run(Thread.java:1012)

Fixes mini-player not appearing on app start if the player service is already playing something.

The PlayerService (and the player) may be started from an external intent that does not involve the MainActivity (e.g. RouterActivity or Android Auto's media browser interface).
This PR tries to bind to the PlayerService as soon as the MainActivity starts, but only does so in a passive way, i.e. if the service is not already running it is not started.
Once the connection between PlayerHolder and PlayerService is setup, the ACTION_PLAYER_STARTED broadcast is sent to MainActivity so that it can setup the bottom mini-player.
Another important thing this commit does is to check whether the player is open before actually adding the mini-player view, since the PlayerService could be bound even without a running player (e.g. Android Auto's media browser is being used). This is a consequence of commit "Drop some assumptions on how PlayerService is started and reused".
This bug started appearing because the way to close the player is now unified in PlayerHolder.stopService(), which causes the player to reach back to the video detail fragment with a notification of the shutdown (i.e. onServiceStopped() is called). This is fixed by adding a nullability check on the binding.
This is, again, a consequence of the commit "Drop some assumptions on how PlayerService is started and reused".
This commit notified VideoDetailFragment of player starting and stopping independently of the player.
Read the comments in the code changes for more information.
@Stypox
Copy link
Member Author

Stypox commented Feb 18, 2025

the player displays the Prev and next arrows on the UI but they don't cause any action when pressed. Ideally they should change the song to next/prev on the history list or they should be grayed out if this is not feasible for some reason.

This is not under our control, as starting from Android 13 (i.e. Tiramisu) the previous, next and play/pause actions are no longer customizable and are set by the system. Do other apps behave differently when there is only one song in queue?

Hi, I noticed a crash this morning that might be related to the changes in the service lifecycle

Thanks, fixed in 126f4b0

Got this while testing new android auto implementation, but I have no idea if this is in any way related to the AA code.

This is unrelated, see #11803


I also pushed commits a7a7dc5 and 6558794 which update the code after the assumptions about how the player service is stopped and reused have changed (i.e. the service can now outlive the player). This fixes some rare crashes or unexpected behaviors. I tested this thoroughly and it miraculously seems to work without issues. I also added comments on every function I touched, so read those to understand the changes.

  • When starting playback on Android Auto then opening the app, the mini player doesn't appear and isn't synchronized with the current state when "opened" (opening the details page of a content with autoplay disabled, pressing the play button plays the content on the details page)

Fixed in 6558794. Note that this behavior was buggy before too, e.g. when the player was started from RouterActivity (i.e. the share menu) while MainActivity was not open. I could not find any open issue on our repo though.

@haggaie
Copy link
Contributor

haggaie commented Feb 21, 2025

Hi,

I tested the previous version (73f2cfa I guess) on my car as well, and it seemed to work well. I've also tested the new version (a7a7dc5) on the desktop-head-unit, and it also works great.

I finally understood the comment about the square desktop-head-unit aspect ratio, and I was able to reproduce it, but I noticed that other apps also exhibit the same behavior. Could it be a problem in how Android Auto supports this aspect ratio?

@frederikstonge
Copy link

Wow, much needed feature! Thank you for your contribution! :)

@oleg-d
Copy link

oleg-d commented Mar 12, 2025

I installed the apk from the CI but my android auto is not showing New Pipe in the launcher. Did you guys do anything apart from install the apk to get it running? This is on a Pixel 9.

Solved it: had to enable unknown sources in android auto developer settings

@ready2code31
Copy link

but in my car, android auto doesnt display newpipe app on android auto display 1 time of 2
i have to unplug and replug my phone to android auto

That's strange, it's up to the Android system to decide when to query apps so I don't know if we can do anything about it.

I think i found a solution to this
you have to install the app-debug.apk using adb to set app provider to com.android.vending (play store)
https://medium.com/@pixplicity/setting-the-install-vendor-of-an-app-7d7deacb01ee
and then each time, you plug your phone to the car
the app display on android auto well
thx devs for this pull, it works great

@Stypox
Copy link
Member Author

Stypox commented Mar 21, 2025

I'm merging this, so it ends up in nightly APKs and gets tested by more people. Thank you again @haggaie!

@Stypox Stypox merged commit 196c277 into dev Mar 21, 2025
4 of 5 checks passed
@TobiGr TobiGr deleted the android-auto branch March 21, 2025 10:53
@harirah1
Copy link

harirah1 commented May 8, 2025

I'm merging this, so it ends up in nightly APKs and gets tested by more people. Thank you again @haggaie!

Hi excuse me, where can I find the new open request (conversation) / the new APK ? Thank you

@Stypox
Copy link
Member Author

Stypox commented May 8, 2025

@harirah1 https://github.com/TeamNewPipe/NewPipe-nightly/releases

@abesqaured
Copy link

Hello, I am unable to start NewPipe on Android auto.

@Stypox
Copy link
Member Author

Stypox commented Jun 20, 2025

@abesqaured which version are you on? This PR is still not in any official version but only in nightlies

@sanchiro82
Copy link

Thank you so much for your contribution, it's incredible. It would be great to include your subscription timeline.

@Stypox
Copy link
Member Author

Stypox commented Jul 16, 2025

Could someone test #12412 on a real car, just to make sure the changes did not break anything? Can someone also comment on TeamNewPipe/website#399, explaning which steps (if any) they had to take to make NewPipe work on Android Auto? E.g. pinging @haggaie @abesqaured @sanchiro82 @harirah1 @asentes2 @notbasa @ready2code31 @oleg-d @frederikstonge @Occhioverde @andry23jsv (sorry for all the pings but we would be really thankful for quick feedback, as we plan to release a new NewPipe version within a week or so)

@Stypox Stypox mentioned this pull request Jul 17, 2025
11 tasks
@haggaie
Copy link
Contributor

haggaie commented Jul 17, 2025

Hi, I tested NewPipe nightly 0.27.7-1045-202507150127, is that okay? The Android Auto features worked well in my car, except for the History tab which didn't load, though I'm not sure if that was related to this change.

@Stypox
Copy link
Member Author

Stypox commented Jul 17, 2025

Yes, nightly 0.27.7-1045-202507150127 is ok, thanks! About the History tab, 🤷

@ready2code31
Copy link

ready2code31 commented Sep 30, 2025 via email

whistlingwoods pushed a commit to whistlingwoods/FoxPipe that referenced this pull request Oct 4, 2025
Add support for Android Auto *(season 2)*
whistlingwoods pushed a commit to whistlingwoods/FoxPipe that referenced this pull request Oct 6, 2025
Add support for Android Auto *(season 2)*
whistlingwoods added a commit to whistlingwoods/FoxPipe that referenced this pull request Oct 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Android Auto Issue is related to Android Auto device/software specific Issues that only happen on some devices or with some specific hardware/software feature request Issue is related to a feature in the app size/giant PRs with more than 750 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Compatibility with Android Auto