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

Commit 6e133007 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "event-framework" into udc-qpr-dev

* changes:
  [BatteryEventFramework] Implement getChargingSpeed function
  [BatteryEventFramework] Implement static util function in BatteryStatus
parents 08a2e18e 28c6ad8a
Loading
Loading
Loading
Loading
+130 −19
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static android.os.BatteryManager.EXTRA_PRESENT;
import static android.os.BatteryManager.EXTRA_STATUS;
import static android.os.OsProtoEnums.BATTERY_PLUGGED_NONE;

import android.content.Context;
import android.content.Intent;
@@ -40,6 +41,8 @@ import java.util.Optional;
 */
public class BatteryStatus {
    private static final int LOW_BATTERY_THRESHOLD = 20;
    private static final int SEVERE_LOW_BATTERY_THRESHOLD = 10;
    private static final int EXTREME_LOW_BATTERY_THRESHOLD = 3;
    private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;

    public static final int CHARGING_UNKNOWN = -1;
@@ -90,21 +93,7 @@ public class BatteryStatus {
        present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true);
        this.incompatibleCharger = incompatibleCharger;

        final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT,
                -1);
        int maxChargingMicroVolt = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1);

        if (maxChargingMicroVolt <= 0) {
            maxChargingMicroVolt = DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT;
        }
        if (maxChargingMicroAmp > 0) {
            // Calculating muW = muA * muV / (10^6 mu^2 / mu); splitting up the divisor
            // to maintain precision equally on both factors.
            maxChargingWattage = (maxChargingMicroAmp / 1000)
                    * (maxChargingMicroVolt / 1000);
        } else {
            maxChargingWattage = -1;
        }
        maxChargingWattage = calculateMaxChargingMicroWatt(batteryChangedIntent);
    }

    /** Determine whether the device is plugged. */
