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

Commit 56e32880 authored by Yiyi Shen's avatar Yiyi Shen Committed by Android (Google) Code Review
Browse files

Merge "Update fallback device when assistant profile disconnected" into main

parents 852e9337 ee6b8562
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ public class BluetoothEventManager {
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private final LocalBluetoothAdapter mLocalAdapter;
    private final LocalBluetoothManager mBtManager;
    private final CachedBluetoothDeviceManager mDeviceManager;
    private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter;
    private final Map<String, Handler> mHandlerMap;
@@ -80,10 +81,15 @@ public class BluetoothEventManager {
     * userHandle passed in is {@code null}, we register event receiver for the
     * {@code context.getUser()} handle.
     */
    BluetoothEventManager(LocalBluetoothAdapter adapter,
            CachedBluetoothDeviceManager deviceManager, Context context,
            android.os.Handler handler, @Nullable UserHandle userHandle) {
    BluetoothEventManager(
            LocalBluetoothAdapter adapter,
            LocalBluetoothManager btManager,
            CachedBluetoothDeviceManager deviceManager,
            Context context,
            android.os.Handler handler,
            @Nullable UserHandle userHandle) {
        mLocalAdapter = adapter;
        mBtManager = btManager;
        mDeviceManager = deviceManager;
        mAdapterIntentFilter = new IntentFilter();
        mProfileIntentFilter = new IntentFilter();
@@ -210,11 +216,27 @@ public class BluetoothEventManager {
        }
    }

    void dispatchProfileConnectionStateChanged(@NonNull CachedBluetoothDevice device, int state,
            int bluetoothProfile) {
    void dispatchProfileConnectionStateChanged(
            @NonNull CachedBluetoothDevice device, int state, int bluetoothProfile) {
        for (BluetoothCallback callback : mCallbacks) {
            callback.onProfileConnectionStateChanged(device, state, bluetoothProfile);
        }

        // Trigger updateFallbackActiveDeviceIfNeeded when ASSISTANT profile disconnected when
        // audio sharing is enabled.
        if (bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
                && state == BluetoothAdapter.STATE_DISCONNECTED
                && BluetoothUtils.isAudioSharingEnabled()) {
            LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
            if (profileManager != null
                    && profileManager.getLeAudioBroadcastProfile() != null
                    && profileManager.getLeAudioBroadcastProfile().isProfileReady()
                    && profileManager.getLeAudioBroadcastAssistantProfile() != null
                    && profileManager.getLeAudioBroadcastAssistantProfile().isProfileReady()) {
                Log.d(TAG, "updateFallbackActiveDeviceIfNeeded, ASSISTANT profile disconnected");
                profileManager.getLeAudioBroadcastProfile().updateFallbackActiveDeviceIfNeeded();
            }
        }
    }

    private void dispatchConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
@@ -536,7 +558,6 @@ public class BluetoothEventManager {
                default:
                    Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action);
                    return;

            }
            dispatchAclStateChanged(activeDevice, state);
        }
+13 −6
Original line number Diff line number Diff line
@@ -21,11 +21,11 @@ import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;

import java.lang.ref.WeakReference;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;

import java.lang.ref.WeakReference;

/**
 * LocalBluetoothManager provides a simplified interface on top of a subset of
 * the Bluetooth API. Note that {@link #getInstance} will return null
@@ -111,10 +111,17 @@ public class LocalBluetoothManager {
        mContext = context.getApplicationContext();
        mLocalAdapter = adapter;
        mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, this);
        mEventManager = new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mContext,
                handler, userHandle);
        mProfileManager = new LocalBluetoothProfileManager(mContext,
                mLocalAdapter, mCachedDeviceManager, mEventManager);
        mEventManager =
                new BluetoothEventManager(
                        mLocalAdapter,
                        this,
                        mCachedDeviceManager,
                        mContext,
                        handler,
                        userHandle);
        mProfileManager =
                new LocalBluetoothProfileManager(
                        mContext, mLocalAdapter, mCachedDeviceManager, mEventManager);

        mProfileManager.updateLocalProfiles();
        mEventManager.readPairedDevices();
+12 −7
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;

import static java.util.concurrent.TimeUnit.SECONDS;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -37,13 +39,11 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static java.util.concurrent.TimeUnit.SECONDS;

import java.util.concurrent.CountDownLatch;

/**
 * Test that verifies that BluetoothEventManager can receive broadcasts for non-current
 * users for all bluetooth events.
 * Test that verifies that BluetoothEventManager can receive broadcasts for non-current users for
 * all bluetooth events.
 *
 * <p>Creation and deletion of users takes a long time, so marking this as a LargeTest.
 */
@@ -64,9 +64,14 @@ public class BluetoothEventManagerIntegTest {
        mContext = InstrumentationRegistry.getTargetContext();
        mUserManager = UserManager.get(mContext);

        mBluetoothEventManager = new BluetoothEventManager(
                mock(LocalBluetoothAdapter.class), mock(CachedBluetoothDeviceManager.class),
                mContext, /* handler= */ null, UserHandle.ALL);
        mBluetoothEventManager =
                new BluetoothEventManager(
                        mock(LocalBluetoothAdapter.class),
                        mock(LocalBluetoothManager.class),
                        mock(CachedBluetoothDeviceManager.class),
                        mContext,
                        /* handler= */ null,
                        UserHandle.ALL);

        // Create and start another user in the background.
        mOtherUser = mUserManager.createUser("TestUser", /* flags= */ 0);
+190 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -29,35 +30,47 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyManager;

import com.android.settingslib.R;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class BluetoothEventManagerTest {
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    private static final String DEVICE_NAME = "test_device_name";

    @Mock
    private LocalBluetoothAdapter mLocalAdapter;
    @Mock
    private LocalBluetoothManager mBtManager;
    @Mock
    private CachedBluetoothDeviceManager mCachedDeviceManager;
    @Mock
    private BluetoothCallback mBluetoothCallback;
@@ -96,8 +109,15 @@ public class BluetoothEventManagerTest {
        MockitoAnnotations.initMocks(this);
        mContext = RuntimeEnvironment.application;

        mBluetoothEventManager = new BluetoothEventManager(mLocalAdapter,
                mCachedDeviceManager, mContext, /* handler= */ null, /* userHandle= */ null);
        mBluetoothEventManager =
                new BluetoothEventManager(
                        mLocalAdapter,
                        mBtManager,
                        mCachedDeviceManager,
                        mContext,
                        /* handler= */ null,
                        /* userHandle= */ null);
        when(mBtManager.getProfileManager()).thenReturn(mLocalProfileManager);
        when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
        when(mHfpProfile.isProfileReady()).thenReturn(true);
        when(mA2dpProfile.isProfileReady()).thenReturn(true);
@@ -113,8 +133,13 @@ public class BluetoothEventManagerTest {
    public void ifUserHandleIsNull_registerReceiverIsCalled() {
        Context mockContext = mock(Context.class);
        BluetoothEventManager eventManager =
                new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mockContext,
                        /* handler= */ null, /* userHandle= */ null);
                new BluetoothEventManager(
                        mLocalAdapter,
                        mBtManager,
                        mCachedDeviceManager,
                        mockContext,
                        /* handler= */ null,
                        /* userHandle= */ null);

        verify(mockContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class),
                eq(null), eq(null), eq(Context.RECEIVER_EXPORTED));
@@ -124,8 +149,13 @@ public class BluetoothEventManagerTest {
    public void ifUserHandleSpecified_registerReceiverAsUserIsCalled() {
        Context mockContext = mock(Context.class);
        BluetoothEventManager eventManager =
                new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mockContext,
                        /* handler= */ null, UserHandle.ALL);
                new BluetoothEventManager(
                        mLocalAdapter,
                        mBtManager,
                        mCachedDeviceManager,
                        mockContext,
                        /* handler= */ null,
                        UserHandle.ALL);

        verify(mockContext).registerReceiverAsUser(any(BroadcastReceiver.class), eq(UserHandle.ALL),
                any(IntentFilter.class), eq(null), eq(null), eq(Context.RECEIVER_EXPORTED));
@@ -172,6 +202,160 @@ public class BluetoothEventManagerTest {
                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
    }

    /**
     * dispatchProfileConnectionStateChanged should not call {@link
     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when audio sharing flag is off.
     */
    @Test
    public void dispatchProfileConnectionStateChanged_flagOff_noUpdateFallbackDevice() {
        ShadowBluetoothAdapter shadowBluetoothAdapter =
                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
        when(broadcast.isProfileReady()).thenReturn(true);
        LocalBluetoothLeBroadcastAssistant assistant =
                mock(LocalBluetoothLeBroadcastAssistant.class);
        when(assistant.isProfileReady()).thenReturn(true);
        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
        when(mBtManager.getProfileManager()).thenReturn(profileManager);
        mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                mCachedBluetoothDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);

        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
    }

    /**
     * dispatchProfileConnectionStateChanged should not call {@link
     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when the device does not
     * support audio sharing.
     */
    @Test
    public void dispatchProfileConnectionStateChanged_notSupport_noUpdateFallbackDevice() {
        ShadowBluetoothAdapter shadowBluetoothAdapter =
                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
        when(broadcast.isProfileReady()).thenReturn(true);
        LocalBluetoothLeBroadcastAssistant assistant =
                mock(LocalBluetoothLeBroadcastAssistant.class);
        when(assistant.isProfileReady()).thenReturn(true);
        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
        when(mBtManager.getProfileManager()).thenReturn(profileManager);
        mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                mCachedBluetoothDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);

        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
    }

    /**
     * dispatchProfileConnectionStateChanged should not call {@link
     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when audio sharing profile is
     * not ready.
     */
    @Test
    public void dispatchProfileConnectionStateChanged_profileNotReady_noUpdateFallbackDevice() {
        ShadowBluetoothAdapter shadowBluetoothAdapter =
                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
        when(broadcast.isProfileReady()).thenReturn(false);
        LocalBluetoothLeBroadcastAssistant assistant =
                mock(LocalBluetoothLeBroadcastAssistant.class);
        when(assistant.isProfileReady()).thenReturn(true);
        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
        when(mBtManager.getProfileManager()).thenReturn(profileManager);
        mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                mCachedBluetoothDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);

        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
    }

    /**
     * dispatchProfileConnectionStateChanged should not call {@link
     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when triggered for profile
     * other than LE_AUDIO_BROADCAST_ASSISTANT or state other than STATE_DISCONNECTED.
     */
    @Test
    public void dispatchProfileConnectionStateChanged_notAssistantProfile_noUpdateFallbackDevice() {
        ShadowBluetoothAdapter shadowBluetoothAdapter =
                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
        when(broadcast.isProfileReady()).thenReturn(true);
        LocalBluetoothLeBroadcastAssistant assistant =
                mock(LocalBluetoothLeBroadcastAssistant.class);
        when(assistant.isProfileReady()).thenReturn(true);
        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
        when(mBtManager.getProfileManager()).thenReturn(profileManager);
        mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                mCachedBluetoothDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.LE_AUDIO);

        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded();
    }

    /**
     * dispatchProfileConnectionStateChanged should call {@link
     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when assistant profile is
     * disconnected and audio sharing is enabled.
     */
    @Test
    public void dispatchProfileConnectionStateChanged_audioSharing_updateFallbackDevice() {
        ShadowBluetoothAdapter shadowBluetoothAdapter =
                Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
                BluetoothStatusCodes.FEATURE_SUPPORTED);
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class);
        when(broadcast.isProfileReady()).thenReturn(true);
        LocalBluetoothLeBroadcastAssistant assistant =
                mock(LocalBluetoothLeBroadcastAssistant.class);
        when(assistant.isProfileReady()).thenReturn(true);
        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class);
        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast);
        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant);
        when(mBtManager.getProfileManager()).thenReturn(profileManager);
        mBluetoothEventManager.dispatchProfileConnectionStateChanged(
                mCachedBluetoothDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);

        verify(broadcast).updateFallbackActiveDeviceIfNeeded();
    }

    @Test
    public void dispatchAclConnectionStateChanged_aclDisconnected_shouldDispatchCallback() {
        mBluetoothEventManager.registerCallback(mBluetoothCallback);
+14 −5
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ import java.util.List;
@Config(shadows = {ShadowBluetoothAdapter.class})
public class LocalBluetoothProfileManagerTest {
    private final static long HISYNCID = 10;

    @Mock
    private LocalBluetoothManager mBtManager;
    @Mock
    private CachedBluetoothDeviceManager mDeviceManager;
    @Mock
@@ -77,13 +78,21 @@ public class LocalBluetoothProfileManagerTest {
        MockitoAnnotations.initMocks(this);
        mContext = spy(RuntimeEnvironment.application);
        mLocalBluetoothAdapter = LocalBluetoothAdapter.getInstance();
        mEventManager = spy(new BluetoothEventManager(mLocalBluetoothAdapter, mDeviceManager,
                mContext, /* handler= */ null, /* userHandle= */ null));
        mEventManager =
                spy(
                        new BluetoothEventManager(
                                mLocalBluetoothAdapter,
                                mBtManager,
                                mDeviceManager,
                                mContext,
                                /* handler= */ null,
                                /* userHandle= */ null));
        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
        when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mDevice);
        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter,
                mDeviceManager, mEventManager);
        mProfileManager =
                new LocalBluetoothProfileManager(
                        mContext, mLocalBluetoothAdapter, mDeviceManager, mEventManager);
    }

    /**
Loading