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

Commit b5df86e7 authored by Ze Li's avatar Ze Li Committed by Android (Google) Code Review
Browse files

Merge "[Battery refactor] Function to get battery information from bluetooth...

Merge "[Battery refactor] Function to get battery information from bluetooth serve for hearing aid components." into main
parents 3d357938 68e111b1
Loading
Loading
Loading
Loading
+93 −21
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
@@ -154,8 +155,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
    private boolean mIsLeAudioProfileConnectedFail = false;
    private boolean mUnpairing;
    @Nullable
    private final InputDevice mInputDevice;
    private final boolean mIsDeviceStylus;
    private InputDevice mInputDevice;
    private boolean mIsDeviceStylus;

    // Group second device for Hearing Aid
    private CachedBluetoothDevice mSubDevice;
@@ -760,11 +761,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
     * {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
     */
    public int getMinBatteryLevelWithMemberDevices() {
        return Stream.concat(Stream.of(this), mMemberDevices.stream())
                .mapToInt(cachedDevice -> cachedDevice.getBatteryLevel())
                .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                .min()
                .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
        return getMinBatteryLevels(Stream.concat(Stream.of(this), mMemberDevices.stream())
                .mapToInt(CachedBluetoothDevice::getBatteryLevel));
    }

    /**
@@ -787,6 +785,13 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
                : null;
    }

    private int getMinBatteryLevels(IntStream batteryLevels) {
        return batteryLevels
                .filter(battery -> battery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                .min()
                .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
    }

    void refresh() {
        ListenableFuture<Void> future = ThreadUtils.getBackgroundExecutor().submit(() -> {
            if (BluetoothUtils.isAdvancedDetailsHeader(mDevice)) {
@@ -1672,10 +1677,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
                return null;
            } else {
                int overallBattery =
                        Arrays.stream(new int[]{leftBattery, rightBattery, caseBattery})
                                .filter(battery -> battery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                                .min()
                                .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
                        getMinBatteryLevels(
                                Arrays.stream(new int[]{leftBattery, rightBattery, caseBattery}));
                Log.d(TAG, "Acquired battery info from metadata for untethered device "
                        + mDevice.getAnonymizedAddress()
                        + " left earbud battery: " + leftBattery
@@ -1709,10 +1712,75 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>

    @Nullable
    private BatteryLevelsInfo getBatteryFromBluetoothService() {
        // TODO(b/397847825): Implement the logic to get battery from Bluetooth service.
        return null;
        BatteryLevelsInfo batteryLevelsInfo;
        if (isConnectedHearingAidDevice()) {
            // If the device is hearing aid device, sides can be distinguished by HearingAidInfo.
            batteryLevelsInfo = getBatteryOfHearingAidDeviceComponents();
            if (batteryLevelsInfo != null) {
                return batteryLevelsInfo;
            }
        }
        if (isConnectedLeAudioDevice()) {
            // If the device is LE Audio device, sides can be distinguished by LeAudioProfile.
            batteryLevelsInfo = getBatteryOfLeAudioDeviceComponents();
            if (batteryLevelsInfo != null) {
                return batteryLevelsInfo;
            }
        }
        int overallBattery = getMinBatteryLevelWithMemberDevices();
        return overallBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN
                ? new BatteryLevelsInfo(
                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                        overallBattery)
                : null;
    }

    @Nullable
    private BatteryLevelsInfo getBatteryOfHearingAidDeviceComponents() {
        if (getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) {
            return new BatteryLevelsInfo(
                    BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                    BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                    BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                    mDevice.getBatteryLevel());
        }

        int leftBattery = getHearingAidSideBattery(HearingAidInfo.DeviceSide.SIDE_LEFT);
        int rightBattery = getHearingAidSideBattery(HearingAidInfo.DeviceSide.SIDE_RIGHT);
        int overallBattery = getMinBatteryLevels(
                Arrays.stream(new int[]{leftBattery, rightBattery}));

        Log.d(TAG, "Acquired battery info from Bluetooth service for hearing aid device "
                + mDevice.getAnonymizedAddress()
                + " left battery: " + leftBattery
                + " right battery: " + rightBattery
                + " overall battery: " + overallBattery);
        return overallBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN
                ? new BatteryLevelsInfo(
                        leftBattery,
                        rightBattery,
                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
                        overallBattery)
                : null;
    }

    private int getHearingAidSideBattery(int side) {
        Optional<CachedBluetoothDevice> connectedHearingAidSide = getConnectedHearingAidSide(side);
        return connectedHearingAidSide.isPresent()
                ? connectedHearingAidSide
                    .map(CachedBluetoothDevice::getBatteryLevel)
                    .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                    .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                : BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
    }

    @Nullable
    private BatteryLevelsInfo getBatteryOfLeAudioDeviceComponents() {
        // TODO(b/397847825): Implement the logic to get battery of LE audio device components.
        return null;
    }
    private CharSequence getTvBatterySummary(int mainBattery, int leftBattery, int rightBattery,
            int lowBatteryColorRes) {
        // Since there doesn't seem to be a way to use format strings to add the
@@ -1831,10 +1899,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>

        // Retrieve hearing aids (ASHA, HAP) individual side battery level
        if (leftBattery == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
            leftBattery = getConnectedHearingAidSide(HearingAidInfo.DeviceSide.SIDE_LEFT)
                    .map(CachedBluetoothDevice::getBatteryLevel)
                    .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                    .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
            leftBattery = getHearingAidSideBattery(HearingAidInfo.DeviceSide.SIDE_LEFT);
        }

        return leftBattery;
@@ -1850,10 +1915,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>

        // Retrieve hearing aids (ASHA, HAP) individual side battery level
        if (rightBattery == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
            rightBattery = getConnectedHearingAidSide(HearingAidInfo.DeviceSide.SIDE_RIGHT)
                    .map(CachedBluetoothDevice::getBatteryLevel)
                    .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
                    .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
            rightBattery = getHearingAidSideBattery(HearingAidInfo.DeviceSide.SIDE_RIGHT);
        }

        return rightBattery;
@@ -2261,6 +2323,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        mBluetoothManager = bluetoothManager;
    }

    @VisibleForTesting
    void setIsDeviceStylus(Boolean isDeviceStylus) {
        mIsDeviceStylus = isDeviceStylus;
    }

    @VisibleForTesting
    void setInputDevice(@Nullable InputDevice inputDevice) {
        mInputDevice = inputDevice;
    }

    private boolean isAndroidAuto() {
        try {
            ParcelUuid[] uuids = mDevice.getUuids();
+27 −7
Original line number Diff line number Diff line
@@ -2298,11 +2298,7 @@ public class CachedBluetoothDeviceTest {
                "false".getBytes());
        when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn(
                MAIN_BATTERY.getBytes());
        when(mContext.getSystemService(InputManager.class)).thenReturn(mInputManager);
        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{TEST_DEVICE_ID});
        when(mInputManager.getInputDeviceBluetoothAddress(TEST_DEVICE_ID)).thenReturn(
                DEVICE_ADDRESS);
        when(mInputManager.getInputDevice(TEST_DEVICE_ID)).thenReturn(mInputDevice);
        mCachedDevice.setInputDevice(mInputDevice);

        BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();

@@ -2320,10 +2316,9 @@ public class CachedBluetoothDeviceTest {
    public void getBatteryLevelsInfo_stylusDeviceWithBattery_returnBatteryLevelsInfo() {
        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
                "false".getBytes());
        when(mDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
                BluetoothDevice.DEVICE_TYPE_STYLUS.getBytes());
        when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn(
                MAIN_BATTERY.getBytes());
        mCachedDevice.setIsDeviceStylus(true);

        BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();

@@ -2337,6 +2332,31 @@ public class CachedBluetoothDeviceTest {
                Integer.parseInt(MAIN_BATTERY));
    }

    @Test
    public void getBatteryLevelsInfo_hearingAidDeviceWithBattery_returnBatteryLevelsInfo() {
        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
                "false".getBytes());
        when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
        mSubCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo());
        when(mSubCachedDevice.getBatteryLevel()).thenReturn(Integer.parseInt(TWS_BATTERY_LEFT));
        updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
        mCachedDevice.setSubDevice(mSubCachedDevice);
        mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo());
        when(mCachedDevice.getBatteryLevel()).thenReturn(Integer.parseInt(TWS_BATTERY_RIGHT));

        BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();

        assertThat(batteryLevelsInfo.getLeftBatteryLevel()).isEqualTo(
                Integer.parseInt(TWS_BATTERY_LEFT));
        assertThat(batteryLevelsInfo.getRightBatteryLevel()).isEqualTo(
                Integer.parseInt(TWS_BATTERY_RIGHT));
        assertThat(batteryLevelsInfo.getCaseBatteryLevel()).isEqualTo(
                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
        assertThat(batteryLevelsInfo.getOverallBatteryLevel()).isEqualTo(
                Integer.parseInt(TWS_BATTERY_LEFT));
    }

    private void updateProfileStatus(LocalBluetoothProfile profile, int status) {
        doReturn(status).when(profile).getConnectionStatus(mDevice);
        mCachedDevice.onProfileStateChanged(profile, status);