Loading android/app/src/com/android/bluetooth/bas/BatteryService.java +1 −1 Original line number Diff line number Diff line Loading @@ -442,7 +442,7 @@ public class BatteryService extends ProfileService { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void handleBatteryChanged(BluetoothDevice device, int batteryLevel) { mAdapterService.setBatteryLevel(device, batteryLevel); mAdapterService.setBatteryLevel(device, batteryLevel, /*isBas=*/ true); } private BatteryStateMachine getOrCreateStateMachine(BluetoothDevice device) { Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +3 −3 Original line number Diff line number Diff line Loading @@ -7666,11 +7666,11 @@ public class AdapterService extends Service { } /** Sets the battery level of the remote device */ public void setBatteryLevel(BluetoothDevice device, int batteryLevel) { public void setBatteryLevel(BluetoothDevice device, int batteryLevel, boolean isBas) { if (batteryLevel == BATTERY_LEVEL_UNKNOWN) { mRemoteDevices.resetBatteryLevel(device); mRemoteDevices.resetBatteryLevel(device, isBas); } else { mRemoteDevices.updateBatteryLevel(device, batteryLevel); mRemoteDevices.updateBatteryLevel(device, batteryLevel, isBas); } } Loading android/app/src/com/android/bluetooth/btservice/RemoteDevices.java +70 −37 Original line number Diff line number Diff line Loading @@ -323,7 +323,8 @@ final class RemoteDevices { private String mAlias; private BluetoothDevice mDevice; private boolean mIsBondingInitiatedLocally; private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private int mBatteryLevelFromHfp = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private int mBatteryLevelFromBatteryService = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private boolean mIsCoordinatedSetMember; private int mAshaCapability; private int mAshaTruncatedHiSyncId; Loading Loading @@ -613,16 +614,28 @@ final class RemoteDevices { */ int getBatteryLevel() { synchronized (mObject) { return mBatteryLevel; if (mBatteryLevelFromBatteryService != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { return mBatteryLevelFromBatteryService; } return mBatteryLevelFromHfp; } } /** * @param batteryLevel the mBatteryLevel to set */ void setBatteryLevel(int batteryLevel) { void setBatteryLevelFromHfp(int batteryLevel) { synchronized (mObject) { if (mBatteryLevelFromHfp == batteryLevel) { return; } mBatteryLevelFromHfp = batteryLevel; } } void setBatteryLevelFromBatteryService(int batteryLevel) { synchronized (mObject) { this.mBatteryLevel = batteryLevel; if (mBatteryLevelFromBatteryService == batteryLevel) { return; } mBatteryLevelFromBatteryService = batteryLevel; } } Loading Loading @@ -740,40 +753,53 @@ final class RemoteDevices { /** * Update battery level in device properties * * @param device The remote device to be updated * @param batteryLevel Battery level Indicator between 0-100, * {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} is error * @param batteryLevel Battery level Indicator between 0-100, {@link * BluetoothDevice#BATTERY_LEVEL_UNKNOWN} is error * @param isBas true if the battery level is from the battery service */ @VisibleForTesting void updateBatteryLevel(BluetoothDevice device, int batteryLevel) { void updateBatteryLevel(BluetoothDevice device, int batteryLevel, boolean isBas) { if (device == null || batteryLevel < 0 || batteryLevel > 100) { warnLog("Invalid parameters device=" + String.valueOf(device == null) + ", batteryLevel=" + String.valueOf(batteryLevel)); warnLog( "Invalid parameters device=" + String.valueOf(device == null) + ", batteryLevel=" + String.valueOf(batteryLevel)); return; } DeviceProperties deviceProperties = getDeviceProperties(device); if (deviceProperties == null) { deviceProperties = addDeviceProperties(Utils.getByteAddress(device)); } synchronized (mObject) { int currentBatteryLevel = deviceProperties.getBatteryLevel(); if (batteryLevel == currentBatteryLevel) { debugLog("Same battery level for device " + device + " received " + String.valueOf( batteryLevel) + "%"); return; int prevBatteryLevel = deviceProperties.getBatteryLevel(); if (isBas) { deviceProperties.setBatteryLevelFromBatteryService(batteryLevel); } else { deviceProperties.setBatteryLevelFromHfp(batteryLevel); } deviceProperties.setBatteryLevel(batteryLevel); int newBatteryLevel = deviceProperties.getBatteryLevel(); if (prevBatteryLevel == newBatteryLevel) { debugLog( "Same battery level for device " + device + " received " + String.valueOf(batteryLevel) + "%"); return; } sendBatteryLevelChangedBroadcast(device, batteryLevel); Log.d(TAG, "Updated device " + device + " battery level to " + batteryLevel + "%"); sendBatteryLevelChangedBroadcast(device, newBatteryLevel); Log.d(TAG, "Updated device " + device + " battery level to " + newBatteryLevel + "%"); } /** * Reset battery level property to {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} for a device * * @param device device whose battery level property needs to be reset */ @VisibleForTesting void resetBatteryLevel(BluetoothDevice device) { void resetBatteryLevel(BluetoothDevice device, boolean isBas) { if (device == null) { warnLog("Device is null"); return; Loading @@ -782,15 +808,21 @@ final class RemoteDevices { if (deviceProperties == null) { return; } synchronized (mObject) { if (deviceProperties.getBatteryLevel() == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { debugLog("Battery level was never set or is already reset, device=" + device); return; int prevBatteryLevel = deviceProperties.getBatteryLevel(); if (isBas) { deviceProperties.setBatteryLevelFromBatteryService( BluetoothDevice.BATTERY_LEVEL_UNKNOWN); } else { deviceProperties.setBatteryLevelFromHfp(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); } deviceProperties.setBatteryLevel(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); int newBatteryLevel = deviceProperties.getBatteryLevel(); if (prevBatteryLevel == newBatteryLevel) { debugLog("Battery level was not changed due to reset, device=" + device); return; } sendBatteryLevelChangedBroadcast(device, BluetoothDevice.BATTERY_LEVEL_UNKNOWN); Log.d(TAG, "Reset battery level, device=" + device); sendBatteryLevelChangedBroadcast(device, newBatteryLevel); Log.d(TAG, "Updated device " + device + " battery level to " + newBatteryLevel + "%"); } private void sendBatteryLevelChangedBroadcast(BluetoothDevice device, int batteryLevel) { Loading Loading @@ -1151,7 +1183,7 @@ final class RemoteDevices { && transportLinkType == BluetoothDevice.TRANSPORT_LE) { batteryService.disconnect(device); } resetBatteryLevel(device); resetBatteryLevel(device, /*isBas=*/ true); } if (mAdapterService.isAllProfilesUnknown(device)) { Loading Loading @@ -1270,7 +1302,7 @@ final class RemoteDevices { if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED) == BluetoothProfile.STATE_DISCONNECTED && !hasBatteryService(device)) { resetBatteryLevel(device); resetBatteryLevel(device, /*isBas=*/ false); } } Loading @@ -1284,7 +1316,7 @@ final class RemoteDevices { int indicatorId = intent.getIntExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_ID, -1); int indicatorValue = intent.getIntExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_VALUE, -1); if (indicatorId == HeadsetHalConstants.HF_INDICATOR_BATTERY_LEVEL_STATUS) { updateBatteryLevel(device, indicatorValue); updateBatteryLevel(device, indicatorValue, /*isBas=*/ false); } } Loading Loading @@ -1329,7 +1361,7 @@ final class RemoteDevices { break; } if (batteryPercent != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { updateBatteryLevel(device, batteryPercent); updateBatteryLevel(device, batteryPercent, /*isBas=*/ false); infoLog("Updated device " + device + " battery level to " + String.valueOf( batteryPercent) + "%"); } Loading Loading @@ -1453,7 +1485,7 @@ final class RemoteDevices { if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED) == BluetoothProfile.STATE_DISCONNECTED && !hasBatteryService(device)) { resetBatteryLevel(device); resetBatteryLevel(device, /*isBas=*/ false); } } Loading @@ -1467,7 +1499,8 @@ final class RemoteDevices { if (intent.hasExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL)) { int batteryLevel = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL, -1); updateBatteryLevel(device, batteryChargeIndicatorToPercentge(batteryLevel)); updateBatteryLevel( device, batteryChargeIndicatorToPercentge(batteryLevel), /*isBas=*/ false); } } Loading android/app/tests/unit/src/com/android/bluetooth/bas/BatteryStateMachineTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -305,7 +305,7 @@ public class BatteryStateMachineTest { } @Test public void testDisconnetResetBatteryLevel() { public void testDisconnectResetBatteryLevel() { allowConnection(true); allowConnectGatt(true); Loading android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java +101 −18 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -121,12 +121,12 @@ public class RemoteDevicesTest { batteryLevel); // Verify that update same battery level for the same device does not trigger intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(any(), anyString(), any()); // Verify that updating battery level to different value triggers the intent again batteryLevel = 15; mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(2)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue()); Loading @@ -147,7 +147,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating with invalid battery level does not trigger the intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, never()).sendBroadcast(any(), anyString(), any()); // Verify that device property stays null after invalid update Loading @@ -164,7 +164,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating invalid battery level does not trigger the intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, never()).sendBroadcast(any(), anyString(), any()); // Verify that device property stays null after invalid update Loading @@ -179,7 +179,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that resetting battery level keeps device property null mRemoteDevices.resetBatteryLevel(mDevice1); mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ false); Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); verifyNoMoreInteractions(mAdapterService); Loading @@ -193,7 +193,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -206,7 +206,7 @@ public class RemoteDevicesTest { // Verify that resetting battery level changes it back to BluetoothDevice // .BATTERY_LEVEL_UNKNOWN mRemoteDevices.resetBatteryLevel(mDevice1); mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ false); // Verify BATTERY_LEVEL_CHANGED intent is sent after first reset verify(mAdapterService, times(2)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); Loading @@ -219,12 +219,12 @@ public class RemoteDevicesTest { BluetoothDevice.BATTERY_LEVEL_UNKNOWN); // Verify no intent is sent after second reset mRemoteDevices.resetBatteryLevel(mDevice1); mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ false); verify(mAdapterService, times(2)).sendBroadcast(any(), anyString(), any()); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(3)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -241,7 +241,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -269,7 +269,7 @@ public class RemoteDevicesTest { BluetoothDevice.BATTERY_LEVEL_UNKNOWN); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(3)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -289,7 +289,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -324,7 +324,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -358,7 +358,7 @@ public class RemoteDevicesTest { mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel()); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(4)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -508,7 +508,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -538,7 +538,7 @@ public class RemoteDevicesTest { BluetoothDevice.BATTERY_LEVEL_UNKNOWN); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(3)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -558,7 +558,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -583,6 +583,89 @@ public class RemoteDevicesTest { verifyNoMoreInteractions(mAdapterService); } @Test public void testUpdateBatteryLevelWithBas_overridesHfpBatteryLevel() { int batteryLevel = 10; int batteryLevel2 = 20; 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, /*fromBas=*/ false); 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 updating battery service overrides hfp battery level mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel2, /*fromBas=*/ true); verify(mAdapterService, times(2)) .sendBroadcast( mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel2, mIntentArgument); // Verify that the battery level isn't reset mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ true); Assert.assertEquals( batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel()); verify(mAdapterService, times(3)) .sendBroadcast( mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); clearBatteryServiceForTesting(oldBatteryService); verifyNoMoreInteractions(mAdapterService); } @Test public void testUpdateBatteryLevelWithSameValue_notSendBroadcast() { 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, /*fromBas=*/ false); 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 updating battery service doesn't send broadcast mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ true); verifyNoMoreInteractions(mAdapterService); // Verify that the battery level isn't reset mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ true); Assert.assertEquals( batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel()); verifyNoMoreInteractions(mAdapterService); clearBatteryServiceForTesting(oldBatteryService); verifyNoMoreInteractions(mAdapterService); } @Test public void testAGIndicatorParser_testCorrectValue() { int batteryLevel = 3; Loading Loading
android/app/src/com/android/bluetooth/bas/BatteryService.java +1 −1 Original line number Diff line number Diff line Loading @@ -442,7 +442,7 @@ public class BatteryService extends ProfileService { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void handleBatteryChanged(BluetoothDevice device, int batteryLevel) { mAdapterService.setBatteryLevel(device, batteryLevel); mAdapterService.setBatteryLevel(device, batteryLevel, /*isBas=*/ true); } private BatteryStateMachine getOrCreateStateMachine(BluetoothDevice device) { Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +3 −3 Original line number Diff line number Diff line Loading @@ -7666,11 +7666,11 @@ public class AdapterService extends Service { } /** Sets the battery level of the remote device */ public void setBatteryLevel(BluetoothDevice device, int batteryLevel) { public void setBatteryLevel(BluetoothDevice device, int batteryLevel, boolean isBas) { if (batteryLevel == BATTERY_LEVEL_UNKNOWN) { mRemoteDevices.resetBatteryLevel(device); mRemoteDevices.resetBatteryLevel(device, isBas); } else { mRemoteDevices.updateBatteryLevel(device, batteryLevel); mRemoteDevices.updateBatteryLevel(device, batteryLevel, isBas); } } Loading
android/app/src/com/android/bluetooth/btservice/RemoteDevices.java +70 −37 Original line number Diff line number Diff line Loading @@ -323,7 +323,8 @@ final class RemoteDevices { private String mAlias; private BluetoothDevice mDevice; private boolean mIsBondingInitiatedLocally; private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private int mBatteryLevelFromHfp = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private int mBatteryLevelFromBatteryService = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; private boolean mIsCoordinatedSetMember; private int mAshaCapability; private int mAshaTruncatedHiSyncId; Loading Loading @@ -613,16 +614,28 @@ final class RemoteDevices { */ int getBatteryLevel() { synchronized (mObject) { return mBatteryLevel; if (mBatteryLevelFromBatteryService != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { return mBatteryLevelFromBatteryService; } return mBatteryLevelFromHfp; } } /** * @param batteryLevel the mBatteryLevel to set */ void setBatteryLevel(int batteryLevel) { void setBatteryLevelFromHfp(int batteryLevel) { synchronized (mObject) { if (mBatteryLevelFromHfp == batteryLevel) { return; } mBatteryLevelFromHfp = batteryLevel; } } void setBatteryLevelFromBatteryService(int batteryLevel) { synchronized (mObject) { this.mBatteryLevel = batteryLevel; if (mBatteryLevelFromBatteryService == batteryLevel) { return; } mBatteryLevelFromBatteryService = batteryLevel; } } Loading Loading @@ -740,40 +753,53 @@ final class RemoteDevices { /** * Update battery level in device properties * * @param device The remote device to be updated * @param batteryLevel Battery level Indicator between 0-100, * {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} is error * @param batteryLevel Battery level Indicator between 0-100, {@link * BluetoothDevice#BATTERY_LEVEL_UNKNOWN} is error * @param isBas true if the battery level is from the battery service */ @VisibleForTesting void updateBatteryLevel(BluetoothDevice device, int batteryLevel) { void updateBatteryLevel(BluetoothDevice device, int batteryLevel, boolean isBas) { if (device == null || batteryLevel < 0 || batteryLevel > 100) { warnLog("Invalid parameters device=" + String.valueOf(device == null) + ", batteryLevel=" + String.valueOf(batteryLevel)); warnLog( "Invalid parameters device=" + String.valueOf(device == null) + ", batteryLevel=" + String.valueOf(batteryLevel)); return; } DeviceProperties deviceProperties = getDeviceProperties(device); if (deviceProperties == null) { deviceProperties = addDeviceProperties(Utils.getByteAddress(device)); } synchronized (mObject) { int currentBatteryLevel = deviceProperties.getBatteryLevel(); if (batteryLevel == currentBatteryLevel) { debugLog("Same battery level for device " + device + " received " + String.valueOf( batteryLevel) + "%"); return; int prevBatteryLevel = deviceProperties.getBatteryLevel(); if (isBas) { deviceProperties.setBatteryLevelFromBatteryService(batteryLevel); } else { deviceProperties.setBatteryLevelFromHfp(batteryLevel); } deviceProperties.setBatteryLevel(batteryLevel); int newBatteryLevel = deviceProperties.getBatteryLevel(); if (prevBatteryLevel == newBatteryLevel) { debugLog( "Same battery level for device " + device + " received " + String.valueOf(batteryLevel) + "%"); return; } sendBatteryLevelChangedBroadcast(device, batteryLevel); Log.d(TAG, "Updated device " + device + " battery level to " + batteryLevel + "%"); sendBatteryLevelChangedBroadcast(device, newBatteryLevel); Log.d(TAG, "Updated device " + device + " battery level to " + newBatteryLevel + "%"); } /** * Reset battery level property to {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN} for a device * * @param device device whose battery level property needs to be reset */ @VisibleForTesting void resetBatteryLevel(BluetoothDevice device) { void resetBatteryLevel(BluetoothDevice device, boolean isBas) { if (device == null) { warnLog("Device is null"); return; Loading @@ -782,15 +808,21 @@ final class RemoteDevices { if (deviceProperties == null) { return; } synchronized (mObject) { if (deviceProperties.getBatteryLevel() == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { debugLog("Battery level was never set or is already reset, device=" + device); return; int prevBatteryLevel = deviceProperties.getBatteryLevel(); if (isBas) { deviceProperties.setBatteryLevelFromBatteryService( BluetoothDevice.BATTERY_LEVEL_UNKNOWN); } else { deviceProperties.setBatteryLevelFromHfp(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); } deviceProperties.setBatteryLevel(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); int newBatteryLevel = deviceProperties.getBatteryLevel(); if (prevBatteryLevel == newBatteryLevel) { debugLog("Battery level was not changed due to reset, device=" + device); return; } sendBatteryLevelChangedBroadcast(device, BluetoothDevice.BATTERY_LEVEL_UNKNOWN); Log.d(TAG, "Reset battery level, device=" + device); sendBatteryLevelChangedBroadcast(device, newBatteryLevel); Log.d(TAG, "Updated device " + device + " battery level to " + newBatteryLevel + "%"); } private void sendBatteryLevelChangedBroadcast(BluetoothDevice device, int batteryLevel) { Loading Loading @@ -1151,7 +1183,7 @@ final class RemoteDevices { && transportLinkType == BluetoothDevice.TRANSPORT_LE) { batteryService.disconnect(device); } resetBatteryLevel(device); resetBatteryLevel(device, /*isBas=*/ true); } if (mAdapterService.isAllProfilesUnknown(device)) { Loading Loading @@ -1270,7 +1302,7 @@ final class RemoteDevices { if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED) == BluetoothProfile.STATE_DISCONNECTED && !hasBatteryService(device)) { resetBatteryLevel(device); resetBatteryLevel(device, /*isBas=*/ false); } } Loading @@ -1284,7 +1316,7 @@ final class RemoteDevices { int indicatorId = intent.getIntExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_ID, -1); int indicatorValue = intent.getIntExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_VALUE, -1); if (indicatorId == HeadsetHalConstants.HF_INDICATOR_BATTERY_LEVEL_STATUS) { updateBatteryLevel(device, indicatorValue); updateBatteryLevel(device, indicatorValue, /*isBas=*/ false); } } Loading Loading @@ -1329,7 +1361,7 @@ final class RemoteDevices { break; } if (batteryPercent != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { updateBatteryLevel(device, batteryPercent); updateBatteryLevel(device, batteryPercent, /*isBas=*/ false); infoLog("Updated device " + device + " battery level to " + String.valueOf( batteryPercent) + "%"); } Loading Loading @@ -1453,7 +1485,7 @@ final class RemoteDevices { if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED) == BluetoothProfile.STATE_DISCONNECTED && !hasBatteryService(device)) { resetBatteryLevel(device); resetBatteryLevel(device, /*isBas=*/ false); } } Loading @@ -1467,7 +1499,8 @@ final class RemoteDevices { if (intent.hasExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL)) { int batteryLevel = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL, -1); updateBatteryLevel(device, batteryChargeIndicatorToPercentge(batteryLevel)); updateBatteryLevel( device, batteryChargeIndicatorToPercentge(batteryLevel), /*isBas=*/ false); } } Loading
android/app/tests/unit/src/com/android/bluetooth/bas/BatteryStateMachineTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -305,7 +305,7 @@ public class BatteryStateMachineTest { } @Test public void testDisconnetResetBatteryLevel() { public void testDisconnectResetBatteryLevel() { allowConnection(true); allowConnectGatt(true); Loading
android/app/tests/unit/src/com/android/bluetooth/btservice/RemoteDevicesTest.java +101 −18 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -121,12 +121,12 @@ public class RemoteDevicesTest { batteryLevel); // Verify that update same battery level for the same device does not trigger intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(any(), anyString(), any()); // Verify that updating battery level to different value triggers the intent again batteryLevel = 15; mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(2)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); Assert.assertEquals(BLUETOOTH_CONNECT, mStringArgument.getValue()); Loading @@ -147,7 +147,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating with invalid battery level does not trigger the intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, never()).sendBroadcast(any(), anyString(), any()); // Verify that device property stays null after invalid update Loading @@ -164,7 +164,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating invalid battery level does not trigger the intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, never()).sendBroadcast(any(), anyString(), any()); // Verify that device property stays null after invalid update Loading @@ -179,7 +179,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that resetting battery level keeps device property null mRemoteDevices.resetBatteryLevel(mDevice1); mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ false); Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); verifyNoMoreInteractions(mAdapterService); Loading @@ -193,7 +193,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -206,7 +206,7 @@ public class RemoteDevicesTest { // Verify that resetting battery level changes it back to BluetoothDevice // .BATTERY_LEVEL_UNKNOWN mRemoteDevices.resetBatteryLevel(mDevice1); mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ false); // Verify BATTERY_LEVEL_CHANGED intent is sent after first reset verify(mAdapterService, times(2)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); Loading @@ -219,12 +219,12 @@ public class RemoteDevicesTest { BluetoothDevice.BATTERY_LEVEL_UNKNOWN); // Verify no intent is sent after second reset mRemoteDevices.resetBatteryLevel(mDevice1); mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ false); verify(mAdapterService, times(2)).sendBroadcast(any(), anyString(), any()); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(3)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -241,7 +241,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -269,7 +269,7 @@ public class RemoteDevicesTest { BluetoothDevice.BATTERY_LEVEL_UNKNOWN); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(3)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -289,7 +289,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -324,7 +324,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -358,7 +358,7 @@ public class RemoteDevicesTest { mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel()); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(4)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -508,7 +508,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading Loading @@ -538,7 +538,7 @@ public class RemoteDevicesTest { BluetoothDevice.BATTERY_LEVEL_UNKNOWN); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent again mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService, times(3)).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -558,7 +558,7 @@ public class RemoteDevicesTest { Assert.assertNull(mRemoteDevices.getDeviceProperties(mDevice1)); // Verify that updating battery level triggers ACTION_BATTERY_LEVEL_CHANGED intent mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel); mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ false); verify(mAdapterService).sendBroadcast(mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); Loading @@ -583,6 +583,89 @@ public class RemoteDevicesTest { verifyNoMoreInteractions(mAdapterService); } @Test public void testUpdateBatteryLevelWithBas_overridesHfpBatteryLevel() { int batteryLevel = 10; int batteryLevel2 = 20; 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, /*fromBas=*/ false); 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 updating battery service overrides hfp battery level mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel2, /*fromBas=*/ true); verify(mAdapterService, times(2)) .sendBroadcast( mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel2, mIntentArgument); // Verify that the battery level isn't reset mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ true); Assert.assertEquals( batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel()); verify(mAdapterService, times(3)) .sendBroadcast( mIntentArgument.capture(), mStringArgument.capture(), any(Bundle.class)); verifyBatteryLevelChangedIntent(mDevice1, batteryLevel, mIntentArgument); clearBatteryServiceForTesting(oldBatteryService); verifyNoMoreInteractions(mAdapterService); } @Test public void testUpdateBatteryLevelWithSameValue_notSendBroadcast() { 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, /*fromBas=*/ false); 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 updating battery service doesn't send broadcast mRemoteDevices.updateBatteryLevel(mDevice1, batteryLevel, /*fromBas=*/ true); verifyNoMoreInteractions(mAdapterService); // Verify that the battery level isn't reset mRemoteDevices.resetBatteryLevel(mDevice1, /*fromBas=*/ true); Assert.assertEquals( batteryLevel, mRemoteDevices.getDeviceProperties(mDevice1).getBatteryLevel()); verifyNoMoreInteractions(mAdapterService); clearBatteryServiceForTesting(oldBatteryService); verifyNoMoreInteractions(mAdapterService); } @Test public void testAGIndicatorParser_testCorrectValue() { int batteryLevel = 3; Loading