Skip to content
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

notifyChildrenChanged does not update Android Auto list of mediaitems #644

Closed
yuroyami opened this issue Sep 12, 2023 · 10 comments
Closed
Assignees
Labels

Comments

@yuroyami
Copy link

yuroyami commented Sep 12, 2023

I am not sure to what extent the library handles Android Auto aside from the common playback controls and commands. However, I've been having some issues making my media app integrate with Android Auto ecosystem :

I use the following code to notify any controllers that my items have undergone some change :

//this is inside my implementation of MediaLibraryService
mediaSession?.notifyChildrenChanged(nodePLAYLIST, playlist.size, null) //playlist is a List<MediaItem>
//or
mediaSession?.notifyChildrenChanged(nodeTRACKLIST, tracklist.size, null)  //tracklist is a List<MediaItem>

I have a root node which is my library root (the one I return under onGetLibraryRoot). It has two children (which Android Auto chooses to show as tabs because they're browsable and not playable): A playlist node and a tracklist node, both which have their own list of items under them.

The media hierarchy is like this:

  • nodeROOT
    -- nodePLAYLIST
    -- nodeTRACKLIST

However, the notifyChildrenChanged works fine on my phone, I can receive the callback on my activity just fine. But on Android Auto, it will not update the UI until I leave the tab and go back to it again. This is annoying because the user performs a LOT of library modifications throughout the lifetime of the app, it is essential the Android auto refreshes the list of items that are visible to the user as soon as the callback is executed.

Do I need to do something else ? Or am I just doing it wrong ?

@oceanjules
Copy link
Contributor

Hi @yuroyami,

Could you check out the following issue thread to see if it can help you - #561?

@yuroyami
Copy link
Author

yuroyami commented Sep 12, 2023

@oceanjules Thank you for the quick reply,

I am aware of the requirement of having the browser subscribed in order for it to receive change callbacks. I've implemented the latter on my activity and it works just fine. However, I don't see how it's possible to make the Android Auto browser subscribe as well ? I've only got ControllerInfoto work with with not so much of an actual MediaBrowser.

EDIT: The issue is confirmed to be more grave on another car head unit where the list of items does not get updated at all until the app is completely disconnected and connected.

@marcbaechinger
Copy link
Contributor

Thanks for your report.

Can you repro this when testing with the Media3 branch of UAMP?

I'm also curious how you test. It sounds like you are testing with an actual headunit of a car. Is this correct? If so is this Android Auto or Automotive and can you repro this with an emulator as well?

Sorry, for asking these questions. Just want to make sure to look at the right thing when I start testing this.

@yuroyami
Copy link
Author

yuroyami commented Sep 16, 2023

@marcbaechinger I appreciate the reply.

I loaded the media3 branch of UAMP but figured out that it does not have any occurrence of any kind related to notifyChildrenChanged, it loads the entire list of items at the very launch and fulfils the future as soon as the list is parsed. That said, the playlist that is visible on the car screen does not require any further refreshing. In other words, it does not edit the playlist later on or allows removal/addition of items because it only does it once at the very beginning then no more, which limits me from testing it because if I implemented the notifyChildrenChanged logic myself, I'd do it the same way I did in my own app.

Regarding the testing environment; my apologies for the ambiguous description. To be more clear, I am not developing the app for Android Automotive OS, but rather just Android with Android Auto support. I tested with:

  • The DHU emulator: The result was that the items for each tab do not get refreshed upon calling notifyChildrenChanged. The only way to refresh them was to leave the tab and to click on it again. This probably causes Android Auto to call onGetChildren again. I confirmed that the notifyChildrenChanged is not what's responsible for repopulating the playlist after revisiting the tab, since I completely commented-out its occurrences from the code, after which, there was no difference, the playlist was getting updated after leaving the tab and revisiting it again. This confirms my aforementioned theory that Android Auto's browser is indeed calling onGetChildren again.

  • An actual physical car headunit: which doesn't belong to me, so I cannot offer much info about this. In contrast to the emulator, the list of items does not get updated at all, even after leaving the tab and revisiting it again. The only solution was to disconnect the phone from Android Auto completely and reconnect it again, or restarting the car headunit. This difference in behavior seems to be caused by an underlying browser behavior difference and not the media3 library, so I believe it isn't relevant in this case.

What matters is that the method notifyChildrenChanged does not seem to go through at all except if I explicitly subscribe to it from my activity for example, but that requires me to have an actual instance of MediaBrowser. Yet there is no way to make Android Auto's controller/browser subscribe because I have no reference to it in my service or anywhere else, and therefore I cannot make it subscribe.

copybara-service bot pushed a commit that referenced this issue Sep 27, 2023
Issue: #561
Issue: #644
Issue: #645
PiperOrigin-RevId: 568948230
microkatz pushed a commit to hugohlln/media that referenced this issue Sep 29, 2023
@yuroyami
Copy link
Author

@marcbaechinger With the use of version 1.2.0'sgetSubscribedControllers(parentId) method, I found out that the Android Auto is actually subscribed to every parentId I have whenever needed. For example, switching from a tab to another will unsubscribe the previous tab MediaItem and will subscribe to the new tab MediaItem. This seems to be strictly a notifyChildrenChanged issue. Seems like changes are not propagated to Auto controller even though it is subscribed.

@marcbaechinger
Copy link
Contributor

Can you expand a bit on repro steps and what the expected behaviour and the observed behaviour is?

@yuroyami
Copy link
Author

yuroyami commented Nov 30, 2023

@marcbaechinger I created a very simple demo project to reproduce the faulty behavior on Android Auto, and shared it as a GitHub repo here: Media3AutoDemo. To give you a quick walkthrough on the project components:

We have a DemoService (MediaLibraryService) which is the pivotal part of the project. The MediaItem hierarchy is dead simple: a root node, then under it there is a child node which is the actual playlist (browsable), which hosts the actual media items visible on the app via DemoActivity. The DemoActivity uses Compose to show the items as a list, where each item can be played or deleted via custom commands.

The DemoService will get the (random from internet) media items from DemoPlaylist. Then it will play or delete the items based on the received custom commands from the activity. Upon deleting items, the service will call notifyChildrenChanged where the activity responds to it and fetches children to update the UI, pretty OK so far.

Playing items works great for both the app and Android Auto, however, deleting items only works for the app, it seems that Android Auto does NOT know that the items are getting deleted even after calling notifyChildrenChanged. As I mentioned early on this thread, the Android Auto controller is actually subscribed when I use getSubscribedControllers, but it doesn't seem to be updating the UI on the car's Head Unit at all (I used the desktop emulator one for this demo).

Expected behavior: Once an item is deleted, the service calls notifyChildrenChanged, which informs the activity that an item is deleted and therefore remove it from the UI list. Android Auto should also remove the item from the UI on the head unit.

Observed behavior:: notifyChildrenChanged only informs the subscribed activity (DemoActivity) but the car's head unit will not update the UI even though it is subscribed, resulting in a static unmodifiable list, probably because it's not calling onGetChildren.

Hope this helps :)

