uiautodev 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uiautodev might be problematic. Click here for more details.

@@ -0,0 +1,123 @@
1
+ import enum
2
+ import socket
3
+ import struct
4
+
5
+ from construct import Byte, Int16ub, Int32ub, Int64ub, Struct
6
+
7
+ from uiautodev.remote.android_input import KeyeventAction, MetaState
8
+ from uiautodev.remote.keycode import KeyCode
9
+
10
+
11
+ # https://github.com/Genymobile/scrcpy/blob/master/app/src/control_msg.h#L29
12
+ class MessageType(enum.IntEnum):
13
+ INJECT_KEYCODE = 0
14
+ INJECT_TEXT = 1
15
+ INJECT_TOUCH_EVENT = 2
16
+ INJECT_SCROLL_EVENT = 3
17
+ BACK_OR_SCREEN_ON = 4
18
+ EXPAND_NOTIFICATION_PANEL = 5
19
+ EXPAND_SETTINGS_PANEL = 6
20
+ COLLAPSE_PANELS = 7
21
+ GET_CLIPBOARD = 8
22
+ SET_CLIPBOARD = 9
23
+ SET_DISPLAY_POWER = 10
24
+ ROTATE_DEVICE = 11
25
+ UHID_CREATE = 12
26
+ UHID_INPUT = 13
27
+ UHID_DESTROY = 14
28
+ OPEN_HARD_KEYBOARD_SETTINGS = 15
29
+ START_APP = 16
30
+ RESET_VIDEO = 17
31
+
32
+
33
+ TouchEvent = Struct(
34
+ "type" / Byte, # SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT
35
+ "action" / Byte, # AKEY_EVENT_ACTION_DOWN
36
+ "pointer_id" / Int64ub, # 8-byte pointer ID
37
+ "x" / Int32ub, # X coordinate
38
+ "y" / Int32ub, # Y coordinate
39
+ "width" / Int16ub, # width
40
+ "height" / Int16ub, # height
41
+ "pressure" / Int16ub, # pressure
42
+ "action_button" / Int32ub, # action button
43
+ "buttons" / Int32ub # buttons
44
+ )
45
+
46
+
47
+ # Define the structure for key events
48
+ KeyEvent = Struct(
49
+ "type" / Byte, # SC_CONTROL_MSG_TYPE_INJECT_KEYCODE
50
+ "action" / Byte, # AKEY_EVENT_ACTION (DOWN, UP, MULTIPLE)
51
+ "keycode" / Int32ub, # Android keycode
52
+ "repeat" / Int32ub, # Repeat count
53
+ "metastate" / Int32ub # Meta state flags (SHIFT, ALT, etc.)
54
+ )
55
+
56
+
57
+ class ScrcpyTouchController:
58
+ """scrcpy控制类,支持scrcpy版本>=2.2"""
59
+
60
+ def __init__(self, control_socket: socket.socket):
61
+ self.control_socket = control_socket
62
+
63
+ def _build_touch_event(self, action: int, x: int, y: int, width: int, height: int):
64
+ x = max(0, min(x, width))
65
+ y = max(0, min(y, height))
66
+ return TouchEvent.build(dict(
67
+ type=MessageType.INJECT_TOUCH_EVENT,
68
+ action=action,
69
+ pointer_id=1,
70
+ x=x,
71
+ y=y,
72
+ width=width,
73
+ height=height,
74
+ pressure=1,
75
+ action_button=1, # AMOTION_EVENT_BUTTON_PRIMARY (action button)
76
+ buttons=1, # AMOTION_EVENT_BUTTON_PRIMARY (buttons)
77
+ ))
78
+
79
+ def down(self, x: int, y: int, width: int, height: int):
80
+ """发送down操作"""
81
+ data = self._build_touch_event(0, x, y, width, height)
82
+ self.control_socket.send(data)
83
+
84
+ def up(self, x: int, y: int, width: int, height: int):
85
+ """发送up操作"""
86
+ data = self._build_touch_event(1, x, y, width, height)
87
+ self.control_socket.send(data)
88
+
89
+ def move(self, x: int, y: int, width: int, height: int):
90
+ """发送move操作"""
91
+ data = self._build_touch_event(2, x, y, width, height)
92
+ self.control_socket.send(data)
93
+
94
+ def text(self, text: str):
95
+ """发送文本操作"""
96
+
97
+ # buffer = text.encode("utf-8")
98
+ # values = struct.pack(self.format_string, 2, 3, 1, len(buffer), 0, 0, 0, self.const_value,
99
+ # self.unknown1, self.unknown2) + buffer
100
+ # self.control_socket.send(values)
101
+ pass
102
+
103
+ def key(self, action: KeyeventAction, keycode: KeyCode, repeat: int, metastate: MetaState):
104
+ """
105
+ Send a keycode event to the Android device
106
+
107
+ Args:
108
+ action: Key action (DOWN, UP, or MULTIPLE)
109
+ keycode: Android key code to send
110
+ repeat: Number of times the key is repeated
111
+ metastate: Meta state flags (SHIFT, ALT, etc.)
112
+ """
113
+ # Build the data using the KeyEvent structure
114
+ data = KeyEvent.build(dict(
115
+ type=MessageType.INJECT_KEYCODE, # Type byte
116
+ action=action, # Action byte
117
+ keycode=keycode, # Keycode (4 bytes)
118
+ repeat=repeat, # Repeat count (4 bytes)
119
+ metastate=metastate, # Meta state (4 bytes)
120
+ ))
121
+
122
+ # Send the data to the control socket
123
+ self.control_socket.send(data)
@@ -28,7 +28,7 @@ def make_router(provider: BaseProvider) -> APIRouter:
28
28
 
