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

Commit 7dafa9ac authored by Sungsoo Lim's avatar Sungsoo Lim
Browse files

Use broadcast receiver to update BT A2DP status

Audio routes observer in AudioService could have several seconds
delay. To mitigate the issue because of the delay, this CL uses
a BroadcastReceiver to get the Bluetooth device connection events.

Bug: 70175199
Test: manually and passed Media CTS
Change-Id: Ic1e9db1b8d5759070962011d7f2fc4f940ce8497
parent a629e4c3
Loading
Loading
Loading
Loading
+37 −29
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import com.android.server.Watchdog;

import android.annotation.NonNull;
import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -96,21 +99,23 @@ public final class MediaRouterService extends IMediaRouterService.Stub
    private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
            new ArrayMap<IBinder, ClientRecord>();
    private int mCurrentUserId = -1;
    private boolean mGlobalBluetoothA2dpOn = false;
    private final IAudioService mAudioService;
    private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
    private final Handler mHandler = new Handler();
    private final AudioRoutesInfo mAudioRoutesInfo = new AudioRoutesInfo();
    private final IntArray mActivePlayerMinPriorityQueue = new IntArray();
    private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray();

    private final BroadcastReceiver mReceiver = new MediaRouterServiceBroadcastReceiver();
    BluetoothDevice mBluetoothDevice;
    int mAudioRouteMainType = AudioRoutesInfo.MAIN_SPEAKER;
    boolean mGlobalBluetoothA2dpOn = false;

    public MediaRouterService(Context context) {
        mContext = context;
        Watchdog.getInstance().addMonitor(this);

        mAudioService = IAudioService.Stub.asInterface(
                ServiceManager.getService(Context.AUDIO_SERVICE));

        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
        mAudioPlayerStateMonitor.registerListener(
                new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() {
@@ -170,44 +175,30 @@ public final class MediaRouterService extends IMediaRouterService.Stub
                @Override
                public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
                    synchronized (mLock) {
                        if (newRoutes.mainType != mAudioRoutesInfo.mainType) {
                        if (newRoutes.mainType != mAudioRouteMainType) {
                            if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET
                                    | AudioRoutesInfo.MAIN_HEADPHONES
                                    | AudioRoutesInfo.MAIN_USB)) == 0) {
                                // headset was plugged out.
                                mGlobalBluetoothA2dpOn = newRoutes.bluetoothName != null;
                                mGlobalBluetoothA2dpOn = mBluetoothDevice != null;
                            } else {
                                // headset was plugged in.
                                mGlobalBluetoothA2dpOn = false;
                            }
                            mAudioRoutesInfo.mainType = newRoutes.mainType;
                            mAudioRouteMainType = newRoutes.mainType;
                        }
                        if (!TextUtils.equals(
                                newRoutes.bluetoothName, mAudioRoutesInfo.bluetoothName)) {
                            if (newRoutes.bluetoothName == null) {
                                // BT was disconnected.
                                mGlobalBluetoothA2dpOn = false;
                            } else {
                                // BT was connected or changed.
                                mGlobalBluetoothA2dpOn = true;
                            }
                            mAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
                        }
                        // Although a Bluetooth device is connected before a new audio playback is
                        // started, dispatchAudioRoutChanged() can be called after
                        // onAudioPlayerActiveStateChanged(). That causes restoreBluetoothA2dp()
                        // is called before mGlobalBluetoothA2dpOn is updated.
                        // Calling restoreBluetoothA2dp() here could prevent that.
                        restoreBluetoothA2dp();
                        // The new audio routes info could be delivered with several seconds delay.
                        // In order to avoid such delay, Bluetooth device info will be updated
                        // via MediaRouterServiceBroadcastReceiver.
                    }
                }
            });
        } catch (RemoteException e) {
            Slog.w(TAG, "RemoteException in the audio service.");
        }
        synchronized (mLock) {
            mGlobalBluetoothA2dpOn = (audioRoutes != null && audioRoutes.bluetoothName != null);
        }

        IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
    }

    public void systemRunning() {
@@ -415,14 +406,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub

    void restoreBluetoothA2dp() {
        try {
            boolean btConnected = false;
            boolean a2dpOn = false;
            synchronized (mLock) {
                btConnected = mAudioRoutesInfo.bluetoothName != null;
                a2dpOn = mGlobalBluetoothA2dpOn;
            }
            // We don't need to change a2dp status when bluetooth is not connected.
            if (btConnected) {
            if (mBluetoothDevice != null) {
                Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")");
                mAudioService.setBluetoothA2dpOn(a2dpOn);
            }
@@ -661,6 +650,25 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        return false;
    }

    final class MediaRouterServiceBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                        BluetoothProfile.STATE_DISCONNECTED);
                if (state == BluetoothProfile.STATE_DISCONNECTED) {
                    mGlobalBluetoothA2dpOn = false;
                    mBluetoothDevice = null;
                } else if (state == BluetoothProfile.STATE_CONNECTED) {
                    mGlobalBluetoothA2dpOn = true;
                    mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    // To ensure that BT A2DP is on, call restoreBluetoothA2dp().
                    restoreBluetoothA2dp();
                }
            }
        }
    }

    /**
     * Information about a particular client of the media router.
     * The contents of this object is guarded by mLock.