Android Auto app never calls onGetRoot
Asked Answered
G

2

8

I'm developing an audio streaming application for Android and integrating Android Auto. I've been following these two tutorials.

Android Developer Training

PTR Android Blog

Using the Desktop Head Unit, I'm able to select my media app from the media app list, but from there a ProgressBar stays instead of giving way to the "To play something, open the menu at the top left." message seen in the Universal Music Player.

On inspection, it seems that the MediaBrowserServiceCompat's onGetRoot()is never invoked and thus never populating my MediaItemCompat into the Auto app's list.

My manifest contains the following.

<manifest package="com.app.audio"
      xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<application
    android:name="com.app.audio.AudioApp"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">


    <activity
        android:name="com.app.audio.presentation.home.HomeActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    <activity
        android:name="com.app.audio.presentation.weather.WeatherActivity"
        android:screenOrientation="userPortrait"/>

    <activity android:name="com.app.audio.presentation.settings.SettingsActivity"/>

    <activity android:name="com.app.audio.presentation.alarm.AlarmActivity"/>

    <activity android:name="com.app.audio.presentation.sleep.SleepActivity"/>

    <receiver android:name="com.app.audio.audio.AudioIntentReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON"/>
            <action android:name="android.media.AUDIO_BECOMING_NOISY"/>
        </intent-filter>
    </receiver>

    <receiver android:name="com.app.audio.presentation.alarm.AlarmReceiver"></receiver>

    <receiver android:name="com.app.audio.presentation.sleep.SleepReceiver"></receiver>

    <service
        android:name="com.app.audio.data.service.media.MediaService"
        android:exported="true">
        <intent-filter>
            <action android:name="android.media.browse.MediaBrowserService"/>
        </intent-filter>
    </service>

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version"/>

    <meta-data
        android:name="com.google.android.gms.car.application"
        android:resource="@xml/automotive_app_desc"/>

    <meta-data
        android:name="com.google.android.gms.car.notification.SmallIcon"
        android:resource="@drawable/ic_launcher"/>
</application>

My automotive_app_desc.xml is very simple, only declaring Media.

<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
    <uses name="media"/>
</automotiveApp>

My MediaService extends MediaBrowserServiceCompat. In the onCreate() I create and set my MediaSessionCompat.

@Override
public void onCreate() {
    super.onCreate();
    //...
    mediaSession = new MediaSessionCompat(
            this,
            SESSION_TAG,
            mediaIntentReceiver,
            null
    );

    mediaSession.setFlags(
            MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                    MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

    mediaSession.setCallback(new MediaSessionCompat.Callback() {
        @Override
        public void onPlay() {
            super.onPlay();
            play(selectedStream);
        }

        @Override
        public void onPause() {
            super.onPause();
            pause();
        }

        @Override
        public void onStop() {
            super.onStop();
            stop();
        }

        @Override
        public void onSkipToNext() {
            super.onSkipToNext();
            playNextStation();
        }

        @Override
        public void onSkipToPrevious() {
            super.onSkipToPrevious();
            playPreviousStation();
        }
    });

    mediaSession.setActive(true);
    setSessionToken(mediaSession.getSessionToken());
    updatePlaybackState(ACTION_STOP);
}

Finally, the two overridden methods from MediaBrowserServiceCompat, of which neither is ever called.

@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
    return new BrowserRoot(ROOT_ID, null);
}

@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
    List<MediaBrowserCompat.MediaItem> items = getMediaItemsById(parentId);
    if (items != null) {
        result.sendResult(items);
    }
}

As far as I can tell, that's everything required to get an Android Auto started, yet when I open the app on my desktop head unit, there is only a ProgressBar greeting me, and when I open the off-screen nav drawer, there's another one. I haven't heard of that state in any material I've read. Is there something I missed?

Glyco answered 26/7, 2016 at 23:7 Comment(0)
G
21

Ultimately, the issue didn't have anything to do with what I described. The aforementioned MediaService also does other tasks that require a custom Binder. This custom Binder didn't call the onGetRoot() needed for the Head Unit. As a solution, I check the Intent action and return super.onBind() when it's from the MediaBrowserServiceCompat.

@Override
public IBinder onBind(Intent intent) {
    if (SERVICE_INTERFACE.equals(intent.getAction())) {
        return super.onBind(intent);
    }
    return new MediaBinder();
}

The SERVICE_INTERFACE is a constant in MediaBrowserServiceCompat.

Glyco answered 28/7, 2016 at 21:1 Comment(2)
Thanks so much for posting this solution. I've been debugging this for hours.Godly
Yes, thank you! Just to mention it since my initial searches were fruitless, returning my own custom Binder instead of MediaBrowserServiceCompat's also resulted in errors getting logged: "[my.package.name]: oneway function results will be dropped but finished with status UNKNOWN_TRANSACTION and parcel size 0". These went away (and Android Auto started working) after I made the change described here.Bustup
T
0

I'm developing an Android auto but I have some problems in this part of my code, in Onbind method of the service:

public IBinder onBind(Intent arg0) {
    Log.i("TAG", "OnBind");
    // TODO Auto-generated method stub
    if (SERVICE_INTERFACE.equals(arg0.getAction())) {
        Log.i("TAG", "SERVICE_INTERFACE");
        registerReceiver(receiver, filter);
        return super.onBind(arg0);
    } else { 
        Log.i("Musica Service", "musicBind");
        return musicBind;}
}

I have other activities bound with my service through a musicBind IBinder, but on the other hand I have set all things to connect my app in Android auto interface but after close my app after disconnect the device from the android auto I can't stop my mediabrowserservice compat. I think it's due to this SERVICE_INTERFACE keeps binded the service. How can I stop or destroy this from the same servicemediabrowserservicecompat?

Tuscany answered 31/1, 2017 at 1:14 Comment(1)
Welcome to Stack Overflow. This is not an answer to the question, it's a comment/new question. Once you have sufficient reputation (50) you will be able to comment on any post. In the meantime you can gain reputation asking your own questions or providing answers on subjects.Eros

© 2022 - 2024 — McMap. All rights reserved.