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

Commit 715b6488 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun
Browse files

MediaRouter: Create BluetoothRouteProvider for each user

The bluetooth service manages the active device for each user
and sent broadcast for each user.

BluetoothRouteProvider was singleton and listened broadcast
from the owner (uid=0) only , which failed to catch correct events when
the foreground user is not the owner.

This CL fixes that by creating BluetoothRouteProvider per user and
listening to the events of each user.

Bug: 162541640
Test: manually open the output switcher and check bluetooth state with switching users
and run cts

Change-Id: Iabab6f7830ce0224b7f73a7c5cfb863aebf5562b
parent 42c87511
Loading
Loading
Loading
Loading
+14 −11
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.AudioSystem;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2Info;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
@@ -55,7 +56,6 @@ class BluetoothRouteProvider {
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);


    private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
    private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
    private static BluetoothRouteProvider sInstance;


    @SuppressWarnings("WeakerAccess") /* synthetic access */
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    // Maps hardware address to BluetoothRouteInfo
    // Maps hardware address to BluetoothRouteInfo
@@ -79,19 +79,21 @@ class BluetoothRouteProvider {
    private final BroadcastReceiver mBroadcastReceiver = new BluetoothBroadcastReceiver();
    private final BroadcastReceiver mBroadcastReceiver = new BluetoothBroadcastReceiver();
    private final BluetoothProfileListener mProfileListener = new BluetoothProfileListener();
    private final BluetoothProfileListener mProfileListener = new BluetoothProfileListener();


    static synchronized BluetoothRouteProvider getInstance(@NonNull Context context,
    /**
     * Create an instance of {@link BluetoothRouteProvider}.
     * It may return {@code null} if Bluetooth is not supported on this hardware platform.
     */
    @Nullable
    static BluetoothRouteProvider createInstance(@NonNull Context context,
            @NonNull BluetoothRoutesUpdatedListener listener) {
            @NonNull BluetoothRoutesUpdatedListener listener) {
        Objects.requireNonNull(context);
        Objects.requireNonNull(context);
        Objects.requireNonNull(listener);
        Objects.requireNonNull(listener);


        if (sInstance == null) {
        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        if (btAdapter == null) {
        if (btAdapter == null) {
            return null;
            return null;
        }
        }
            sInstance = new BluetoothRouteProvider(context, btAdapter, listener);
        return new BluetoothRouteProvider(context, btAdapter, listener);
        }
        return sInstance;
    }
    }


    private BluetoothRouteProvider(Context context, BluetoothAdapter btAdapter,
    private BluetoothRouteProvider(Context context, BluetoothAdapter btAdapter,
@@ -103,7 +105,7 @@ class BluetoothRouteProvider {
        buildBluetoothRoutes();
        buildBluetoothRoutes();
    }
    }


    public void start() {
    public void start(UserHandle user) {
        mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
        mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
        mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
        mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);


@@ -118,7 +120,8 @@ class BluetoothRouteProvider {
        addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED,
        addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED,
                deviceStateChangedReceiver);
                deviceStateChangedReceiver);


        mContext.registerReceiver(mBroadcastReceiver, mIntentFilter, null, null);
        mContext.registerReceiverAsUser(mBroadcastReceiver, user,
                mIntentFilter, null, null);
    }
    }


    /**
    /**
+2 −1
Original line number Original line Diff line number Diff line
@@ -1176,7 +1176,8 @@ class MediaRouter2ServiceImpl {
            super(Looper.getMainLooper(), null, true);
            super(Looper.getMainLooper(), null, true);
            mServiceRef = new WeakReference<>(service);
            mServiceRef = new WeakReference<>(service);
            mUserRecord = userRecord;
            mUserRecord = userRecord;
            mSystemProvider = new SystemMediaRoute2Provider(service.mContext);
            mSystemProvider = new SystemMediaRoute2Provider(service.mContext,
                    UserHandle.of(userRecord.mUserId));
            mRouteProviders.add(mSystemProvider);
            mRouteProviders.add(mSystemProvider);
            mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
            mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
                    this, mUserRecord.mUserId);
                    this, mUserRecord.mUserId);
+6 −4
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
@@ -99,7 +100,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
        }
        }
    };
    };


    SystemMediaRoute2Provider(Context context) {
    SystemMediaRoute2Provider(Context context, UserHandle user) {
        super(sComponentName);
        super(sComponentName);


        mIsSystemRouteProvider = true;
        mIsSystemRouteProvider = true;
@@ -117,7 +118,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
        updateDeviceRoute(newAudioRoutes);
        updateDeviceRoute(newAudioRoutes);


        // .getInstance returns null if there is no bt adapter available
        // .getInstance returns null if there is no bt adapter available
        mBtRouteProvider = BluetoothRouteProvider.getInstance(context, (routes) -> {
        mBtRouteProvider = BluetoothRouteProvider.createInstance(context, (routes) -> {
            publishProviderState();
            publishProviderState();


            boolean sessionInfoChanged;
            boolean sessionInfoChanged;
@@ -130,11 +131,12 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {


        IntentFilter intentFilter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
        IntentFilter intentFilter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
        intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
        intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
        mContext.registerReceiver(new AudioManagerBroadcastReceiver(), intentFilter);
        mContext.registerReceiverAsUser(new AudioManagerBroadcastReceiver(), user,
                intentFilter, null, null);


        if (mBtRouteProvider != null) {
        if (mBtRouteProvider != null) {
            mHandler.post(() -> {
            mHandler.post(() -> {
                mBtRouteProvider.start();
                mBtRouteProvider.start(user);
                notifyProviderState();
                notifyProviderState();
            });
            });
        }
        }