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

Commit d1ddd24c authored by Jack He's avatar Jack He
Browse files

Allow PRIORITY_UNDEFINED when remote device is BONDING or BONDED

* When priority is undefined, it is likely that SDP has not completed
  and peer is initiating the connection. Allow this connection for HFP,
  A2DP, and HearingAid if the device is bonded or bonding.
* Added unit tests for various okToConnect methods

Bug: 78336562
Test: A2dpServiceTest, HeadsetServiceTest, HearingAidServiceTest
      let Benz NTG5 Star2 Car kit connect to DUT

Change-Id: I3e35fab38b485efa89b33c65a3980072a17b7272
parent bf668ef0
Loading
Loading
Loading
Loading
+17 −11
Original line number Diff line number Diff line
@@ -346,19 +346,25 @@ public class A2dpService extends ProfileService {
                    + " : too many connected devices");
            return false;
        }
        // Check priority and accept or reject the connection
        // Check priority and accept or reject the connection.
        // Note: Logic can be simplified, but keeping it this way for readability
        int priority = getPriority(device);
        int bondState = mAdapterService.getBondState(device);
        // If priority is undefined, it is likely that our SDP has not completed and peer is
        // initiating the connection. Allow the connection only if the device is bonded or bonding.
        if ((priority == BluetoothProfile.PRIORITY_UNDEFINED)
                && (bondState == BluetoothDevice.BOND_NONE)) {
            Log.e(TAG, "okToConnect: cannot connect to " + device + " : priority=" + priority
                    + " bondState=" + bondState);
            return false;
        }
        if (priority <= BluetoothProfile.PRIORITY_OFF) {
            Log.e(TAG, "okToConnect: cannot connect to " + device + " : priority=" + priority);
        // If priority is undefined, it is likely that service discovery has not completed and peer
        // initiated the connection. Allow this connection only if the device is bonded or bonding
        boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
                && (bondState == BluetoothDevice.BOND_BONDING
                || bondState == BluetoothDevice.BOND_BONDED);
        // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
        boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
                || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT)
                && (bondState == BluetoothDevice.BOND_BONDED
                || bondState == BluetoothDevice.BOND_BONDING);
        if (!serviceDiscoveryPending && !isEnabled) {
            // Otherwise, reject the connection if no service discovery is pending and priority is
            // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT
            Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState="
                    + bondState);
            return false;
        }
        return true;
+17 −10
Original line number Diff line number Diff line
@@ -313,18 +313,25 @@ public class HearingAidService extends ProfileService {
            Log.e(TAG, "okToConnect: cannot connect to " + device + " : quiet mode enabled");
            return false;
        }
        // Check priority and accept or reject the connection
        // Check priority and accept or reject the connection.
        // Note: Logic can be simplified, but keeping it this way for readability
        int priority = getPriority(device);
        int bondState = mAdapterService.getBondState(device);
        // Allow the connection only if the device is bonded or bonding.
        if ((priority == BluetoothProfile.PRIORITY_UNDEFINED)
                && (bondState == BluetoothDevice.BOND_NONE)) {
            Log.e(TAG, "okToConnect: cannot connect to " + device + " : priority=" + priority
                    + " bondState=" + bondState);
            return false;
        }
        if (priority <= BluetoothProfile.PRIORITY_OFF) {
            Log.e(TAG, "okToConnect: cannot connect to " + device + " : priority=" + priority);
        // If priority is undefined, it is likely that service discovery has not completed and peer
        // initiated the connection. Allow this connection only if the device is bonded or bonding
        boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
                && (bondState == BluetoothDevice.BOND_BONDING
                   || bondState == BluetoothDevice.BOND_BONDED);
        // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
        boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
                || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT)
                && (bondState == BluetoothDevice.BOND_BONDED
                   || bondState == BluetoothDevice.BOND_BONDING);
        if (!serviceDiscoveryPending && !isEnabled) {
            // Otherwise, reject the connection if no service discovery is pending and priority is
            // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT
            Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState="
                    + bondState);
            return false;
        }
        return true;
