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

Commit fffc0b43 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "AutoConnect HFP: extend to multi device" into main

parents 98128e37 4eb78ba9
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ import java.util.Objects;
// 2. When the profile connection-state changes: At this point if a new profile gets CONNECTED we
// will try to connect other profiles on the same device. This is to avoid collision if devices
// somehow end up trying to connect at same time or general connection issues.
class PhonePolicy implements AdapterService.BluetoothStateCallback {
public class PhonePolicy implements AdapterService.BluetoothStateCallback {
    private static final boolean DBG = true;
    private static final String TAG = "BluetoothPhonePolicy";

@@ -83,6 +83,13 @@ class PhonePolicy implements AdapterService.BluetoothStateCallback {
    static boolean sIsHfpAutoConnectEnabled =
            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, HFP_AUTO_CONNECT, false);

    /** flag for multi auto connect */
    public static boolean sIsHfpMultiAutoConnectEnabled =
            DeviceConfig.getBoolean(
                    DeviceConfig.NAMESPACE_BLUETOOTH,
                    "com.android.bluetooth.hfp_multi_auto_connect",
                    false);

    // Timeouts
    @VisibleForTesting static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s

@@ -623,6 +630,20 @@ class PhonePolicy implements AdapterService.BluetoothStateCallback {
            return;
        }

        if (sIsHfpMultiAutoConnectEnabled) {
            final List<BluetoothDevice> mostRecentlyConnectedHfpDevices =
                    mDatabaseManager.getMostRecentlyActiveHfpDevices();
            for (BluetoothDevice hfpDevice : mostRecentlyConnectedHfpDevices) {
                debugLog("autoConnect: Headset device: " + hfpDevice);
                autoConnectHeadset(hfpDevice);
            }
            if (mostRecentlyConnectedHfpDevices.size() == 0) {
                Log.i(TAG, "autoConnect: No device to reconnect to");
            }
            return;
        }
        debugLog("HFP multi auto connect is not enabled");