@@ -126,7 +115,7 @@ public class BatteryStatus {

    /** Determine whether the device is plugged in dock. */
    public boolean isPluggedInDock() {
        return plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
        return isPluggedInDock(plugged);
    }

    /**
@@ -140,15 +129,15 @@ public class BatteryStatus {

    /** Whether battery is low and needs to be charged. */
    public boolean isBatteryLow() {
        return level < LOW_BATTERY_THRESHOLD;
        return isLowBattery(level);
    }

    /** Whether battery defender is enabled. */
    public boolean isBatteryDefender() {
        return chargingStatus == CHARGING_POLICY_ADAPTIVE_LONGLIFE;
        return isBatteryDefender(chargingStatus);
    }

    /** Return current chargin speed is fast, slow or normal. */
    /** Return current charging speed is fast, slow or normal. */
    public final int getChargingSpeed(Context context) {
        final int slowThreshold = context.getResources().getInteger(
                R.integer.config_chargingSlowlyThreshold);
@@ -218,4 +207,126 @@ public class BatteryStatus {
                || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
                || plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
    }

    /** Determine whether the device is plugged in dock. */
    public static boolean isPluggedInDock(Intent batteryChangedIntent) {
        return isPluggedInDock(
                batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, BATTERY_PLUGGED_NONE));
    }

    /** Determine whether the device is plugged in dock. */
    public static boolean isPluggedInDock(int plugged) {
        return plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
    }

    /**
     * Whether the battery is low or not.
     *
     * @param batteryChangedIntent the {@link ACTION_BATTERY_CHANGED} intent
     * @return {@code true} if the battery level is less or equal to {@link LOW_BATTERY_THRESHOLD}
     */
    public static boolean isLowBattery(Intent batteryChangedIntent) {
        int level = getBatteryLevel(batteryChangedIntent);
        return isLowBattery(level);
    }

    /**
     * Whether the battery is low or not.
     *
     * @param batteryLevel the battery level
     * @return {@code true} if the battery level is less or equal to {@link LOW_BATTERY_THRESHOLD}
     */
    public static boolean isLowBattery(int batteryLevel) {
        return batteryLevel <= LOW_BATTERY_THRESHOLD;
    }

    /**
     * Whether the battery is severe low or not.
     *
     * @param batteryChangedIntent the ACTION_BATTERY_CHANGED intent
     * @return {@code true} if the battery level is less or equal to {@link
     *     SEVERE_LOW_BATTERY_THRESHOLD}
     */
    public static boolean isSevereLowBattery(Intent batteryChangedIntent) {
        int level = getBatteryLevel(batteryChangedIntent);
        return level <= SEVERE_LOW_BATTERY_THRESHOLD;
    }

    /**
     * Whether the battery is extreme low or not.
     *
     * @param batteryChangedIntent the ACTION_BATTERY_CHANGED intent
     * @return {@code true} if the battery level is less or equal to {@link
     *     EXTREME_LOW_BATTERY_THRESHOLD}
     */
    public static boolean isExtremeLowBattery(Intent batteryChangedIntent) {
        int level = getBatteryLevel(batteryChangedIntent);
        return level <= EXTREME_LOW_BATTERY_THRESHOLD;
    }

    /**
     * Whether the battery defender is enabled or not.
     *
     * @param batteryChangedIntent the ACTION_BATTERY_CHANGED intent
     * @return {@code true} if the battery defender is enabled. It could be dock defend, dwell
     *     defend, or temp defend
     */
    public static boolean isBatteryDefender(Intent batteryChangedIntent) {
        int chargingStatus =
                batteryChangedIntent.getIntExtra(EXTRA_CHARGING_STATUS, CHARGING_POLICY_DEFAULT);
        return isBatteryDefender(chargingStatus);
    }

    /**
     * Whether the battery defender is enabled or not.
     *
     * @param chargingStatus for {@link EXTRA_CHARGING_STATUS} field in the ACTION_BATTERY_CHANGED
     *     intent
     * @return {@code true} if the battery defender is enabled. It could be dock defend, dwell
     *     defend, or temp defend
     */
    public static boolean isBatteryDefender(int chargingStatus) {
        return chargingStatus == CHARGING_POLICY_ADAPTIVE_LONGLIFE;
    }

    /**
     * Gets the max charging current and max charging voltage form {@link
     * Intent.ACTION_BATTERY_CHANGED} and calculates the charging speed based on the {@link
     * R.integer.config_chargingSlowlyThreshold} and {@link R.integer.config_chargingFastThreshold}.
     *
     * @param context the application context
     * @param batteryChangedIntent the intent from {@link Intent.ACTION_BATTERY_CHANGED}
     * @return the charging speed. {@link CHARGING_REGULAR}, {@link CHARGING_FAST}, {@link
     *     CHARGING_SLOWLY} or {@link CHARGING_UNKNOWN}
     */
    public static int getChargingSpeed(Context context, Intent batteryChangedIntent) {
        final int maxChargingMicroWatt = calculateMaxChargingMicroWatt(batteryChangedIntent);
        if (maxChargingMicroWatt <= 0) {
            return CHARGING_UNKNOWN;
        } else if (maxChargingMicroWatt
                < context.getResources().getInteger(R.integer.config_chargingSlowlyThreshold)) {
            return CHARGING_SLOWLY;
        } else if (maxChargingMicroWatt
                > context.getResources().getInteger(R.integer.config_chargingFastThreshold)) {
            return CHARGING_FAST;
        } else {
            return CHARGING_REGULAR;
        }
    }

    private static int calculateMaxChargingMicroWatt(Intent batteryChangedIntent) {
        final int maxChargingMicroAmp =
                batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1);
        int maxChargingMicroVolt = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1);
        if (maxChargingMicroVolt <= 0) {
            maxChargingMicroVolt = DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT;
        }

        if (maxChargingMicroAmp > 0) {
            // Calculating µW = mA * mV
            return (int) Math.round(maxChargingMicroAmp * 0.001 * maxChargingMicroVolt * 0.001);
        } else {
            return -1;
        }
    }
}
+330 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.fuelgague

import android.content.Context
import android.content.Intent
import android.os.BatteryManager
import android.os.BatteryManager.BATTERY_PLUGGED_AC
import android.os.BatteryManager.BATTERY_PLUGGED_DOCK
import android.os.BatteryManager.BATTERY_PLUGGED_USB
import android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS
import android.os.BatteryManager.BATTERY_STATUS_FULL
import android.os.BatteryManager.BATTERY_STATUS_UNKNOWN
import android.os.BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE
import android.os.BatteryManager.CHARGING_POLICY_DEFAULT
import android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT
import android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE
import android.os.OsProtoEnums.BATTERY_PLUGGED_NONE
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.fuelgauge.BatteryStatus
import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_FAST
import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_REGULAR
import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_SLOWLY
import com.android.settingslib.fuelgauge.BatteryStatus.CHARGING_UNKNOWN
import com.android.settingslib.fuelgauge.BatteryStatus.isBatteryDefender
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.Optional
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Suite
import org.junit.runners.Suite.SuiteClasses

@RunWith(Suite::class)
@SuiteClasses(
    BatteryStatusTest.NonParameterizedTest::class,
    BatteryStatusTest.IsPluggedInTest::class,
    BatteryStatusTest.IsChargedTest::class,
    BatteryStatusTest.GetChargingSpeedTest::class,
    BatteryStatusTest.IsPluggedInDockTest::class,
)
open class BatteryStatusTest {

    @RunWith(AndroidJUnit4::class)
    class NonParameterizedTest : BatteryStatusTest() {
        @Test
        fun isLowBattery_20Percent_returnsTrue() {
            val level = 20
            val intent = createIntent(batteryLevel = level)

            assertWithMessage("failed by isLowBattery(Intent), level=$level")
                .that(BatteryStatus.isLowBattery(intent))
                .isTrue()
            assertWithMessage("failed by isLowBattery($level)")
                .that(BatteryStatus.isLowBattery(level))
                .isTrue()
        }

        @Test
        fun isLowBattery_21Percent_returnsFalse() {
            val level = 21
            val intent = createIntent(batteryLevel = level)

            assertWithMessage("failed by isLowBattery(intent), level=$level")
                .that(BatteryStatus.isLowBattery(intent))
                .isFalse()
            assertWithMessage("failed by isLowBattery($level)")
                .that(BatteryStatus.isLowBattery(intent))
                .isFalse()
        }

        @Test
        fun isSevereLowBattery_10Percent_returnsTrue() {
            val batteryChangedIntent = createIntent(batteryLevel = 10)

            assertThat(BatteryStatus.isSevereLowBattery(batteryChangedIntent)).isTrue()
        }

        @Test
        fun isSevereLowBattery_11Percent_returnFalse() {
            val batteryChangedIntent = createIntent(batteryLevel = 11)

            assertThat(BatteryStatus.isSevereLowBattery(batteryChangedIntent)).isFalse()
        }

        @Test
        fun isExtremeLowBattery_3Percent_returnsTrue() {
            val batteryChangedIntent = createIntent(batteryLevel = 3)

            assertThat(BatteryStatus.isExtremeLowBattery(batteryChangedIntent)).isTrue()
        }

        @Test
        fun isExtremeLowBattery_4Percent_returnsFalse() {
            val batteryChangedIntent = createIntent(batteryLevel = 4)

            assertThat(BatteryStatus.isExtremeLowBattery(batteryChangedIntent)).isFalse()
        }

        @Test
        fun isBatteryDefender_chargingLongLife_returnsTrue() {
            val chargingStatus = CHARGING_POLICY_ADAPTIVE_LONGLIFE
            val batteryChangedIntent = createIntent(chargingStatus = chargingStatus)

            assertIsBatteryDefender(chargingStatus, batteryChangedIntent).isTrue()
        }

        @Test
        fun isBatteryDefender_nonChargingLongLife_returnsFalse() {
            val chargingStatus = CHARGING_POLICY_DEFAULT
            val batteryChangedIntent = createIntent(chargingStatus = chargingStatus)

            assertIsBatteryDefender(chargingStatus, batteryChangedIntent).isFalse()
        }

        private fun assertIsBatteryDefender(chargingStatus: Int, batteryChangedIntent: Intent) =
            object {
                val assertions =
                    listOf(
                        "failed by isBatteryDefender(Intent), chargingStatus=$chargingStatus".let {
                            assertWithMessage(it).that(isBatteryDefender(batteryChangedIntent))
                        },
                        "failed by isBatteryDefender($chargingStatus)".let {
                            assertWithMessage(it).that(isBatteryDefender(chargingStatus))
                        },
                    )

                fun isTrue() = assertions.forEach { it.isTrue() }

                fun isFalse() = assertions.forEach { it.isFalse() }
            }
    }

    @RunWith(Parameterized::class)
    class IsPluggedInTest(
        private val name: String,
        private val plugged: Int,
        val expected: Boolean
    ) : BatteryStatusTest() {

        @Test
        fun isPluggedIn_() {
            val batteryChangedIntent = createIntent(plugged = plugged)

            assertWithMessage("failed by isPluggedIn(plugged=$plugged)")
                .that(BatteryStatus.isPluggedIn(plugged))
                .isEqualTo(expected)
            assertWithMessage("failed by isPlugged(Intent), which plugged=$plugged")
                .that(BatteryStatus.isPluggedIn(batteryChangedIntent))
                .isEqualTo(expected)
        }

        companion object {
            @Parameterized.Parameters(name = "{0}")
            @JvmStatic
            fun parameters() =
                arrayListOf(
                    arrayOf("withAC_returnsTrue", BATTERY_PLUGGED_AC, true),
                    arrayOf("withDock_returnsTrue", BATTERY_PLUGGED_DOCK, true),
                    arrayOf("withUSB_returnsTrue", BATTERY_PLUGGED_USB, true),
                    arrayOf("withWireless_returnsTrue", BATTERY_PLUGGED_WIRELESS, true),
                    arrayOf("pluggedNone_returnsTrue", BATTERY_PLUGGED_NONE, false),
                )
        }
    }

    @RunWith(Parameterized::class)
    class IsPluggedInDockTest(
        private val name: String,
        private val plugged: Int,
        val expected: Boolean
    ) : BatteryStatusTest() {

        @Test
        fun isPluggedDockIn_() {
            val batteryChangedIntent = createIntent(plugged = plugged)

            assertWithMessage("failed by isPluggedInDock(plugged=$plugged)")
                .that(BatteryStatus.isPluggedInDock(plugged))
                .isEqualTo(expected)
            assertWithMessage("failed by isPluggedInDock(Intent), which plugged=$plugged")
                .that(BatteryStatus.isPluggedInDock(batteryChangedIntent))
                .isEqualTo(expected)
        }

        companion object {
            @Parameterized.Parameters(name = "{0}")
            @JvmStatic
            fun parameters() =
                arrayListOf(
                    arrayOf("withAC_returnsTrue", BATTERY_PLUGGED_AC, false),
                    arrayOf("withDock_returnsTrue", BATTERY_PLUGGED_DOCK, true),
                    arrayOf("withUSB_returnsTrue", BATTERY_PLUGGED_USB, false),
                    arrayOf("withWireless_returnsTrue", BATTERY_PLUGGED_WIRELESS, false),
                    arrayOf("pluggedNone_returnsTrue", BATTERY_PLUGGED_NONE, false),
                )
        }
    }

    @RunWith(Parameterized::class)
    class IsChargedTest(
        private val status: Int,
        private val batteryLevel: Int,
        private val expected: Boolean
    ) : BatteryStatusTest() {

        @Test
        fun isCharged_() {
            val batteryChangedIntent = createIntent(batteryLevel = batteryLevel, status = status)

            assertWithMessage(
                    "failed by isCharged(Intent), status=$status, batteryLevel=$batteryLevel"
                )
                .that(BatteryStatus.isCharged(batteryChangedIntent))
                .isEqualTo(expected)
            assertWithMessage("failed by isCharged($status, $batteryLevel)")
                .that(BatteryStatus.isCharged(status, batteryLevel))
                .isEqualTo(expected)
        }

        companion object {
            @Parameterized.Parameters(name = "status{0}_level{1}_returns-{2}")
            @JvmStatic
            fun parameters() =
                arrayListOf(
                    arrayOf(BATTERY_STATUS_FULL, 99, true),
                    arrayOf(BATTERY_STATUS_UNKNOWN, 100, true),
                    arrayOf(BATTERY_STATUS_FULL, 100, true),
                    arrayOf(BATTERY_STATUS_UNKNOWN, 99, false),
                )
        }
    }

    @RunWith(Parameterized::class)
    class GetChargingSpeedTest(
        private val name: String,
        private val maxChargingCurrent: Optional<Int>,
        private val maxChargingVoltage: Optional<Int>,
        private val expectedChargingSpeed: Int,
    ) {

        val context: Context = ApplicationProvider.getApplicationContext()

        @Test
        fun getChargingSpeed_() {
            val batteryChangedIntent =
                Intent(Intent.ACTION_BATTERY_CHANGED).apply {
                    maxChargingCurrent.ifPresent { putExtra(EXTRA_MAX_CHARGING_CURRENT, it) }
                    maxChargingVoltage.ifPresent { putExtra(EXTRA_MAX_CHARGING_VOLTAGE, it) }
                }

            assertThat(BatteryStatus.getChargingSpeed(context, batteryChangedIntent))
                .isEqualTo(expectedChargingSpeed)
        }

        companion object {
            @Parameterized.Parameters(name = "{0}")
            @JvmStatic
            fun parameters() =
                arrayListOf(
                    arrayOf(
                        "maxCurrent=n/a, maxVoltage=n/a -> UNKNOWN",
                        Optional.empty<Int>(),
                        Optional.empty<Int>(),
                        CHARGING_UNKNOWN
                    ),
                    arrayOf(
                        "maxCurrent=0, maxVoltage=9000000 -> UNKNOWN",
                        Optional.of(0),
                        Optional.of(0),
                        CHARGING_UNKNOWN
                    ),
                    arrayOf(
                        "maxCurrent=1500000, maxVoltage=5000000 -> CHARGING_REGULAR",
                        Optional.of(1500000),
                        Optional.of(5000000),
                        CHARGING_REGULAR
                    ),
                    arrayOf(
                        "maxCurrent=1000000, maxVoltage=5000000 -> CHARGING_REGULAR",
                        Optional.of(1000000),
                        Optional.of(5000000),
                        CHARGING_REGULAR
                    ),
                    arrayOf(
                        "maxCurrent=1500001, maxVoltage=5000000 -> CHARGING_FAST",
                        Optional.of(1501000),
                        Optional.of(5000000),
                        CHARGING_FAST
                    ),
                    arrayOf(
                        "maxCurrent=999999, maxVoltage=5000000 -> CHARGING_SLOWLY",
                        Optional.of(999999),
                        Optional.of(5000000),
                        CHARGING_SLOWLY
                    ),
                )
        }
    }

    protected fun createIntent(
        batteryLevel: Int = 50,
        chargingStatus: Int = CHARGING_POLICY_DEFAULT,
        plugged: Int = BATTERY_PLUGGED_NONE,
        status: Int = BatteryManager.BATTERY_STATUS_CHARGING,
    ): Intent =
        Intent(Intent.ACTION_BATTERY_CHANGED).apply {
            putExtra(BatteryManager.EXTRA_STATUS, status)
            putExtra(BatteryManager.EXTRA_LEVEL, batteryLevel)
            putExtra(BatteryManager.EXTRA_SCALE, 100)
            putExtra(BatteryManager.EXTRA_CHARGING_STATUS, chargingStatus)
            putExtra(BatteryManager.EXTRA_PLUGGED, plugged)
        }
}