Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1721f59 authored by Sal Savage's avatar Sal Savage
Browse files

Signal "Connecting" state when receiving audio focus

Problem: The main AAOS Media Center app relies on CarMediaService, who
does not listen to the media framework media key event session changed
callback to understand which application on the system the media
framework would forward key events to. Instead, they have their own set
of criteria for determining which application is the currently playing
application that should be shown in their UI and have key events routed
to it. Key to their method is the presence of an "active" playback
state, which can sometimes take a long time for our service to reflect
due to the remote device needing to establish playback first. As well,
sometimes devices don't establish playback at all due to bugs on their
side! This causes Bluetooth not to show up at the playing app in Media
Center, which also keeps the user from being able to use controller
side media controls to fix the error state.

Solution: Briefly indicate we're in the "connecting" state when we gain
audio focus. This state is considered "active" by the Media Center's set
of conditions and causes us to be shown immediately, placing Media
Center's UI in sync with the media framework's view of the world.

Flag: 350510879
Bug: 346831665
Bug: 310001181
Test: atest BluetoothMediaBrowserServiceTest
Change-Id: If113db4bb3fa780d3c35c9fbe8499d0076d0a143
parent aa8f4301
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -503,6 +503,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                case AUDIO_FOCUS_STATE_CHANGE:
                    int newState = msg.arg1;
                    debug("Connected: Audio focus changed -> " + newState);
                    BluetoothMediaBrowserService.onAudioFocusStateChanged(newState);
                    switch (newState) {
                        case AudioManager.AUDIOFOCUS_GAIN:
                            // Begin playing audio again if we paused the remote
+61 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.MediaMetadataCompat;
@@ -33,6 +34,7 @@ import androidx.media.MediaBrowserServiceCompat;

import com.android.bluetooth.BluetoothPrefs;
import com.android.bluetooth.R;
import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

@@ -399,6 +401,65 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        service.mSession.setPlaybackState(state);
    }

    /**
     * Notify this MediaBrowserService of changes to audio focus state
     *
     * <p>Temporarily set state to "Connecting" to better interoperate with media center
     * applications.
     *
     * <p>The "Connecting" state is considered an "active" playback state, which will cause clients
     * that don't listen to the media framework's callback for media key events (whoever most
     * recently requested focus + had playback) to think we're the application who most recently
     * updated to an "active" playback state, which in turn will have them show us as the active app
     * in the UI while we wait on the remote device to accept our playback command.
     */
    static synchronized void onAudioFocusStateChanged(int state) {
        if (!Flags.signalConnectingOnFocusGain()) {
            Log.w(TAG, "Feature 'signal_connecting_on_focus_gain' not enabled. Skip");
            return;
        }

        if (state != AudioManager.AUDIOFOCUS_GAIN) {
            return;
        }

        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "onAudioFocusStateChanged(state=" + state + "): Service not available");
            return;
        }

        Log.i(
                TAG,
                "onAudioFocusStateChanged(state="
                        + state
                        + "): Focus gained, briefly signal connecting");

        MediaSessionCompat session = service.getSession();
        MediaControllerCompat controller = session.getController();
        PlaybackStateCompat currentState =
                controller == null ? null : controller.getPlaybackState();

        PlaybackStateCompat connectingState = null;
        if (currentState != null) {
            connectingState =
                    new PlaybackStateCompat.Builder(currentState)
                            .setState(
                                    PlaybackStateCompat.STATE_CONNECTING,
                                    currentState.getPosition(),
                                    currentState.getPlaybackSpeed())
                            .build();
            service.mSession.setPlaybackState(connectingState);
            service.mSession.setPlaybackState(currentState);
        } else {
            Log.w(
                    TAG,
                    "onAudioFocusStateChanged(state="
                            + state
                            + "): current playback state is null");
        }
    }

    /** Get playback state */
    public static synchronized PlaybackStateCompat getPlaybackState() {
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();