29
29
  @router.get("/list")
30
30
  def _list() -> List[DeviceInfo]:
31
- """List of Android devices"""
31
+ """List devices"""
32
32
  try:
33
33
  return provider.list_devices()
34
34
  except NotImplementedError as e:
@@ -80,7 +80,8 @@ def make_router(provider: BaseProvider) -> APIRouter:
80
80
  else:
81
81
  return Response(content=f"Invalid format: {format}", media_type="text/plain", status_code=400)
82
82
  except Exception as e:
83
- logger.exception("dump_hierarchy failed")
83
+ #logger.exception("dump_hierarchy failed")
84
+ logger.error(f"Error dumping hierarchy: {str(e)}")
84
85
  return Response(content=str(e), media_type="text/plain", status_code=500)
85
86
 
86
87
  @router.post('/{serial}/command/tap')
uiautodev/utils/common.py CHANGED
@@ -5,11 +5,12 @@ import json as sysjson
5
5
  import platform
6
6
  import re
7
7
  import socket
8
+ import subprocess
8
9
  import sys
9
10
  import typing
10
11
  import uuid
11
12
  from http.client import HTTPConnection, HTTPResponse
12
- from typing import Optional, TypeVar, Union
13
+ from typing import List, Optional, TypeVar, Union
13
14
 
14
15
  from pydantic import BaseModel
15
16
  from pygments import formatters, highlight, lexers
@@ -61,10 +62,11 @@ def print_json(buf, colored=None, default=default_json_encoder):
61
62
  print(colorful_json)
62
63
  else:
63
64
  print(formatted_json)
64
-
65
+
65
66
 
66
67
  _T = TypeVar("_T")
67
68
 
69
+
68
70
  def convert_to_type(value: str, _type: _T) -> _T:
69
71
  """ usage example:
70
72
  convert_to_type("123", int)
@@ -78,9 +80,9 @@ def convert_to_type(value: str, _type: _T) -> _T:
78
80
  if _type == re.Pattern:
79
81
  return re.compile(value)
80
82
  raise NotImplementedError(f"convert {value} to {_type}")
81
-
82
83
 
83
- def convert_params_to_model(params: list[str], model: BaseModel) -> BaseModel:
84
+
85
+ def convert_params_to_model(params: List[str], model: BaseModel) -> BaseModel:
84
86
  """ used in cli.py """
85
87
  assert len(params) > 0
86
88
  if len(params) == 1:
@@ -114,7 +116,7 @@ class SocketHTTPConnection(HTTPConnection):
114
116
  def __init__(self, conn: socket.socket, timeout: float):
115
117
  super().__init__("localhost", timeout=timeout)
116
118
  self.__conn = conn
117
-
119
+
118
120
  def connect(self):
119
121
  self.sock = self.__conn
120
122
 
@@ -131,7 +133,8 @@ class MySocketHTTPConnection(SocketHTTPConnection):
131
133
  self.sock.settimeout(self.timeout)
132
134
 
133
135
 
134
- def fetch_through_socket(sock: socket.socket, path: str, method: str = "GET", json: Optional[dict] = None, timeout: float = 60) -> bytearray:
136
+ def fetch_through_socket(sock: socket.socket, path: str, method: str = "GET", json: Optional[dict] = None,
137
+ timeout: float = 60) -> bytearray:
135
138
  """ usage example:
