1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib.fuelgague 18 19 import android.content.Context 20 import android.content.Intent 21 import android.os.BatteryManager 22 import android.os.BatteryManager.BATTERY_PLUGGED_AC 23 import android.os.BatteryManager.BATTERY_PLUGGED_DOCK 24 import android.os.BatteryManager.BATTERY_PLUGGED_USB 25 import android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS 26 import android.os.BatteryManager.BATTERY_STATUS_FULL 27 import android.os.BatteryManager.BATTERY_STATUS_UNKNOWN 28 import android.os.BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE 29 import android.os.BatteryManager.CHARGING_POLICY_DEFAULT 30 import android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT 31 import android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE 32 import android.os.OsProtoEnums.BATTERY_PLUGGED_NONE 33 import androidx.test.core.app.ApplicationProvider 34 import androidx.test.ext.junit.runners.AndroidJUnit4 35 import com.android.settingslib.fuelgauge.BatteryStatus 36 import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_FAST 37 import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_REGULAR 38 import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_SLOWLY 39 import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_UNKNOWN 40 import com.android.settingslib.fuelgauge.BatteryStatus.isBatteryDefender 41 import com.google.common.truth.Truth.assertThat 42 import com.google.common.truth.Truth.assertWithMessage 43 import java.util.Optional 44 import org.junit.Test 45 import org.junit.runner.RunWith 46 import org.junit.runners.Parameterized 47 import org.junit.runners.Suite 48 import org.junit.runners.Suite.SuiteClasses 49 50 @RunWith(Suite::class) 51 @SuiteClasses( 52 BatteryStatusTest.NonParameterizedTest::class, 53 BatteryStatusTest.IsPluggedInTest::class, 54 BatteryStatusTest.IsChargedTest::class, 55 BatteryStatusTest.GetChargingSpeedTest::class, 56 BatteryStatusTest.IsPluggedInDockTest::class, 57 ) 58 open class BatteryStatusTest { 59 60 @RunWith(AndroidJUnit4::class) 61 class NonParameterizedTest : BatteryStatusTest() { 62 @Test 63 fun isLowBattery_20Percent_returnsTrue() { 64 val level = 20 65 val intent = createIntent(batteryLevel = level) 66 67 assertWithMessage("failed by isLowBattery(Intent), level=$level") 68 .that(BatteryStatus.isLowBattery(intent)) 69 .isTrue() 70 assertWithMessage("failed by isLowBattery($level)") 71 .that(BatteryStatus.isLowBattery(level)) 72 .isTrue() 73 } 74 75 @Test 76 fun isLowBattery_21Percent_returnsFalse() { 77 val level = 21 78 val intent = createIntent(batteryLevel = level) 79 80 assertWithMessage("failed by isLowBattery(intent), level=$level") 81 .that(BatteryStatus.isLowBattery(intent)) 82 .isFalse() 83 assertWithMessage("failed by isLowBattery($level)") 84 .that(BatteryStatus.isLowBattery(intent)) 85 .isFalse() 86 } 87 88 @Test 89 fun isSevereLowBattery_10Percent_returnsTrue() { 90 val batteryChangedIntent = createIntent(batteryLevel = 10) 91 92 assertThat(BatteryStatus.isSevereLowBattery(batteryChangedIntent)).isTrue() 93 } 94 95 @Test 96 fun isSevereLowBattery_11Percent_returnFalse() { 97 val batteryChangedIntent = createIntent(batteryLevel = 11) 98 99 assertThat(BatteryStatus.isSevereLowBattery(batteryChangedIntent)).isFalse() 100 } 101 102 @Test 103 fun isExtremeLowBattery_3Percent_returnsTrue() { 104 val batteryChangedIntent = createIntent(batteryLevel = 3) 105 106 assertThat(BatteryStatus.isExtremeLowBattery(batteryChangedIntent)).isTrue() 107 } 108 109 @Test 110 fun isExtremeLowBattery_4Percent_returnsFalse() { 111 val batteryChangedIntent = createIntent(batteryLevel = 4) 112 113 assertThat(BatteryStatus.isExtremeLowBattery(batteryChangedIntent)).isFalse() 114 } 115 116 @Test 117 fun isBatteryDefender_chargingLongLife_returnsTrue() { 118 val chargingStatus = CHARGING_POLICY_ADAPTIVE_LONGLIFE 119 val batteryChangedIntent = createIntent(chargingStatus = chargingStatus) 120 121 assertIsBatteryDefender(chargingStatus, batteryChangedIntent).isTrue() 122 } 123 124 @Test 125 fun isBatteryDefender_nonChargingLongLife_returnsFalse() { 126 val chargingStatus = CHARGING_POLICY_DEFAULT 127 val batteryChangedIntent = createIntent(chargingStatus = chargingStatus) 128 129 assertIsBatteryDefender(chargingStatus, batteryChangedIntent).isFalse() 130 } 131 132 private fun assertIsBatteryDefender(chargingStatus: Int, batteryChangedIntent: Intent) = 133 object { 134 val assertions = 135 listOf( 136 "failed by isBatteryDefender(Intent), chargingStatus=$chargingStatus".let { 137 assertWithMessage(it).that(isBatteryDefender(batteryChangedIntent)) 138 }, 139 "failed by isBatteryDefender($chargingStatus)".let { 140 assertWithMessage(it).that(isBatteryDefender(chargingStatus)) 141 }, 142 ) 143 144 fun isTrue() = assertions.forEach { it.isTrue() } 145 146 fun isFalse() = assertions.forEach { it.isFalse() } 147 } 148 } 149 150 @RunWith(Parameterized::class) 151 class IsPluggedInTest( 152 private val name: String, 153 private val plugged: Int, 154 val expected: Boolean 155 ) : BatteryStatusTest() { 156 157 @Test 158 fun isPluggedIn_() { 159 val batteryChangedIntent = createIntent(plugged = plugged) 160 161 assertWithMessage("failed by isPluggedIn(plugged=$plugged)") 162 .that(BatteryStatus.isPluggedIn(plugged)) 163 .isEqualTo(expected) 164 assertWithMessage("failed by isPlugged(Intent), which plugged=$plugged") 165 .that(BatteryStatus.isPluggedIn(batteryChangedIntent)) 166 .isEqualTo(expected) 167 } 168 169 companion object { 170 @Parameterized.Parameters(name = "{0}") 171 @JvmStatic 172 fun parameters() = 173 arrayListOf( 174 arrayOf("withAC_returnsTrue", BATTERY_PLUGGED_AC, true), 175 arrayOf("withDock_returnsTrue", BATTERY_PLUGGED_DOCK, true), 176 arrayOf("withUSB_returnsTrue", BATTERY_PLUGGED_USB, true), 177 arrayOf("withWireless_returnsTrue", BATTERY_PLUGGED_WIRELESS, true), 178 arrayOf("pluggedNone_returnsTrue", BATTERY_PLUGGED_NONE, false), 179 ) 180 } 181 } 182 183 @RunWith(Parameterized::class) 184 class IsPluggedInDockTest( 185 private val name: String, 186 private val plugged: Int, 187 val expected: Boolean 188 ) : BatteryStatusTest() { 189 190 @Test 191 fun isPluggedDockIn_() { 192 val batteryChangedIntent = createIntent(plugged = plugged) 193 194 assertWithMessage("failed by isPluggedInDock(plugged=$plugged)") 195 .that(BatteryStatus.isPluggedInDock(plugged)) 196 .isEqualTo(expected) 197 assertWithMessage("failed by isPluggedInDock(Intent), which plugged=$plugged") 198 .that(BatteryStatus.isPluggedInDock(batteryChangedIntent)) 199 .isEqualTo(expected) 200 } 201 202 companion object { 203 @Parameterized.Parameters(name = "{0}") 204 @JvmStatic 205 fun parameters() = 206 arrayListOf( 207 arrayOf("withAC_returnsTrue", BATTERY_PLUGGED_AC, false), 208 arrayOf("withDock_returnsTrue", BATTERY_PLUGGED_DOCK, true), 209 arrayOf("withUSB_returnsTrue", BATTERY_PLUGGED_USB, false), 210 arrayOf("withWireless_returnsTrue", BATTERY_PLUGGED_WIRELESS, false), 211 arrayOf("pluggedNone_returnsTrue", BATTERY_PLUGGED_NONE, false), 212 ) 213 } 214 } 215 216 @RunWith(Parameterized::class) 217 class IsChargedTest( 218 private val status: Int, 219 private val batteryLevel: Int, 220 private val expected: Boolean 221 ) : BatteryStatusTest() { 222 223 @Test 224 fun isCharged_() { 225 val batteryChangedIntent = createIntent(batteryLevel = batteryLevel, status = status) 226 227 assertWithMessage( 228 "failed by isCharged(Intent), status=$status, batteryLevel=$batteryLevel" 229 ) 230 .that(BatteryStatus.isCharged(batteryChangedIntent)) 231 .isEqualTo(expected) 232 assertWithMessage("failed by isCharged($status, $batteryLevel)") 233 .that(BatteryStatus.isCharged(status, batteryLevel)) 234 .isEqualTo(expected) 235 } 236 237 companion object { 238 @Parameterized.Parameters(name = "status{0}_level{1}_returns-{2}") 239 @JvmStatic 240 fun parameters() = 241 arrayListOf( 242 arrayOf(BATTERY_STATUS_FULL, 99, true), 243 arrayOf(BATTERY_STATUS_UNKNOWN, 100, true), 244 arrayOf(BATTERY_STATUS_FULL, 100, true), 245 arrayOf(BATTERY_STATUS_UNKNOWN, 99, false), 246 ) 247 } 248 } 249 250 @RunWith(Parameterized::class) 251 class GetChargingSpeedTest( 252 private val name: String, 253 private val maxChargingCurrent: Optional<Int>, 254 private val maxChargingVoltage: Optional<Int>, 255 private val expectedChargingSpeed: Int, 256 ) { 257 258 val context: Context = ApplicationProvider.getApplicationContext() 259 260 @Test 261 fun getChargingSpeed_() { 262 val batteryChangedIntent = 263 Intent(Intent.ACTION_BATTERY_CHANGED).apply { 264 maxChargingCurrent.ifPresent { putExtra(EXTRA_MAX_CHARGING_CURRENT, it) } 265 maxChargingVoltage.ifPresent { putExtra(EXTRA_MAX_CHARGING_VOLTAGE, it) } 266 } 267 268 assertThat(BatteryStatus.getChargingSpeed(context, batteryChangedIntent)) 269 .isEqualTo(expectedChargingSpeed) 270 } 271 272 companion object { 273 @Parameterized.Parameters(name = "{0}") 274 @JvmStatic 275 fun parameters() = 276 arrayListOf( 277 arrayOf( 278 "maxCurrent=n/a, maxVoltage=n/a -> UNKNOWN", 279 Optional.empty<Int>(), 280 Optional.empty<Int>(), 281 CHARGING_UNKNOWN 282 ), 283 arrayOf( 284 "maxCurrent=0, maxVoltage=9000000 -> UNKNOWN", 285 Optional.of(0), 286 Optional.of(0), 287 CHARGING_UNKNOWN 288 ), 289 arrayOf( 290 "maxCurrent=1500000, maxVoltage=5000000 -> CHARGING_REGULAR", 291 Optional.of(1500000), 292 Optional.of(5000000), 293 CHARGING_REGULAR 294 ), 295 arrayOf( 296 "maxCurrent=1000000, maxVoltage=5000000 -> CHARGING_REGULAR", 297 Optional.of(1000000), 298 Optional.of(5000000), 299 CHARGING_REGULAR 300 ), 301 arrayOf( 302 "maxCurrent=1500001, maxVoltage=5000000 -> CHARGING_FAST", 303 Optional.of(1501000), 304 Optional.of(5000000), 305 CHARGING_FAST 306 ), 307 arrayOf( 308 "maxCurrent=999999, maxVoltage=5000000 -> CHARGING_SLOWLY", 309 Optional.of(999999), 310 Optional.of(5000000), 311 CHARGING_SLOWLY 312 ), 313 ) 314 } 315 } 316 317 protected fun createIntent( 318 batteryLevel: Int = 50, 319 chargingStatus: Int = CHARGING_POLICY_DEFAULT, 320 plugged: Int = BATTERY_PLUGGED_NONE, 321 status: Int = BatteryManager.BATTERY_STATUS_CHARGING, 322 ): Intent = 323 Intent(Intent.ACTION_BATTERY_CHANGED).apply { 324 putExtra(BatteryManager.EXTRA_STATUS, status) 325 putExtra(BatteryManager.EXTRA_LEVEL, batteryLevel) 326 putExtra(BatteryManager.EXTRA_SCALE, 100) 327 putExtra(BatteryManager.EXTRA_CHARGING_STATUS, chargingStatus) 328 putExtra(BatteryManager.EXTRA_PLUGGED, plugged) 329 } 330 } 331