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

Commit 20ef4025 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun Committed by Jack He
Browse files

Do not reset battery level when HFP is disconnected

The battery level was reset when HFP was disconnected.

It was okay when HFP was the only way to get the battery level
but we are getting the battery level from the
battery service (BAS) as well so we need to
check if we should reset or not.

This change checks the condition and does not reset the
battery level if it is still valid information.

It also adds tests to ensure the functionality.

Tag: #feature
Bug: 269969529
Test: atest BluetoothInstrumentationTests and manually tested with LE HS and HFP
Change-Id: Iac16347045cac4201f0cd2132e51336159f03fed
parent e7dc1c41
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -61,7 +61,6 @@ public class BatteryService extends ProfileService {

    private static final int MAX_BATTERY_STATE_MACHINES = 10;
    private static BatteryService sBatteryService;

    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
@@ -177,7 +176,11 @@ public class BatteryService extends ProfileService {
        return sBatteryService;
    }

    private static synchronized void setBatteryService(BatteryService instance) {
    /**
     * Sets the battery service instance. It should be called only for testing purpose.
     */
    @VisibleForTesting
    public static synchronized void setBatteryService(BatteryService instance) {
        if (DBG) {
            Log.d(TAG, "setBatteryService(): set to: " + instance);
        }
+11 −4
Original line number Diff line number Diff line
@@ -1217,8 +1217,8 @@ final class RemoteDevices {
            return;
        }
        if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED)
                == BluetoothProfile.STATE_DISCONNECTED) {
            // TODO: Rework this when non-HFP sources of battery level indication is added
                == BluetoothProfile.STATE_DISCONNECTED
                && !hasBatteryService(device)) {
            resetBatteryLevel(device);
        }
    }
@@ -1381,6 +1381,13 @@ final class RemoteDevices {
        return batteryLevel * 100 / (numberOfLevels - 1);
    }

    @VisibleForTesting
    boolean hasBatteryService(BluetoothDevice device) {
        BatteryService batteryService = BatteryService.getBatteryService();
        return batteryService != null
                && batteryService.getConnectionState(device) == BluetoothProfile.STATE_CONNECTED;
    }

    /**
     * Handles headset client connection state change event
     * @param intent must be {@link BluetoothHeadsetClient#ACTION_CONNECTION_STATE_CHANGED} intent
@@ -1393,8 +1400,8 @@ final class RemoteDevices {
            return;
        }
        if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED)
                == BluetoothProfile.STATE_DISCONNECTED) {
            // TODO: Rework this when non-HFP sources of battery level indication is added
                == BluetoothProfile.STATE_DISCONNECTED
                && !hasBatteryService(device)) {
            resetBatteryLevel(device);
        }
    }
+90 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.Utils;
import com.android.bluetooth.bas.BatteryService;
import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
import com.android.bluetooth.hfp.HeadsetHalConstants;

@@ -274,6 +275,43 @@ public class RemoteDevicesTest {
        verifyNoMoreInteractions(mAdapterService);
    }

    @Test
    public void testOnHeadsetStateChangeWithBatteryService_NotResetBatteryLevel() {
        int batteryLevel = 10;

        BatteryService oldBatteryService = setBatteryServiceForTesting(mDevice1);
        Assert.assertTrue(mRemoteDevices.hasBatteryService(mDevice1));

        // Verify that device property is null initially
        Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));

        // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
        mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel);
        verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(),
                any(Bundle.class));
        verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument);
        Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());

        // Verify that user can get battery level after the update
        Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
        Assert.assertEquals(mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(),
                batteryLevel);

        // Verify that battery level is not reset
        mRemoteDevices.onHeadsetConnectionStateChanged(
                getHeadsetConnectionStateChangedIntent(mDevice1,
                        BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_DISCONNECTED));

        Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
        Assert.assertEquals(batteryLevel,
                mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel());

        // Recover the previous battery service if exists
        clearBatteryServiceForTesting(oldBatteryService);

        verifyNoMoreInteractions(mAdapterService);
    }

    @Test
    @Ignore("b/266128644")
    public void testResetBatteryLevel_testAclStateChangeCallback() {
@@ -506,6 +544,42 @@ public class RemoteDevicesTest {
        verifyNoMoreInteractions(mAdapterService);
    }

    @Test
    public void testHeadsetClientDisconnectedWithBatteryService_NotResetBatteryLevel() {
        int batteryLevel = 10;

        BatteryService oldBatteryService = setBatteryServiceForTesting(mDevice1);
        Assert.assertTrue(mRemoteDevices.hasBatteryService(mDevice1));

        // Verify that device property is null initially
        Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1));

        // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent
        mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel);
        verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(),
                any(Bundle.class));
        verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument);
        Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue());

        // Verify that user can get battery level after the update
        Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
        Assert.assertEquals(mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel(),
                batteryLevel);

        // Verify that battery level is not reset.
        mRemoteDevices.onHeadsetClientConnectionStateChanged(
                getHeadsetClientConnectionStateChangedIntent(mDevice1,
                        BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_DISCONNECTED));

        Assert.assertNotNull(mRemoteDevices.getDeviceProperties(mDevice1));
        Assert.assertEquals(batteryLevel,
                mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel());

        clearBatteryServiceForTesting(oldBatteryService);

        verifyNoMoreInteractions(mAdapterService);
    }

    @Test
    public void testAGIndicatorParser_testCorrectValue() {
        int batteryLevel = 3;
@@ -647,4 +721,20 @@ public class RemoteDevicesTest {

        return intent;
    }

    private static BatteryService setBatteryServiceForTesting(BluetoothDevice device) {
        BatteryService newService = mock(BatteryService.class);
        when(newService.getConnectionState(device))
                .thenReturn(BluetoothProfile.STATE_CONNECTED);
        when(newService.isAvailable()).thenReturn(true);

        BatteryService oldService = BatteryService.getBatteryService();
        BatteryService.setBatteryService(newService);

        return oldService;
    }

    private static void clearBatteryServiceForTesting(BatteryService service) {
        BatteryService.setBatteryService(service);
    }
}