136
139
  with socket.create_connection((host, port)) as s:
137
140
  request_through_socket(s, "GET", "/")
@@ -163,4 +166,5 @@ def node_travel(node: Node, dfs: bool = True):
163
166
  for child in node.children:
164
167
  yield from node_travel(child, dfs)
165
168
  if dfs:
166
- yield node
169
+ yield node
170
+
@@ -0,0 +1,9 @@
1
+ import os
2
+
3
+
4
+ def is_enabled(name: str) -> bool:
5
+ return os.getenv(name, "false").lower() in ("true", "1", "on", "yes", "y")
6
+
7
+
8
+ class Environment:
9
+ UIAUTODEV_MOCK = is_enabled("UIAUTODEV_MOCK")
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: uiautodev
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: Mobile UI Automation, include UI hierarchy inspector, script recorder
5
- Home-page: https://uiauto.dev
6
5
  License: MIT
7
6
  Author: codeskyblue
8
7
  Author-email: codeskyblue@gmail.com
@@ -14,7 +13,8 @@ Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
- Requires-Dist: adbutils (>=2.7.0,<3.0.0)
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Dist: adbutils (>=2.8.10,<3)
18
18
  Requires-Dist: click (>=8.1.7,<9.0.0)
19
19
  Requires-Dist: construct
20
20
  Requires-Dist: fastapi (>=0.111.0,<0.112.0)
@@ -27,6 +27,7 @@ Requires-Dist: pygments (>=2)
27
27
  Requires-Dist: uiautomator2 (>=2)
28
28
  Requires-Dist: uvicorn[standard]
29
29
  Requires-Dist: wdapy (>=0.2.2,<0.3.0)
30
+ Project-URL: Homepage, https://uiauto.dev
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  # uiautodev
@@ -79,6 +80,18 @@ make format
79
80
 
80
81
  # run server
81
82
  make dev
