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

Commit ee62a74e authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

PhonePolicy: Fix connecting other profiles.

Connecting other profiles is called from timer - 6sec after some
profile got connected.
If within this 6 sec, device got disconnected, connect other profile
will be called and if there is still a profile connected then other
profiles will start to reconnect (even device is already disconnecte)

Note: if there is LeAudio device streaming, and LeAudio lead device got
disconnected, the LeAudioProfile is still connected in order to keep
music play. Under the hood it is reconnecting, but this is happaning in
native layer. In such case we don't want java layer to start
reconnection of the profiles

Bug: 294965719
Test: atest PhonePolicyTest
Tag: #feature
Change-Id: Ib0dac7a9d9bae75eaa68ec321e055092c035dcb5
parent a3de0fb8
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -750,6 +750,13 @@ class PhonePolicy {
            warnLog("processConnectOtherProfiles, adapter is not ON " + mAdapterService.getState());
            return;
        }

        /* Make sure that device is still connected before connecting other profiles */
        if (mAdapterService.getConnectionState(device) != BluetoothAdapter.STATE_CONNECTED) {
            debugLog("processConnectOtherProfiles: device is not connected anymore " + device);
            return;
        }

        if (handleAllProfilesDisconnected(device)) {
            debugLog("processConnectOtherProfiles: all profiles disconnected for " + device);
            return;
+80 −4
Original line number Diff line number Diff line
@@ -468,6 +468,10 @@ public class PhonePolicyTest {
        when(mA2dpService.getConnectionState(bondedDevices[0])).thenReturn(
                BluetoothProfile.STATE_DISCONNECTED);

        // ACL is connected, lets simulate this.
        when(mAdapterService.getConnectionState(bondedDevices[0]))
                .thenReturn(BluetoothProfile.STATE_CONNECTED);

        // We send a connection successful for one profile since the re-connect *only* works if we
        // have already connected successfully over one of the profiles
        updateProfileConnectionStateHelper(bondedDevices[0], BluetoothProfile.HEADSET,
@@ -478,6 +482,54 @@ public class PhonePolicyTest {
                eq(bondedDevices[0]));
    }

    /**
     * Test that connectOtherProfile will not trigger any actions when ACL is disconnected. This is
     * to add robustness to the connection mechanism
     */
    @Test
    public void testConnectOtherProfileWhileDeviceIsDisconnected() {
        // Return a list of bonded devices (just one)
        BluetoothDevice[] bondedDevices = new BluetoothDevice[1];
        bondedDevices[0] = getTestDevice(mAdapter, 0);
        when(mAdapterService.getBondedDevices()).thenReturn(bondedDevices);

        // Return PRIORITY_AUTO_CONNECT over HFP and A2DP. This would imply that the profiles are
        // auto-connectable.
        when(mHeadsetService.getConnectionPolicy(bondedDevices[0]))
                .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        when(mA2dpService.getConnectionPolicy(bondedDevices[0]))
                .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        when(mAdapterService.getState()).thenReturn(BluetoothAdapter.STATE_ON);

        // We want to trigger (in CONNECT_OTHER_PROFILES_TIMEOUT) a call to connect A2DP
        // To enable that we need to make sure that HeadsetService returns the device as list of
        // connected devices
        ArrayList<BluetoothDevice> hsConnectedDevices = new ArrayList<>();
        hsConnectedDevices.add(bondedDevices[0]);
        when(mHeadsetService.getConnectedDevices()).thenReturn(hsConnectedDevices);
        // Also the A2DP should say that it's not connected for same device
        when(mA2dpService.getConnectionState(bondedDevices[0]))
                .thenReturn(BluetoothProfile.STATE_DISCONNECTED);

        // ACL is disconnected just after HEADSET profile got connected and connectOtherProfile
        // was scheduled. Lets simulate this.
        when(mAdapterService.getConnectionState(bondedDevices[0]))
                .thenReturn(BluetoothProfile.STATE_DISCONNECTED);

        // We send a connection successful for one profile since the re-connect *only* works if we
        // have already connected successfully over one of the profiles
        updateProfileConnectionStateHelper(
                bondedDevices[0],
                BluetoothProfile.HEADSET,
                BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);

        // Check that there will be no A2DP connect
        verify(mA2dpService, after(CONNECT_OTHER_PROFILES_TIMEOUT_WAIT_MILLIS).never())
                .connect(eq(bondedDevices[0]));
    }

    /**
     * Test that we will try to re-connect to a profile on a device next time if a previous attempt
     * failed partially. This will make sure the connection mechanism still works at next try while
@@ -486,7 +538,13 @@ public class PhonePolicyTest {
    @Test
    public void testReconnectOnPartialConnect_PreviousPartialFail() {
        List<BluetoothDevice> connectionOrder = new ArrayList<>();
        connectionOrder.add(getTestDevice(mAdapter, 0));
        BluetoothDevice testDevice = getTestDevice(mAdapter, 0);
        connectionOrder.add(testDevice);

        // ACL is connected, lets simulate this.
        when(mAdapterService.getConnectionState(testDevice))
                .thenReturn(BluetoothProfile.STATE_CONNECTED);

        when(mDatabaseManager.getMostRecentlyConnectedA2dpDevice()).thenReturn(
                connectionOrder.get(0));

@@ -573,6 +631,10 @@ public class PhonePolicyTest {
            BluetoothDevice testDevice = getTestDevice(mAdapter, i);
            testDevices[i] = testDevice;

            // ACL is connected, lets simulate this.
            when(mAdapterService.getConnectionState(testDevice))
                    .thenReturn(BluetoothProfile.STATE_CONNECTED);

            // Return PRIORITY_AUTO_CONNECT over HFP and A2DP. This would imply that the profiles
            // are auto-connectable.
            when(mHeadsetService.getConnectionPolicy(testDevice)).thenReturn(
@@ -641,6 +703,10 @@ public class PhonePolicyTest {
            BluetoothDevice testDevice = getTestDevice(mAdapter, i);
            testDevices[i] = testDevice;

            // ACL is connected, lets simulate this.
            when(mAdapterService.getConnectionState(testDevices[i]))
                    .thenReturn(BluetoothProfile.STATE_CONNECTED);

            // Connect HFP and A2DP for each device as appropriate.
            // Return PRIORITY_AUTO_CONNECT only for testDevices[0]
            if (i == 0) {
@@ -854,6 +920,12 @@ public class PhonePolicyTest {
        when(mHeadsetService.getConnectionState(bondedDevices[1])).thenReturn(
                BluetoothProfile.STATE_CONNECTED);

        // ACL is connected for both devices.
        when(mAdapterService.getConnectionState(bondedDevices[0]))
                .thenReturn(BluetoothProfile.STATE_CONNECTED);
        when(mAdapterService.getConnectionState(bondedDevices[1]))
                .thenReturn(BluetoothProfile.STATE_CONNECTED);

        // We send a connection successful for one profile since the re-connect *only* works if we
        // have already connected successfully over one of the profiles
        Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
@@ -906,14 +978,18 @@ public class PhonePolicyTest {
        when(mA2dpService.getConnectionState(bondedDevices[1])).thenReturn(
                BluetoothProfile.STATE_DISCONNECTED);

        // ACL is connected, lets simulate this.
        when(mAdapterService.getConnectionState(bondedDevices[1]))
                .thenReturn(BluetoothProfile.STATE_CONNECTED);

        // We send a connection successful for one profile since the re-connect *only* works if we
        // have already connected successfully over one of the profiles
        updateProfileConnectionStateHelper(bondedDevices[1], BluetoothProfile.HEADSET,
                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);

        // Check that we don't get any calls to reconnect
        verify(mA2dpService, timeout(CONNECT_OTHER_PROFILES_TIMEOUT_WAIT_MILLIS)).connect(
                eq(bondedDevices[1]));
        // Check that we do get A2DP call to reconnect, because HEADSET just got connected
        verify(mA2dpService, timeout(CONNECT_OTHER_PROFILES_TIMEOUT_WAIT_MILLIS))
                .connect(eq(bondedDevices[1]));
    }

    /**