@marcbaechinger
Copy link
Contributor

mediaSession?.notifyChildrenChanged(nodeTRACKLIST, tracklist.size, null)

I think there is a bug in the Media3 method notifyChildrenChanged(String parentId, int itemCount, @Nullable LibraryParams params) that fails notifying connected legacy controllers.

We will provide a fix for this.

--

If you want to fix this earlier on your end, then you can use the overloaded method notifyChildrenChanged(Controller Info controllerInfo, String parentId, int itemCount, @Nullable LibraryParams params) instead.

Iterate over mediaSession.getConnectedControllers() and then call the overloaded method with the 'controllerInfo' for each connected controller:

mediaSession.connectedControllers.forEach {
    (session as MediaLibrarySession).notifyChildrenChanged(it, parentId, childrenCount, /* params= */ null)
}

@yuroyami
Copy link
Author

Tested the workaround and it appears to be working perfectly. Thank you so much :)

copybara-service bot pushed a commit that referenced this issue Dec 14, 2023
When broadcasting a notifyChildrenChanged event, the task for legacy
controllers was sent to the broadcasting callback. This would
technically work, but because the subscription list is maintained
with specific controllers, the broadcast controller isn't subscribed
and hence the call wasn't executed.

This change calls the overloaded method for a specific controller
for each connected controller. Making sure (only) subscribed
controllers are notified.

Issue: #644
PiperOrigin-RevId: 590904037
@marcbaechinger
Copy link
Contributor

We synced a fix for this to the dev branch (see above). I'm closing this issue. Thanks again for reporting!

microkatz pushed a commit that referenced this issue Jan 11, 2024
When broadcasting a notifyChildrenChanged event, the task for legacy
controllers was sent to the broadcasting callback. This would
technically work, but because the subscription list is maintained
with specific controllers, the broadcast controller isn't subscribed
and hence the call wasn't executed.

This change calls the overloaded method for a specific controller
for each connected controller. Making sure (only) subscribed
controllers are notified.

Issue: #644
PiperOrigin-RevId: 590904037
(cherry picked from commit 4974f96)
@androidx androidx locked and limited conversation to collaborators Feb 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants