Skip to content

Commit

Permalink
add test for battery()
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed May 6, 2024
1 parent 2410806 commit 1eea76f
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 94 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ d.root()

# adb tcpip <port>
d.tcpip(5555)

print(d.battery())
BatteryInfo(ac_powered=False, usb_powered=False, wireless_powered=False, dock_powered=False, max_charging_current=0, max_charging_voltage=0, charge_counter=10000, status=4, health=2, present=True, level=100, scale=100, voltage=5000, temperature=25.0, technology='Li-ion')
```

Screenrecord (mp4)
Expand Down
43 changes: 22 additions & 21 deletions adbutils/_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import enum
import datetime
import pathlib
import typing
from typing import List, NamedTuple, Optional, Union
from dataclasses import dataclass


Expand Down Expand Up @@ -58,35 +58,36 @@ class FileInfo:
@dataclass
class AppInfo:
package_name: str
version_name: typing.Optional[str]
version_code: typing.Optional[int]
flags: typing.Union[str, list]
version_name: Optional[str]
version_code: Optional[int]
flags: Union[str, list]
first_install_time: datetime.datetime
last_update_time: datetime.datetime
signature: str
path: str
sub_apk_paths: typing.List[str]
sub_apk_paths: List[str]


@dataclass
class BatteryInfo:
ac_powered: bool
usb_powered: bool
wireless_powered: bool
max_charging_current: typing.Optional[int]
max_charging_voltage: typing.Optional[int]
charge_counter: typing.Optional[int]
status: typing.Optional[int]
health: typing.Optional[int]
present: bool
level: typing.Optional[int]
scale: typing.Optional[int]
voltage: typing.Optional[int, float]
temperature: typing.Optional[int, float]
technology: typing.Optional[str]


class WindowSize(typing.NamedTuple):
wireless_powered: Optional[bool]
dock_powered: Optional[bool]
max_charging_current: Optional[int]
max_charging_voltage: Optional[int]
charge_counter: Optional[int]
status: Optional[int]
health: Optional[int]
present: Optional[bool]
level: Optional[int]
scale: Optional[int]
voltage: Optional[int] # mV
temperature: Optional[float] # e.g. 25.0
technology: Optional[str]


class WindowSize(NamedTuple):
width: int
height: int

Expand Down Expand Up @@ -117,4 +118,4 @@ class AdbDeviceInfo:
state: str


StrOrPathLike = typing.Union[str, pathlib.Path]
StrOrPathLike = Union[str, pathlib.Path]
105 changes: 55 additions & 50 deletions adbutils/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,58 +441,64 @@ def dump_hierarchy(self) -> str:
raise AdbError("dump output is not xml", xml_data)
return xml_data

def battery(self) -> Optional[BatteryInfo]:
def battery(self) -> BatteryInfo:
"""
Get battery info
AC powered - Indicates that the device is currently not powered by AC power. If true, it indicates that the device is connected to an AC power adapter.
USB powered - Indicates that the device is currently being powered or charged through the USB interface.
Wireless powered - Indicates that the device is not powered through wireless charging. If wireless charging is supported and currently in use, this will be true.
Max charging current - The maximum charging current supported by the device, usually in microamperes( μ A).
Max charging voltage - The maximum charging voltage supported by the device may be in millivolts (mV).
Charge counter - The cumulative charge count of a battery, usually measured in milliampere hours (mAh)
Status - Battery status code.
Health - Battery health status code.
Present - indicates that the battery is currently detected and installed in the device.
Level - The percentage of current battery level.
Scale - The full scale of the percentage of battery charge, indicating that the battery level is measured using 100 as the standard for full charge.
Voltage - The current voltage of the battery, usually measured in millivolts (mV).
Temperature - Battery temperature, usually measured in degrees Celsius (° C)
Technology - Battery type, like (Li-ion) battery
Returns: BatteryInfo
Returns:
BatteryInfo
Details:
AC powered - Indicates that the device is currently not powered by AC power. If true, it indicates that the device is connected to an AC power adapter.
USB powered - Indicates that the device is currently being powered or charged through the USB interface.
Wireless powered - Indicates that the device is not powered through wireless charging. If wireless charging is supported and currently in use, this will be true.
Max charging current - The maximum charging current supported by the device, usually in microamperes( μ A).
Max charging voltage - The maximum charging voltage supported by the device may be in millivolts (mV).
Charge counter - The cumulative charge count of a battery, usually measured in milliampere hours (mAh)
Status - Battery status code.
Health - Battery health status code.
Present - indicates that the battery is currently detected and installed in the device.
Level - The percentage of current battery level.
Scale - The full scale of the percentage of battery charge, indicating that the battery level is measured using 100 as the standard for full charge.
Voltage - The current voltage of the battery, usually measured in millivolts (mV).
Temperature - Battery temperature, usually measured in degrees Celsius (° C)
Technology - Battery type, like (Li-ion) battery
"""
def to_bool(v: str) -> bool:
return v == "true"

output = self.shell(["dumpsys", "battery"])
m_ac_powered = re.search(r"AC powered: (\w+)", output)
ac_powered_status = m_ac_powered.group(1) if m_ac_powered else None
m_usb_powered = re.search(r"USB powered: (\w+)", output)
usb_powered_status = m_usb_powered.group(1) if m_usb_powered else None
m_wireless_powered = re.search(r"Wireless powered: (\w+)", output)
wireless_powered_status = m_wireless_powered.group(1) if m_wireless_powered else None
m_max_charging_current = re.search(r"Max charging current: (\d+)", output)
max_charging_current = m_max_charging_current.group(1) if m_max_charging_current else None
m_max_charging_voltage = re.search(r"Max charging voltage: (\d+)", output)
max_charging_voltage = m_max_charging_voltage.group(1) if m_max_charging_voltage else None
m_charge_counter = re.search(r"Charge counter: (\d+)", output)
charge_counter = m_charge_counter.group(1) if m_charge_counter else None
m_status = re.search(r"status: (\d+)", output)
status = m_status.group(1) if m_status else None
m_health = re.search(r"health: (\d+)", output)
health = m_health.group(1) if m_health else None
m_present = re.search(r"present: (\w+)", output)
present = m_present.group(1) if m_present else None
m_level = re.search(r"level: (\d+)", output)
level = int(m_level.group(1)) if m_level else None
m_scale = re.search(r"scale: (\d+)", output)
scale = int(m_scale.group(1)) if m_scale else None
m_voltage = re.search(r"voltage: (\d+)", output)
voltage = int(m_scale.group(1)) if m_voltage else None
m_temperature = re.search(r"temperature: (\d+)", output)
temperature = m_temperature.group(1) if m_temperature else None
m_technology = re.search(r"technology: \s*(.*)$", output)
technology = m_technology.group(1).strip() if m_technology else None
battery_info = BatteryInfo(
ac_powered=ac_powered_status,
usb_powered=usb_powered_status,
wireless_powered=wireless_powered_status,
shell_kvs = {}
for line in output.splitlines():
key, val = line.strip().split(':', 1)
shell_kvs[key.strip()] = val.strip()

def get_key(k: str, map_function):
v = shell_kvs.get(k)
if v is not None:
return map_function(v)
return None

ac_powered = get_key("AC powered", to_bool)
usb_powered = get_key("USB powered", to_bool)
wireless_powered = get_key("Wireless powered", to_bool)
dock_powered = get_key("Dock powered", to_bool)
max_charging_current = get_key("Max charging current", int)
max_charging_voltage = get_key("Max charging voltage", int)
charge_counter = get_key("Charge counter", int)
status = get_key("status", int)
health = get_key("health", int)
present = get_key("present", to_bool)
level = get_key("level", int)
scale = get_key("scale", int)
voltage = get_key("voltage", int)
temperature = get_key("temperature", lambda x: int(x) / 10)
technology = shell_kvs.get("technology", str)
return BatteryInfo(
ac_powered=ac_powered,
usb_powered=usb_powered,
wireless_powered=wireless_powered,
dock_powered=dock_powered,
max_charging_current=max_charging_current,
max_charging_voltage=max_charging_voltage,
charge_counter=charge_counter,
Expand All @@ -504,5 +510,4 @@ def battery(self) -> Optional[BatteryInfo]:
voltage=voltage,
temperature=temperature,
technology=technology,
)
return battery_info
)
20 changes: 0 additions & 20 deletions tests/adb_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,27 +94,7 @@ async def host_kill(ctx: Context):
await ctx.server.stop()
# os.kill(os.getpid(), signal.SIGINT)


_DUMPSYS_BATTERY_ = """Current Battery Service state:
AC powered: false
USB powered: false
Wireless powered: false
Dock powered: false
Max charging current: 0
Max charging voltage: 0
Charge counter: 10000
status: 4
health: 2
present: true
level: 90
scale: 100
voltage: 5000
temperature: 250
technology: Li-ion"""


SHELL_OUTPUTS = {
"dumpsys battery": _DUMPSYS_BATTERY_,
"pwd": "/",
}

Expand Down
5 changes: 2 additions & 3 deletions tests/test_adb_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,5 @@ def test_host_tport_serial(adb: adbutils.AdbClient):
d.open_transport()


def test_shell_pwd(adb: adbutils.AdbClient):
d = adb.device(serial="123456")
assert d.shell("pwd") == "/"


51 changes: 51 additions & 0 deletions tests/test_adb_shell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Created on Mon May 06 2024 14:41:10 by codeskyblue
"""

import adbutils


def test_shell_pwd(adb: adbutils.AdbClient):
d = adb.device(serial="123456")
assert d.shell("pwd") == "/"


def test_shell_battery(adb: adbutils.AdbClient):
d = adb.device(serial="123456")

_DUMPSYS_BATTERY_ = """Current Battery Service state:
AC powered: false
USB powered: true
Wireless powered: false
Dock powered: false
Max charging current: 0
Max charging voltage: 0
Charge counter: 10000
status: 4
health: 2
present: true
level: 80
scale: 100
voltage: 5000
temperature: 250
technology: Li-ion"""
d.shell = lambda cmd: _DUMPSYS_BATTERY_

bat = d.battery()
assert bat.ac_powered == False
assert bat.wireless_powered == False
assert bat.usb_powered == True
assert bat.dock_powered == False
assert bat.max_charging_current == 0
assert bat.max_charging_voltage == 0
assert bat.charge_counter == 10000
assert bat.status == 4
assert bat.health == 2
assert bat.present == True
assert bat.level == 80
assert bat.scale == 100
assert bat.voltage == 5000
assert bat.temperature == 25.0
assert bat.technology == "Li-ion"

0 comments on commit 1eea76f

Please sign in to comment.