        // Try to autoConnect with Hfp only if there was no a2dp valid device
        final BluetoothDevice mostRecentlyConnectedHfpDevice =
                mDatabaseManager.getMostRecentlyActiveHfpDevice();
+16 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.util.Log;
import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.PhonePolicy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

@@ -57,6 +58,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * The active device manager is responsible to handle a Room database
@@ -646,7 +648,7 @@ public class DatabaseManager {
            if (isA2dpDevice) {
                resetActiveA2dpDevice();
            }
            if (isHfpDevice) {
            if (isHfpDevice && !PhonePolicy.sIsHfpMultiAutoConnectEnabled) {
                resetActiveHfpDevice();
            }

@@ -845,6 +847,19 @@ public class DatabaseManager {
        return null;
    }

    /**
     * @return the list of device registered as HFP active
     */
    public List<BluetoothDevice> getMostRecentlyActiveHfpDevices() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        synchronized (mMetadataCache) {
            return mMetadataCache.entrySet().stream()
                    .filter(x -> x.getValue().isActiveHfpDevice)
                    .map(x -> adapter.getRemoteDevice(x.getValue().getAddress()))
                    .collect(Collectors.toList());
        }
    }

    /**
     *
     * @param metadataList is the list of metadata
+110 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.bluetooth.btservice;
import static com.android.bluetooth.TestUtils.getTestDevice;
import static com.android.bluetooth.TestUtils.waitForLooperToFinishScheduledTask;
import static com.android.bluetooth.btservice.PhonePolicy.sIsHfpAutoConnectEnabled;
import static com.android.bluetooth.btservice.PhonePolicy.sIsHfpMultiAutoConnectEnabled;

import static org.mockito.Mockito.*;

@@ -660,6 +661,115 @@ public class PhonePolicyTest {
        }
    }

    @Test
    public void autoConnect_whenMultiHfp_startConnection() {
        sIsHfpAutoConnectEnabled = true;
        sIsHfpMultiAutoConnectEnabled = true;

        try {
            // Return desired values from the mocked object(s)
            doReturn(BluetoothAdapter.STATE_ON).when(mAdapterService).getState();
            doReturn(false).when(mAdapterService).isQuietModeEnabled();

            MetadataDatabase mDatabase =
                    Room.inMemoryDatabaseBuilder(
                                    InstrumentationRegistry.getInstrumentation().getTargetContext(),
                                    MetadataDatabase.class)
                            .build();
            DatabaseManager db = new DatabaseManager(mAdapterService);
            doReturn(db).when(mAdapterService).getDatabase();
            PhonePolicy phonePolicy = new PhonePolicy(mAdapterService, mServiceFactory);

            db.start(mDatabase);
            TestUtils.waitForLooperToFinishScheduledTask(db.getHandlerLooper());

            List<BluetoothDevice> devices =
                    List.of(
                            getTestDevice(mAdapter, 1),
                            getTestDevice(mAdapter, 2),
                            getTestDevice(mAdapter, 3));

            for (BluetoothDevice device : devices) {
                db.setConnection(device, BluetoothProfile.HEADSET);
                doReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED)
                        .when(mHeadsetService)
                        .getConnectionPolicy(eq(device));
            }
            // wait for all MSG_UPDATE_DATABASE
            TestUtils.waitForLooperToFinishScheduledTask(db.getHandlerLooper());

            phonePolicy.autoConnect();

            // Check that we got a request to connect over HFP for each device
            for (BluetoothDevice device : devices) {
                verify(mHeadsetService).connect(eq(device));
            }
        } finally {
            sIsHfpMultiAutoConnectEnabled = false;
            sIsHfpAutoConnectEnabled = false;
        }
    }

    @Test
    public void autoConnect_whenMultiHfpAndDeconnection_startConnection() {
        sIsHfpAutoConnectEnabled = true;
        sIsHfpMultiAutoConnectEnabled = true;

        try {
            // Return desired values from the mocked object(s)
            doReturn(BluetoothAdapter.STATE_ON).when(mAdapterService).getState();
            doReturn(false).when(mAdapterService).isQuietModeEnabled();

            MetadataDatabase mDatabase =
                    Room.inMemoryDatabaseBuilder(
                                    InstrumentationRegistry.getInstrumentation().getTargetContext(),
                                    MetadataDatabase.class)
                            .build();
            DatabaseManager db = new DatabaseManager(mAdapterService);
            doReturn(db).when(mAdapterService).getDatabase();
            PhonePolicy phonePolicy = new PhonePolicy(mAdapterService, mServiceFactory);

            db.start(mDatabase);
            TestUtils.waitForLooperToFinishScheduledTask(db.getHandlerLooper());

            BluetoothDevice deviceToDeconnect = getTestDevice(mAdapter, 0);
            db.setConnection(deviceToDeconnect, BluetoothProfile.HEADSET);
            doReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED)
                    .when(mHeadsetService)
                    .getConnectionPolicy(eq(deviceToDeconnect));

            List<BluetoothDevice> devices =
                    List.of(
                            getTestDevice(mAdapter, 1),
                            getTestDevice(mAdapter, 2),
                            getTestDevice(mAdapter, 3));

            for (BluetoothDevice device : devices) {
                db.setConnection(device, BluetoothProfile.HEADSET);
                doReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED)
                        .when(mHeadsetService)
                        .getConnectionPolicy(eq(device));
            }

            db.setDisconnection(deviceToDeconnect, BluetoothProfile.HEADSET);

            // wait for all MSG_UPDATE_DATABASE
            TestUtils.waitForLooperToFinishScheduledTask(db.getHandlerLooper());

            phonePolicy.autoConnect();

            // Check that we got a request to connect over HFP for each device
            for (BluetoothDevice device : devices) {
                verify(mHeadsetService).connect(eq(device));
            }
            // Except for the device that was manually disconnected
            verify(mHeadsetService, times(0)).connect(eq(deviceToDeconnect));
        } finally {
            sIsHfpMultiAutoConnectEnabled = false;
            sIsHfpAutoConnectEnabled = false;
        }
    }

    /**
     * Test that a second device will auto-connect if there is already one connected device.
     *