+14 −9
Original line number Diff line number Diff line
@@ -1231,17 +1231,22 @@ public class HeadsetService extends ProfileService {
        // Note: Logic can be simplified, but keeping it this way for readability
        int priority = getPriority(device);
        int bondState = mAdapterService.getBondState(device);
        // If priority is undefined, it is likely that our SDP has not completed and peer is
        // initiating the connection. Allow this connection only if the device is bonded or bonding
        if ((priority == BluetoothProfile.PRIORITY_UNDEFINED) && (bondState
                == BluetoothDevice.BOND_NONE)) {
            Log.w(TAG, "okToAcceptConnection: return false, priority=" + priority + ", bondState="
        // If priority is undefined, it is likely that service discovery has not completed and peer
        // initiated the connection. Allow this connection only if the device is bonded or bonding
        boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
                && (bondState == BluetoothDevice.BOND_BONDING
                || bondState == BluetoothDevice.BOND_BONDED);
        // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
        boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
                || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT)
                && (bondState == BluetoothDevice.BOND_BONDED
                || bondState == BluetoothDevice.BOND_BONDING);
        if (!serviceDiscoveryPending && !isEnabled) {
            // Otherwise, reject the connection if no service discovery is pending and priority is
            // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT
            Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState="
                    + bondState);
            return false;
        } else if (priority <= BluetoothProfile.PRIORITY_OFF) {
            // Otherwise, reject the connection if priority is less than or equal to PRIORITY_OFF
            Log.w(TAG, "okToAcceptConnection: return false, priority=" + priority);
            return false;
        }
        List<BluetoothDevice> connectingConnectedDevices =
                getDevicesMatchingConnectionStates(CONNECTING_CONNECTED_STATES);
+69 −0
Original line number Diff line number Diff line
@@ -315,6 +315,59 @@ public class A2dpServiceTest {
                            mA2dpService.getPriority(mTestDevice));
    }

    /**
     *  Test okToConnect method using various test cases
     */
    @Test
    public void testOkToConnect() {
        int badPriorityValue = 1024;
        int badBondState = 42;
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_UNDEFINED, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_ON, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_NONE, badPriorityValue, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, true);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, true);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDING, badPriorityValue, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_UNDEFINED, true);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_ON, true);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
        testOkToConnectCase(mTestDevice,
                BluetoothDevice.BOND_BONDED, badPriorityValue, false);
        testOkToConnectCase(mTestDevice,
                badBondState, BluetoothProfile.PRIORITY_UNDEFINED, false);
        testOkToConnectCase(mTestDevice,
                badBondState, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mTestDevice,
                badBondState, BluetoothProfile.PRIORITY_ON, false);
        testOkToConnectCase(mTestDevice,
                badBondState, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
        testOkToConnectCase(mTestDevice,
                badBondState, badPriorityValue, false);
        // Restore prirority to undefined for this test device
        Assert.assertTrue(mA2dpService.setPriority(
                mTestDevice, BluetoothProfile.PRIORITY_UNDEFINED));
    }


    /**
     * Test that an outgoing connection to device that does not have A2DP Sink UUID is rejected
     */
@@ -834,4 +887,20 @@ public class A2dpServiceTest {
        // Verify the codec status broadcast
        verifyNoCodecConfigIntent(TIMEOUT_MS);
    }

    /**
     *  Helper function to test okToConnect() method
     *
     *  @param device test device
     *  @param bondState bond state value, could be invalid
     *  @param priority value, could be invalid, coudl be invalid
     *  @param expected expected result from okToConnect()
     */
    private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority,
            boolean expected) {
        doReturn(bondState).when(mAdapterService).getBondState(device);
        Assert.assertTrue(mA2dpService.setPriority(device, priority));
        Assert.assertEquals(expected, mA2dpService.okToConnect(device));
    }

}
+78 −0
Original line number Diff line number Diff line
@@ -277,6 +277,57 @@ public class HearingAidServiceTest {
                mService.getPriority(mLeftDevice));
    }

    /**
     *  Test okToConnect method using various test cases
     */
    @Test
    public void testOkToConnect() {
        int badPriorityValue = 1024;
        int badBondState = 42;
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_UNDEFINED, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_ON, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_NONE, badPriorityValue, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, true);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, true);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDING, badPriorityValue, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_UNDEFINED, true);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_ON, true);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
        testOkToConnectCase(mSingleDevice,
                BluetoothDevice.BOND_BONDED, badPriorityValue, false);
        testOkToConnectCase(mSingleDevice,
                badBondState, BluetoothProfile.PRIORITY_UNDEFINED, false);
        testOkToConnectCase(mSingleDevice,
                badBondState, BluetoothProfile.PRIORITY_OFF, false);
        testOkToConnectCase(mSingleDevice,
                badBondState, BluetoothProfile.PRIORITY_ON, false);
        testOkToConnectCase(mSingleDevice,
                badBondState, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
        testOkToConnectCase(mSingleDevice,
                badBondState, badPriorityValue, false);
        // Restore prirority to undefined for this test device
        Assert.assertTrue(mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED));
    }

    /**
     * Test that an outgoing connection to device that does not have Hearing Aid UUID is rejected
     */
@@ -284,6 +335,8 @@ public class HearingAidServiceTest {
    public void testOutgoingConnectMissingHearingAidUuid() {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_OFF);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -317,6 +370,8 @@ public class HearingAidServiceTest {
    public void testOutgoingConnectTimeout() {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_OFF);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -347,6 +402,7 @@ public class HearingAidServiceTest {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -434,6 +490,7 @@ public class HearingAidServiceTest {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -542,6 +599,8 @@ public class HearingAidServiceTest {
    public void testCreateStateMachineStackEvents() {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_OFF);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -601,6 +660,8 @@ public class HearingAidServiceTest {
    public void testDeleteStateMachineUnbondEvents() {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_OFF);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -656,6 +717,8 @@ public class HearingAidServiceTest {
    public void testDeleteStateMachineDisconnectEvents() {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_OFF);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);
        doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class));
        doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class));

@@ -698,6 +761,7 @@ public class HearingAidServiceTest {
        // Update the device priority so okToConnect() returns true
        mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON);
        mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_OFF);

        generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_CONNECTED,
                BluetoothProfile.STATE_DISCONNECTED);
@@ -806,5 +870,19 @@ public class HearingAidServiceTest {
        verifyNoConnectionStateIntent(TIMEOUT_MS);
    }

    /**
     *  Helper function to test okToConnect() method
     *
     *  @param device test device
     *  @param bondState bond state value, could be invalid
     *  @param priority value, could be invalid, coudl be invalid
     *  @param expected expected result from okToConnect()
     */
    private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority,
            boolean expected) {
        doReturn(bondState).when(mAdapterService).getBondState(device);
        Assert.assertTrue(mService.setPriority(device, priority));
        Assert.assertEquals(expected, mService.okToConnect(device));
    }

}
Loading