Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Auto app never calls onGetRoot

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?

like image 242
Fargonaut Avatar asked Jul 26 '16 23:07

Fargonaut


1 Answers

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.

like image 192
Fargonaut Avatar answered Oct 27 '22 16:10

Fargonaut