diff --git a/HISTORY.rst b/HISTORY.rst index 927f9a3..aa5a4f9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,3 +1,20 @@ +0.3.0 (Unreleased) +-------------------- + +* Fixes #111: Invalid escape sequence via @eamanu and @mib1185 +* Fixes #110: Add ability to pass extra arguments to `screencap` commands for waydroid via @CloCkWeRX +* Fixes #88: Missing return in ppadb.command.transport: Transport.shell() for custom handler via @roxen +* Fixes #60: Close socket if the connection fails via @JeffLIrion +* Fixes #64: ADB reverse command via @Hamz-a +* Fixes #92: incorrect timestamp type in asynchronous push via @slicen and @GeekDuanLian +* Adds #65: Added support to remove reverses via @Hamz-a +* Adds #67: asynchronous install and uninstall commands via @slicen +* Adds #85: Include LICENSE in pip package via @jan-janssen +* Adds #57: Recursive directory push for DeviceAsync class via @JeffLIrion +* Adds #89: Call disable-user if app is device-admin via @eybisi +* Change #94: Device#install and DeviceAsync#install changes param from `grand_all_permissions` to `grant_all_permissions` + + 0.2.1 (2019-10-14) -------------------- diff --git a/ppadb/command/host/__init__.py b/ppadb/command/host/__init__.py index 61b16ce..e457608 100644 --- a/ppadb/command/host/__init__.py +++ b/ppadb/command/host/__init__.py @@ -3,7 +3,7 @@ class Host(Command): - CONNECT_RESULT_PATTERN = "(connected to|already connected)" + CONNECT_RESULT_PATTERN = r"(connected to|already connected)" OFFLINE = "offline" DEVICE = "device" diff --git a/ppadb/command/host_async/__init__.py b/ppadb/command/host_async/__init__.py index 2de3cab..274d043 100644 --- a/ppadb/command/host_async/__init__.py +++ b/ppadb/command/host_async/__init__.py @@ -2,7 +2,7 @@ class HostAsync: - CONNECT_RESULT_PATTERN = "(connected to|already connected)" + CONNECT_RESULT_PATTERN = r"(connected to|already connected)" OFFLINE = "offline" DEVICE = "device" diff --git a/ppadb/command/transport/__init__.py b/ppadb/command/transport/__init__.py index 2b319cb..f141be3 100644 --- a/ppadb/command/transport/__init__.py +++ b/ppadb/command/transport/__init__.py @@ -23,7 +23,7 @@ def shell(self, cmd, handler=None, timeout=None): conn.send(cmd) if handler: - handler(conn) + return handler(conn) else: result = conn.read_all() conn.close() @@ -37,11 +37,13 @@ def sync(self): return conn - def screencap(self): + def screencap(self, optional_args=None): conn = self.create_connection() with conn: cmd = "shell:/system/bin/screencap -p" + if optional_args is not None: + cmd = cmd + " " + optional_args conn.send(cmd) result = conn.read_all() @@ -51,7 +53,7 @@ def screencap(self): return result def clear(self, package): - clear_result_pattern = "(Success|Failed)" + clear_result_pattern = r"(Success|Failed)" result = self.shell("pm clear {}".format(package)) m = re.search(clear_result_pattern, result) @@ -68,7 +70,7 @@ def framebuffer(self): def list_features(self): result = self.shell("pm list features 2>/dev/null") - result_pattern = "^feature:(.*?)(?:=(.*?))?\r?$" + result_pattern = r"^feature:(.*?)(?:=(.*?))?\r?$" features = {} for line in result.split("\n"): m = re.match(result_pattern, line) @@ -80,7 +82,7 @@ def list_features(self): def list_packages(self): result = self.shell("pm list packages 2>/dev/null") - result_pattern = "^package:(.*?)\r?$" + result_pattern = r"^package:(.*?)\r?$" packages = [] for line in result.split("\n"): @@ -92,7 +94,7 @@ def list_packages(self): def get_properties(self): result = self.shell("getprop") - result_pattern = "^\[([\s\S]*?)\]: \[([\s\S]*?)\]\r?$" + result_pattern = r"^\[([\s\S]*?)\]: \[([\s\S]*?)\]\r?$" properties = {} for line in result.split("\n"): diff --git a/ppadb/command/transport_async/__init__.py b/ppadb/command/transport_async/__init__.py index be6a618..2532a7d 100644 --- a/ppadb/command/transport_async/__init__.py +++ b/ppadb/command/transport_async/__init__.py @@ -23,9 +23,13 @@ async def sync(self): return conn - async def screencap(self): + # Take a screenshot. Optionally, you can pass + # additional command line arguments, ie "2>/dev/null" + async def screencap(self, optional_args=None): async with await self.create_connection() as conn: cmd = "shell:/system/bin/screencap -p" + if optional_args is not None: + cmd = cmd + " " + optional_args await conn.send(cmd) result = await conn.read_all() diff --git a/ppadb/device.py b/ppadb/device.py index 876c54b..ca0cb1a 100644 --- a/ppadb/device.py +++ b/ppadb/device.py @@ -31,8 +31,8 @@ class Device(Transport, Serial, Input, Utils, WM, Traffic, CPUStat, BatteryStats): - INSTALL_RESULT_PATTERN = "(Success|Failure|Error)\s?(.*)" - UNINSTALL_RESULT_PATTERN = "(Success|Failure.*|.*Unknown package:.*)" + INSTALL_RESULT_PATTERN = r"(Success|Failure|Error)\s?(.*)" + UNINSTALL_RESULT_PATTERN = r"(Success|Failure.*|.*Unknown package:.*)" def __init__(self, client, serial): self.client = client @@ -90,7 +90,7 @@ def install( shared_mass_storage=False, # -s internal_system_memory=False, # -f downgrade=False, # -d - grand_all_permissions=False, # -g + grant_all_permissions=False, # -g ): dest = Sync.temp(path) self.push(path, dest) @@ -110,7 +110,7 @@ def install( parameters.append("-f") if downgrade: parameters.append("-d") - if grand_all_permissions: + if grant_all_permissions: parameters.append("-g") try: @@ -146,6 +146,10 @@ def uninstall(self, package): return True elif m: logger.error(m.group(1)) + if "DELETE_FAILED_DEVICE_POLICY_MANAGER" in m.group(1): + logger.info("App is device-admin, calling disable-user") + self.shell("pm disable-user {}".format(package)) + return self.uninstall(package) return False else: logger.error("There is no message after uninstalling") diff --git a/ppadb/device_async.py b/ppadb/device_async.py index 64e4f00..41b517c 100644 --- a/ppadb/device_async.py +++ b/ppadb/device_async.py @@ -16,8 +16,8 @@ class DeviceAsync(TransportAsync): - INSTALL_RESULT_PATTERN = "(Success|Failure|Error)\s?(.*)" - UNINSTALL_RESULT_PATTERN = "(Success|Failure.*|.*Unknown package:.*)" + INSTALL_RESULT_PATTERN = r"(Success|Failure|Error)\s?(.*)" + UNINSTALL_RESULT_PATTERN = r"(Success|Failure.*|.*Unknown package:.*)" def __init__(self, client, serial): self.client = client @@ -75,7 +75,7 @@ async def install( shared_mass_storage=False, # -s internal_system_memory=False, # -f downgrade=False, # -d - grand_all_permissions=False, # -g + grant_all_permissions=False, # -g ): dest = SyncAsync.temp(path) @@ -99,7 +99,7 @@ async def install( parameters.append("-f") if downgrade: parameters.append("-d") - if grand_all_permissions: + if grant_all_permissions: parameters.append("-g") try: diff --git a/ppadb/plugins/device/cpustat.py b/ppadb/plugins/device/cpustat.py index 40ad05a..923fc84 100644 --- a/ppadb/plugins/device/cpustat.py +++ b/ppadb/plugins/device/cpustat.py @@ -111,7 +111,7 @@ def total(self): class CPUStat(Plugin): total_cpu_pattern = re.compile( - "cpu\s+([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s" + r"cpu\s+([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s([\d]+)\s" ) def cpu_times(self): diff --git a/ppadb/plugins/device/traffic.py b/ppadb/plugins/device/traffic.py index ceac99e..9b1fe1f 100644 --- a/ppadb/plugins/device/traffic.py +++ b/ppadb/plugins/device/traffic.py @@ -36,7 +36,7 @@ def get_traffic(self, package_name): cmd = "dumpsys package {} | grep userId".format(package_name) result = self.shell(cmd).strip() - pattern = "userId=([\d]+)" + pattern = r"userId=([\d]+)" if result: match = re.search(pattern, result) diff --git a/ppadb/plugins/device/utils.py b/ppadb/plugins/device/utils.py index ca4c885..06ef5fd 100644 --- a/ppadb/plugins/device/utils.py +++ b/ppadb/plugins/device/utils.py @@ -41,7 +41,7 @@ def get_top_activity(self): return None def get_top_activities(self): - pattern = "ACTIVITY\s([\w\.]+)/([\w\.]+)\s[\w\d]+\spid=([\d]+)" + pattern = r"ACTIVITY\s([\w\.]+)/([\w\.]+)\s[\w\d]+\spid=([\d]+)" cmd = "dumpsys activity top | grep ACTIVITY" result = self.shell(cmd) @@ -57,13 +57,13 @@ def get_top_activities(self): def get_meminfo(self, package_name): total_meminfo_re = re.compile( - "\s*TOTAL\s*(?P\d+)" - "\s*(?P\d+)" - "\s*(?P\d+)" - "\s*(?P\d+)" - "\s*(?P\d+)" - "\s*(?P\d+)" - "\s*(?P\d+)" + r"\s*TOTAL\s*(?P\d+)" + r"\s*(?P\d+)" + r"\s*(?P\d+)" + r"\s*(?P\d+)" + r"\s*(?P\d+)" + r"\s*(?P\d+)" + r"\s*(?P\d+)" ) cmd = "dumpsys meminfo {}".format(package_name) @@ -95,7 +95,7 @@ def get_uid(self, package_name): cmd = "dumpsys package {} | grep userId".format(package_name) result = self.shell(cmd).strip() - pattern = "userId=([\d]+)" + pattern = r"userId=([\d]+)" if result: match = re.search(pattern, result) @@ -112,7 +112,7 @@ def get_package_version_name(self, package_name): cmd = "dumpsys package {} | grep versionName".format(package_name) result = self.shell(cmd).strip() - pattern = "versionName=([\d\.]+)" + pattern = r"versionName=([\d\.]+)" if result: match = re.search(pattern, result) diff --git a/ppadb/plugins/device/wm.py b/ppadb/plugins/device/wm.py index 03734b2..92ff8d8 100644 --- a/ppadb/plugins/device/wm.py +++ b/ppadb/plugins/device/wm.py @@ -7,7 +7,7 @@ class WM(Plugin): - SIZE_RE = "Physical size:\s([\d]+)x([\d]+)" + SIZE_RE = r"Physical size:\s([\d]+)x([\d]+)" def wm_size(self): result = self.shell("wm size") diff --git a/setup.py b/setup.py index 610847e..f2cf73b 100644 --- a/setup.py +++ b/setup.py @@ -22,11 +22,11 @@ setup( name="pure-python-adb", version="0.3.0-dev", - description="Pure python implementation of the adb client", + description="Pure python implementation of the adb client, forked and maintained", long_description=readme + "\n\n" + history, - author="Swind Ou", - author_email="swind@cloudmosa.com", - url="https://github.com/Swind/pure-python-adb", + author="Sergio Martins", + author_email="", + url="https://github.com/spm5065/pure-python-adb", license="MIT license", packages=find_packages(exclude=["*.test", "*.test.*", "test.*", "test"]), install_requires=[],