83
+
84
+ # If you encounter the error NameError: name 'int2byte' is not defined,
85
+ # try installing a stable version of the construct package to resolve it:
86
+ # and restart: make dev
87
+ pip install construct==2.9.45
88
+
89
+ ```
90
+
91
+ 运行测试
92
+
93
+ ```sh
94
+ make test
82
95
  ```
83
96
 
84
97
  # LICENSE
@@ -0,0 +1,38 @@
1
+ uiautodev/__init__.py,sha256=mTWKzvzN8eHwDcyb2IbYUtJ_o-BljuhJ03UOiHxpUdY,164
2
+ uiautodev/__main__.py,sha256=0WZHyHW-M7FG5RexANNoIB5pkCX8xwQbTnmaOA9Y1kg,176
3
+ uiautodev/app.py,sha256=dzylhfAId-GqjsyQuJznCNzn2NIK9WZ7PsiHhUrazvY,4615
4
+ uiautodev/appium_proxy.py,sha256=yMzPnIDo50hYSaq0g5bXUpgRrFa_849wNa2o7ZpxGNY,1773
5
+ uiautodev/binaries/scrcpy_server.jar,sha256=ojxWWfNsJg8QXAItJ7yz6v_6JgcOe6qe2mbQE3ehrbo,71200
6
+ uiautodev/case.py,sha256=Jk2_5X2F-XIPnGuYTCqOVQiwwchwOhF7uKK5oKv5shg,3919
7
+ uiautodev/cli.py,sha256=nqxVTaNkItIN5REGEgVPFr0JWxPmeIPz_tZvFQNU7Jc,5442
8
+ uiautodev/command_proxy.py,sha256=C9z-dITMED4k5na45NMdEWAXlLh3Ll921mKuefFyk78,5226
9
+ uiautodev/command_types.py,sha256=pWdnCS4FRnEIiR1ynd4cjXX8zeFndjPztacBlukt61E,1761
10
+ uiautodev/common.py,sha256=1A0kXfxVrp_i5mc_aRjuqSDWFFZ7DwZR9qpRLu2GMMg,1488
11
+ uiautodev/driver/android.py,sha256=ZdgMkcoyqleibHbPeg-9bDnpFx3KHBnQxhLZlnKOmbE,6344
12
+ uiautodev/driver/appium.py,sha256=U3TGpOXmu3tEa3E1ttTFoXehOfFyjavJQ3XA4CtqeBE,5308
13
+ uiautodev/driver/base_driver.py,sha256=neoVS9T8MN5RXvW6vvqXSc6pcBW_fqujJurjUrlt0OA,2816
14
+ uiautodev/driver/harmony.py,sha256=93pwlg04wazey8MQM6DEvcBkr52REYVw4bwz321fK38,8031
15
+ uiautodev/driver/ios.py,sha256=EOi9k-Y4qQS6Htdz_ycBf5jYCnOkruB-mR0Sc8J-coo,4204
16
+ uiautodev/driver/mock.py,sha256=0VtxBkZRMbHiQGHjqm8Ih2Ld6baXiVxX8yUTwWJQlnE,2422
17
+ uiautodev/driver/testdata/layout.json,sha256=0z9jGJteXuGwkOhO_iINYPoDp1kCq-EaQds_iZkmiPQ,276538
18
+ uiautodev/driver/udt/appium-uiautomator2-v5.12.4-light.apk,sha256=cKUVKpqEiGRXODeqpwzVWllyjdSLyowFm94a6jDTvhI,3675062
19
+ uiautodev/driver/udt/udt.py,sha256=p6opbUtYxEGTINIX83F6m2CtzB42iSSBYRv1SjXCEFg,8351
20
+ uiautodev/exceptions.py,sha256=TuRD5SWQk5N2_KjrcDuXG_p84LBhLa2QEEXyFNFm0yQ,465
21
+ uiautodev/model.py,sha256=hziSYyh7ufaKbQrMmRMcIVeZ0x-pwkLMHljrI-qu184,950
22
+ uiautodev/provider.py,sha256=EnBI8PD2eoBjqugGS5cmy8GZ1Z7EaEF6YEQSfpOMN6s,2862
23
+ uiautodev/remote/android_input.py,sha256=r9y2SxnDw0GhN44emL-2Nz0UasaVaVtzh53hd-LJ710,2445
24
+ uiautodev/remote/keycode.py,sha256=RHSJVfcNY2pelQd7_tcE6T0j3n8CKBkiku7A2AJZUpk,8097
25
+ uiautodev/remote/scrcpy.py,sha256=Iagm9RrdB67KC2fkyyzpCeHYT0VMSQhoBEks1R_bXpo,7380
26
+ uiautodev/remote/touch_controller.py,sha256=dYl5XTLaYEyZiNJmKwHQpw9QhPSkN3iUetJSaiQJBHg,4255
27
+ uiautodev/router/device.py,sha256=zYrxjVGjrz7Jw8G9KNO0su22OIiQDuuSHBDBDpC1PG8,4899
28
+ uiautodev/router/xml.py,sha256=MKVLhjMBqE4qbEraQxvdrVp_OBnylEL9Wti5lnmBDk4,891
29
+ uiautodev/static/demo.html,sha256=qC7qUZP5Af9T3V5EuFGbovzv8mArwiGMWsX_vcs_Bt0,1240
30
+ uiautodev/utils/common.py,sha256=L1qBBBS6jRgkXlGy5o6Xafo49auLXKRWyX9x8U_IKjc,4821
31
+ uiautodev/utils/envutils.py,sha256=Clyt2Hz9PXpK_fT0yWbMmixXyGvCaJO3LAgamM7aUVc,197
32
+ uiautodev/utils/exceptions.py,sha256=lL_G_E41KWvfXnl32-E4Vgr3_HyTboxq_EwzdQMuvK4,637
33
+ uiautodev/utils/usbmux.py,sha256=LYupLDn7U4KFKhYQJrmIroS-3040gqZQVDRDB_FNDJM,17386
34
+ uiautodev-0.7.0.dist-info/LICENSE,sha256=RyeW676gBYO7AVVP2zQgfEx5rPSt46vR47xXZe7TlX4,1068
35
+ uiautodev-0.7.0.dist-info/METADATA,sha256=cQAcxwZTGA-_kMnh95lbcdwqfi1OqIUvJowagJ7E7xo,2607
36
+ uiautodev-0.7.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
+ uiautodev-0.7.0.dist-info/entry_points.txt,sha256=zBY8GgseYAAzPFA5Cf4rCCS9ivdyWsNxMVVYIaGAHJU,88
38
+ uiautodev-0.7.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,30 +0,0 @@
1
- uiautodev/__init__.py,sha256=uBLcbZ_b1lvAbHh0kXPeO4VWJvl-Zc4XvUMhg6PmzyY,164
2
- uiautodev/__main__.py,sha256=0WZHyHW-M7FG5RexANNoIB5pkCX8xwQbTnmaOA9Y1kg,176
3
- uiautodev/app.py,sha256=R7AV5uuh4VLkrF9Kl_JJWUiPQnuIeJ02CN1W7tNGPKE,2498
4
- uiautodev/appium_proxy.py,sha256=yMzPnIDo50hYSaq0g5bXUpgRrFa_849wNa2o7ZpxGNY,1773
5
- uiautodev/case.py,sha256=Jk2_5X2F-XIPnGuYTCqOVQiwwchwOhF7uKK5oKv5shg,3919
6
- uiautodev/cli.py,sha256=K4CEvGJSDWLAFR5tvls2Qp4evQ2lApLoUxA-4DI2-Sc,6235
7
- uiautodev/command_proxy.py,sha256=gP4oTCjA1uKteWq5NOcHQLrI34el0ag5LUHNEq_j7Ko,5280
8
- uiautodev/command_types.py,sha256=pWdnCS4FRnEIiR1ynd4cjXX8zeFndjPztacBlukt61E,1761
9
- uiautodev/common.py,sha256=t1jmG7S0LVXAigtg86J3vM2XXf1xYPfDV_HwSwyl3OI,552
10
- uiautodev/driver/android.py,sha256=aKx6mW0eUMejv2uItkvDQg6o5nxtAOJ3m0gqomRXC_g,6394
11
- uiautodev/driver/appium.py,sha256=U3TGpOXmu3tEa3E1ttTFoXehOfFyjavJQ3XA4CtqeBE,5308
12
- uiautodev/driver/base_driver.py,sha256=8uo7DgEKfgW_wf-HpkmFxjNRkElpFEDjjg45Q2pgiWA,2816
13
- uiautodev/driver/ios.py,sha256=EOi9k-Y4qQS6Htdz_ycBf5jYCnOkruB-mR0Sc8J-coo,4204
14
- uiautodev/driver/mock.py,sha256=0VtxBkZRMbHiQGHjqm8Ih2Ld6baXiVxX8yUTwWJQlnE,2422
15
- uiautodev/driver/udt/appium-uiautomator2-v5.12.4-light.apk,sha256=cKUVKpqEiGRXODeqpwzVWllyjdSLyowFm94a6jDTvhI,3675062
16
- uiautodev/driver/udt/udt.py,sha256=p6opbUtYxEGTINIX83F6m2CtzB42iSSBYRv1SjXCEFg,8351
17
- uiautodev/exceptions.py,sha256=TuRD5SWQk5N2_KjrcDuXG_p84LBhLa2QEEXyFNFm0yQ,465
18
- uiautodev/model.py,sha256=ij9Ct_OboSygyU_cQHoXzQ9czcwGogoezwXjyY-Cr0U,876
19
- uiautodev/provider.py,sha256=HDD_Jj-cJVfBceunzCYU9zJvGVya7Jd35GG9h85BY-0,2370
20
- uiautodev/router/device.py,sha256=9lLN7L1lExWUZ39uKz3fd56s3dkgdTfrKgcs9jQDD0I,4846
21
- uiautodev/router/xml.py,sha256=MKVLhjMBqE4qbEraQxvdrVp_OBnylEL9Wti5lnmBDk4,891
22
- uiautodev/static/demo.html,sha256=qC7qUZP5Af9T3V5EuFGbovzv8mArwiGMWsX_vcs_Bt0,1240
23
- uiautodev/utils/common.py,sha256=HuXJvipkg1QQg6vCD7OxH6JQtqbSVbXNzI1X2OVcEcU,4785
24
- uiautodev/utils/exceptions.py,sha256=lL_G_E41KWvfXnl32-E4Vgr3_HyTboxq_EwzdQMuvK4,637
25
- uiautodev/utils/usbmux.py,sha256=LYupLDn7U4KFKhYQJrmIroS-3040gqZQVDRDB_FNDJM,17386
26
- uiautodev-0.5.0.dist-info/LICENSE,sha256=RyeW676gBYO7AVVP2zQgfEx5rPSt46vR47xXZe7TlX4,1068
27
- uiautodev-0.5.0.dist-info/METADATA,sha256=jcCkmA85d8iUEKD7yO-JbHnykMP-gkiSy6zHHCULv34,2310
28
- uiautodev-0.5.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
29
- uiautodev-0.5.0.dist-info/entry_points.txt,sha256=zBY8GgseYAAzPFA5Cf4rCCS9ivdyWsNxMVVYIaGAHJU,88
30
- uiautodev-0.5.0.dist-info/RECORD,,