androidctl 0.1.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.
- androidctl/__init__.py +5 -0
- androidctl/__main__.py +4 -0
- androidctl/_version.py +1 -0
- androidctl/app.py +73 -0
- androidctl/cli_options.py +27 -0
- androidctl/command_payloads.py +264 -0
- androidctl/command_views.py +157 -0
- androidctl/commands/__init__.py +1 -0
- androidctl/commands/actions.py +236 -0
- androidctl/commands/adb_wireless.py +157 -0
- androidctl/commands/close.py +30 -0
- androidctl/commands/connect.py +69 -0
- androidctl/commands/execute.py +179 -0
- androidctl/commands/list_apps.py +26 -0
- androidctl/commands/observe.py +26 -0
- androidctl/commands/open.py +41 -0
- androidctl/commands/plumbing.py +58 -0
- androidctl/commands/run_pipeline.py +307 -0
- androidctl/commands/screenshot.py +29 -0
- androidctl/commands/setup.py +301 -0
- androidctl/commands/wait.py +60 -0
- androidctl/daemon/__init__.py +1 -0
- androidctl/daemon/client.py +348 -0
- androidctl/daemon/discovery.py +190 -0
- androidctl/daemon/launcher.py +26 -0
- androidctl/daemon/owner.py +349 -0
- androidctl/errors/__init__.py +1 -0
- androidctl/errors/mapping.py +149 -0
- androidctl/errors/models.py +16 -0
- androidctl/exit_codes.py +8 -0
- androidctl/output.py +147 -0
- androidctl/parsing/__init__.py +1 -0
- androidctl/parsing/duration.py +17 -0
- androidctl/parsing/open_target.py +51 -0
- androidctl/parsing/refs.py +12 -0
- androidctl/parsing/screen_id.py +10 -0
- androidctl/parsing/wait.py +70 -0
- androidctl/renderers/__init__.py +110 -0
- androidctl/renderers/_paths.py +109 -0
- androidctl/renderers/xml.py +234 -0
- androidctl/renderers/xml_projection.py +732 -0
- androidctl/resources/__init__.py +1 -0
- androidctl/resources/androidctl-agent-0.1.0-release.apk +0 -0
- androidctl/setup/__init__.py +1 -0
- androidctl/setup/accessibility.py +159 -0
- androidctl/setup/adb.py +586 -0
- androidctl/setup/apk_resource.py +29 -0
- androidctl/setup/pairing.py +70 -0
- androidctl/setup/verify.py +175 -0
- androidctl/workspace/__init__.py +3 -0
- androidctl/workspace/resolve.py +27 -0
- androidctl-0.1.0.dist-info/METADATA +217 -0
- androidctl-0.1.0.dist-info/RECORD +187 -0
- androidctl-0.1.0.dist-info/WHEEL +5 -0
- androidctl-0.1.0.dist-info/entry_points.txt +3 -0
- androidctl-0.1.0.dist-info/licenses/LICENSE +674 -0
- androidctl-0.1.0.dist-info/top_level.txt +3 -0
- androidctl_contracts/__init__.py +55 -0
- androidctl_contracts/_version.py +1 -0
- androidctl_contracts/_wire_helpers.py +31 -0
- androidctl_contracts/base.py +142 -0
- androidctl_contracts/command_catalog.py +414 -0
- androidctl_contracts/command_results.py +630 -0
- androidctl_contracts/daemon_api.py +335 -0
- androidctl_contracts/errors.py +44 -0
- androidctl_contracts/paths.py +5 -0
- androidctl_contracts/public_screen.py +579 -0
- androidctl_contracts/user_state.py +23 -0
- androidctl_contracts/vocabulary.py +82 -0
- androidctld/__init__.py +5 -0
- androidctld/__main__.py +63 -0
- androidctld/_version.py +1 -0
- androidctld/actions/__init__.py +1 -0
- androidctld/actions/action_target.py +142 -0
- androidctld/actions/capabilities.py +539 -0
- androidctld/actions/executor.py +894 -0
- androidctld/actions/focus_confirmation.py +177 -0
- androidctld/actions/focused_input_admissibility.py +120 -0
- androidctld/actions/fresh_current.py +176 -0
- androidctld/actions/postconditions.py +473 -0
- androidctld/actions/repair.py +101 -0
- androidctld/actions/request_builder.py +204 -0
- androidctld/actions/settle.py +146 -0
- androidctld/actions/submit_confirmation.py +211 -0
- androidctld/actions/submit_routing.py +311 -0
- androidctld/actions/type_confirmation.py +257 -0
- androidctld/app_targets.py +71 -0
- androidctld/artifacts/__init__.py +1 -0
- androidctld/artifacts/models.py +26 -0
- androidctld/artifacts/screen_lookup.py +241 -0
- androidctld/artifacts/screen_payloads.py +109 -0
- androidctld/artifacts/writer.py +286 -0
- androidctld/auth/__init__.py +1 -0
- androidctld/auth/active_registry.py +266 -0
- androidctld/auth/secret_files.py +52 -0
- androidctld/auth/token_store.py +59 -0
- androidctld/commands/__init__.py +1 -0
- androidctld/commands/assembly.py +231 -0
- androidctld/commands/command_models.py +254 -0
- androidctld/commands/dispatch.py +99 -0
- androidctld/commands/executor.py +31 -0
- androidctld/commands/from_boundary.py +175 -0
- androidctld/commands/handlers/__init__.py +15 -0
- androidctld/commands/handlers/action.py +439 -0
- androidctld/commands/handlers/connect.py +94 -0
- androidctld/commands/handlers/list_apps.py +215 -0
- androidctld/commands/handlers/observe.py +121 -0
- androidctld/commands/handlers/screenshot.py +105 -0
- androidctld/commands/handlers/wait.py +286 -0
- androidctld/commands/models.py +65 -0
- androidctld/commands/open_targets.py +56 -0
- androidctld/commands/orchestration.py +353 -0
- androidctld/commands/registry.py +116 -0
- androidctld/commands/result_builders.py +40 -0
- androidctld/commands/result_models.py +555 -0
- androidctld/commands/results.py +108 -0
- androidctld/commands/semantic_command_names.py +17 -0
- androidctld/commands/semantic_error_mapping.py +93 -0
- androidctld/commands/semantic_truth.py +135 -0
- androidctld/commands/service.py +67 -0
- androidctld/config.py +75 -0
- androidctld/daemon/__init__.py +1 -0
- androidctld/daemon/active_slot.py +326 -0
- androidctld/daemon/envelope.py +30 -0
- androidctld/daemon/http_host.py +123 -0
- androidctld/daemon/ingress.py +112 -0
- androidctld/daemon/ownership_probe.py +204 -0
- androidctld/daemon/server.py +286 -0
- androidctld/daemon/service.py +99 -0
- androidctld/device/__init__.py +1 -0
- androidctld/device/action_models.py +154 -0
- androidctld/device/action_serialization.py +121 -0
- androidctld/device/adapters.py +220 -0
- androidctld/device/bootstrap.py +153 -0
- androidctld/device/connectors.py +231 -0
- androidctld/device/errors.py +100 -0
- androidctld/device/interfaces.py +58 -0
- androidctld/device/parsing.py +320 -0
- androidctld/device/rpc.py +483 -0
- androidctld/device/schema.py +114 -0
- androidctld/device/types.py +161 -0
- androidctld/errors/__init__.py +94 -0
- androidctld/logging/__init__.py +22 -0
- androidctld/observation.py +98 -0
- androidctld/protocol.py +53 -0
- androidctld/refs/__init__.py +1 -0
- androidctld/refs/models.py +54 -0
- androidctld/refs/repair.py +284 -0
- androidctld/refs/service.py +422 -0
- androidctld/rendering/__init__.py +1 -0
- androidctld/rendering/screen_xml.py +256 -0
- androidctld/runtime/__init__.py +21 -0
- androidctld/runtime/kernel.py +548 -0
- androidctld/runtime/lifecycle.py +19 -0
- androidctld/runtime/models.py +48 -0
- androidctld/runtime/screen_state.py +117 -0
- androidctld/runtime/state_repo.py +70 -0
- androidctld/runtime/store.py +76 -0
- androidctld/runtime_policy.py +127 -0
- androidctld/schema/__init__.py +5 -0
- androidctld/schema/base.py +132 -0
- androidctld/schema/core.py +35 -0
- androidctld/schema/daemon_api.py +108 -0
- androidctld/schema/persistence.py +161 -0
- androidctld/schema/persistence_io.py +41 -0
- androidctld/schema/validation_errors.py +309 -0
- androidctld/semantics/__init__.py +1 -0
- androidctld/semantics/compiler.py +610 -0
- androidctld/semantics/continuity.py +107 -0
- androidctld/semantics/labels.py +252 -0
- androidctld/semantics/models.py +25 -0
- androidctld/semantics/policy.py +23 -0
- androidctld/semantics/public_models.py +123 -0
- androidctld/semantics/registries.py +13 -0
- androidctld/semantics/submit_refs.py +417 -0
- androidctld/semantics/surface.py +254 -0
- androidctld/semantics/targets.py +167 -0
- androidctld/snapshots/__init__.py +1 -0
- androidctld/snapshots/models.py +219 -0
- androidctld/snapshots/refresh.py +273 -0
- androidctld/snapshots/schema.py +74 -0
- androidctld/snapshots/service.py +138 -0
- androidctld/text_equivalence.py +67 -0
- androidctld/waits/__init__.py +1 -0
- androidctld/waits/evaluators.py +216 -0
- androidctld/waits/loop.py +305 -0
- androidctld/waits/matcher.py +41 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from androidctl.commands import run_pipeline
|
|
8
|
+
from androidctl.errors.mapping import map_exception
|
|
9
|
+
from androidctl.setup import adb as setup_adb
|
|
10
|
+
from androidctl_contracts.daemon_api import ConnectCommandPayload, ConnectionPayload
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class SetupVerificationResult:
|
|
15
|
+
command: str
|
|
16
|
+
envelope: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SetupVerificationError(RuntimeError):
|
|
20
|
+
def __init__(self, code: str, layer: str, message: str) -> None:
|
|
21
|
+
super().__init__(message)
|
|
22
|
+
self.code = code
|
|
23
|
+
self.layer = layer
|
|
24
|
+
self.message = message
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
DEFAULT_VERIFY_ATTEMPTS = 5
|
|
28
|
+
DEFAULT_VERIFY_RETRY_DELAY_SECONDS = 0.5
|
|
29
|
+
_RETRYABLE_VERIFY_CODES = {
|
|
30
|
+
"ACCESSIBILITY_DISABLED",
|
|
31
|
+
"ACCESSIBILITY_NOT_READY",
|
|
32
|
+
"DEVICE_AGENT_UNAVAILABLE",
|
|
33
|
+
"DEVICE_DISCONNECTED",
|
|
34
|
+
"DEVICE_NOT_CONNECTED",
|
|
35
|
+
"DEVICE_RPC_TRANSPORT_RESET",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def verify_setup_readiness(
|
|
40
|
+
*,
|
|
41
|
+
serial: str,
|
|
42
|
+
token: str,
|
|
43
|
+
workspace_root: Path | None,
|
|
44
|
+
attempts: int = DEFAULT_VERIFY_ATTEMPTS,
|
|
45
|
+
retry_delay_seconds: float = DEFAULT_VERIFY_RETRY_DELAY_SECONDS,
|
|
46
|
+
) -> SetupVerificationResult:
|
|
47
|
+
normalized_attempts = max(1, attempts)
|
|
48
|
+
last_error: SetupVerificationError | None = None
|
|
49
|
+
for attempt_index in range(normalized_attempts):
|
|
50
|
+
try:
|
|
51
|
+
return _verify_setup_readiness_once(
|
|
52
|
+
serial=serial,
|
|
53
|
+
token=token,
|
|
54
|
+
workspace_root=workspace_root,
|
|
55
|
+
)
|
|
56
|
+
except SetupVerificationError as error:
|
|
57
|
+
last_error = error
|
|
58
|
+
if (
|
|
59
|
+
attempt_index == normalized_attempts - 1
|
|
60
|
+
or not _is_retryable_verify_error(error)
|
|
61
|
+
):
|
|
62
|
+
raise
|
|
63
|
+
time.sleep(max(0.0, retry_delay_seconds))
|
|
64
|
+
if last_error is not None:
|
|
65
|
+
raise last_error
|
|
66
|
+
raise SetupVerificationError(
|
|
67
|
+
code="SETUP_VERIFY_FAILED",
|
|
68
|
+
layer="daemon",
|
|
69
|
+
message="daemon connect/readiness verification failed",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _verify_setup_readiness_once(
|
|
74
|
+
*,
|
|
75
|
+
serial: str,
|
|
76
|
+
token: str,
|
|
77
|
+
workspace_root: Path | None,
|
|
78
|
+
) -> SetupVerificationResult:
|
|
79
|
+
request = run_pipeline.CliCommandRequest(
|
|
80
|
+
public_command="connect",
|
|
81
|
+
command=ConnectCommandPayload(
|
|
82
|
+
kind="connect",
|
|
83
|
+
connection=ConnectionPayload(
|
|
84
|
+
mode="adb",
|
|
85
|
+
token=token,
|
|
86
|
+
serial=serial,
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
workspace_root=workspace_root,
|
|
90
|
+
)
|
|
91
|
+
verification_error: SetupVerificationError | None = None
|
|
92
|
+
try:
|
|
93
|
+
outcome = run_pipeline.run_command(request, run_pipeline.build_context())
|
|
94
|
+
except Exception as error:
|
|
95
|
+
verification_error = _verification_error_from_exception(error, token=token)
|
|
96
|
+
if verification_error is not None:
|
|
97
|
+
raise verification_error
|
|
98
|
+
|
|
99
|
+
payload = outcome.payload
|
|
100
|
+
if payload.get("ok") is not True:
|
|
101
|
+
raise _verification_error_from_payload(payload, token=token)
|
|
102
|
+
command = _payload_string(payload, "command")
|
|
103
|
+
envelope = _payload_string(payload, "envelope")
|
|
104
|
+
if command != "connect" or envelope != "bootstrap":
|
|
105
|
+
raise SetupVerificationError(
|
|
106
|
+
code="SETUP_VERIFY_FAILED",
|
|
107
|
+
layer="daemon",
|
|
108
|
+
message="daemon connect returned an unexpected readiness result",
|
|
109
|
+
)
|
|
110
|
+
return SetupVerificationResult(
|
|
111
|
+
command=command,
|
|
112
|
+
envelope=envelope,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _is_retryable_verify_error(error: SetupVerificationError) -> bool:
|
|
117
|
+
return error.code in _RETRYABLE_VERIFY_CODES
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _verification_error_from_payload(
|
|
121
|
+
payload: dict[str, object],
|
|
122
|
+
*,
|
|
123
|
+
token: str,
|
|
124
|
+
) -> SetupVerificationError:
|
|
125
|
+
code = _payload_string(payload, "code") or "SETUP_VERIFY_FAILED"
|
|
126
|
+
message = _payload_string(payload, "message") or (
|
|
127
|
+
"daemon connect/readiness verification failed"
|
|
128
|
+
)
|
|
129
|
+
return SetupVerificationError(
|
|
130
|
+
code=code,
|
|
131
|
+
layer=verification_layer_for_code(code),
|
|
132
|
+
message=_redact_sensitive_text(message, token=token),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _verification_error_from_exception(
|
|
137
|
+
error: Exception,
|
|
138
|
+
*,
|
|
139
|
+
token: str,
|
|
140
|
+
) -> SetupVerificationError:
|
|
141
|
+
mapped_error = error
|
|
142
|
+
if isinstance(error, run_pipeline.PreDispatchCommandError):
|
|
143
|
+
mapped_error = error.cause
|
|
144
|
+
public_error = map_exception(mapped_error)
|
|
145
|
+
return SetupVerificationError(
|
|
146
|
+
code=public_error.code,
|
|
147
|
+
layer=verification_layer_for_code(public_error.code),
|
|
148
|
+
message=_redact_sensitive_text(public_error.message, token=token),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def verification_layer_for_code(code: str) -> str:
|
|
153
|
+
if code in {"DEVICE_AGENT_UNAUTHORIZED"}:
|
|
154
|
+
return "auth"
|
|
155
|
+
if code in {"ACCESSIBILITY_NOT_READY", "ACCESSIBILITY_DISABLED"}:
|
|
156
|
+
return "accessibility"
|
|
157
|
+
if code in {
|
|
158
|
+
"DEVICE_AGENT_UNAVAILABLE",
|
|
159
|
+
"DEVICE_DISCONNECTED",
|
|
160
|
+
"DEVICE_NOT_CONNECTED",
|
|
161
|
+
}:
|
|
162
|
+
return "server"
|
|
163
|
+
return "daemon"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _payload_string(payload: dict[str, object], key: str) -> str | None:
|
|
167
|
+
value = payload.get(key)
|
|
168
|
+
if not isinstance(value, str):
|
|
169
|
+
return None
|
|
170
|
+
normalized = value.strip()
|
|
171
|
+
return normalized or None
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _redact_sensitive_text(text: str, *, token: str) -> str:
|
|
175
|
+
return setup_adb.redact_adb_output(text, sensitive_values=(token,))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path, PureWindowsPath
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _resolve_user_path(value: Path | str, *, cwd: Path, field_name: str) -> Path:
|
|
8
|
+
raw_value = str(value)
|
|
9
|
+
if os.name != "nt" and PureWindowsPath(raw_value).is_absolute():
|
|
10
|
+
raise ValueError(f"{field_name} must use a host path")
|
|
11
|
+
candidate = Path(raw_value)
|
|
12
|
+
if not candidate.is_absolute():
|
|
13
|
+
candidate = cwd / candidate
|
|
14
|
+
return candidate.resolve()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def resolve_workspace_root(
|
|
18
|
+
*,
|
|
19
|
+
flag_value: Path | None,
|
|
20
|
+
env_value: str | None,
|
|
21
|
+
cwd: Path,
|
|
22
|
+
) -> Path:
|
|
23
|
+
if flag_value is not None:
|
|
24
|
+
return _resolve_user_path(flag_value, cwd=cwd, field_name="workspace root")
|
|
25
|
+
if env_value:
|
|
26
|
+
return _resolve_user_path(env_value, cwd=cwd, field_name="workspace root")
|
|
27
|
+
return cwd.resolve()
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: androidctl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Playwright-like CLI for Android automation, built for AI agents.
|
|
5
|
+
Author: Azure99
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/Azure99/androidctl
|
|
8
|
+
Project-URL: Repository, https://github.com/Azure99/androidctl
|
|
9
|
+
Project-URL: Issues, https://github.com/Azure99/androidctl/issues
|
|
10
|
+
Keywords: agent,android,adb,automation,cli,accessibility
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: click<9,>=8.1
|
|
22
|
+
Requires-Dist: httpx<0.29,>=0.27
|
|
23
|
+
Requires-Dist: pydantic<3,>=2.11
|
|
24
|
+
Requires-Dist: pydantic-core<3,>=2.33
|
|
25
|
+
Requires-Dist: typing-extensions<5,>=4.12
|
|
26
|
+
Requires-Dist: typer<1,>=0.16
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: black; extra == "dev"
|
|
29
|
+
Requires-Dist: build; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy<1.11; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest<9,>=8; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff; extra == "dev"
|
|
33
|
+
Requires-Dist: tomli; extra == "dev"
|
|
34
|
+
Requires-Dist: twine; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# AndroidCtl
|
|
38
|
+
|
|
39
|
+
AndroidCtl is a local Android automation toolkit for developer and agent
|
|
40
|
+
workflows. It provides a host CLI, a host daemon, shared Python contracts, and an
|
|
41
|
+
Android device agent that can observe the current UI, expose stable element refs,
|
|
42
|
+
run actions, wait for screen changes, and collect artifacts such as screenshots.
|
|
43
|
+
|
|
44
|
+
The usual loop is:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
androidctl observe
|
|
48
|
+
androidctl tap n3
|
|
49
|
+
androidctl wait --until idle
|
|
50
|
+
androidctl observe
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Repository Layout
|
|
54
|
+
|
|
55
|
+
- `contracts/`: shared Python wire models and command catalog.
|
|
56
|
+
- `androidctl/`: public CLI, command parsing, daemon discovery, and XML output.
|
|
57
|
+
- `androidctld/`: host daemon, runtime state, command execution, and device RPC.
|
|
58
|
+
- `android/`: Kotlin Android device agent with a foreground RPC service and
|
|
59
|
+
Accessibility service.
|
|
60
|
+
|
|
61
|
+
## Requirements
|
|
62
|
+
|
|
63
|
+
- Python 3.10.
|
|
64
|
+
- Android SDK platform tools, especially `adb`.
|
|
65
|
+
- An Android 11+ device or emulator with USB debugging enabled.
|
|
66
|
+
|
|
67
|
+
## Install From PyPI
|
|
68
|
+
|
|
69
|
+
Install the released host tools with the single public distribution:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
pip install androidctl
|
|
73
|
+
androidctl --help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `androidctl` distribution includes the CLI, host daemon, and shared Python
|
|
77
|
+
contracts. Do not install separate `androidctld` or `androidctl-contracts`
|
|
78
|
+
distributions.
|
|
79
|
+
|
|
80
|
+
## Install From Source
|
|
81
|
+
|
|
82
|
+
Create a local Python environment and install AndroidCtl in editable mode:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
conda create -p ./.conda python=3.10
|
|
86
|
+
./.conda/bin/python -m pip install -U pip
|
|
87
|
+
./.conda/bin/python -m pip install -e ".[dev]"
|
|
88
|
+
export PATH="$PWD/.conda/bin:$PATH"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Check the CLI:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
androidctl --version
|
|
95
|
+
androidctl --help
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Build The Android Agent
|
|
99
|
+
|
|
100
|
+
Released Python packages include the Android agent APK used by setup. When
|
|
101
|
+
working from source and testing a locally built debug agent, build a debug APK
|
|
102
|
+
and pass it to setup with `--apk`:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
(cd android && ./gradlew :app:assembleDebug)
|
|
106
|
+
androidctl setup --adb --apk android/app/build/outputs/apk/debug/app-debug.apk
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The debug APK is created at:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
android/app/build/outputs/apk/debug/app-debug.apk
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Prepare A Device
|
|
116
|
+
|
|
117
|
+
Connect a device with USB debugging enabled and confirm that ADB can see it:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
adb devices
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Run the onboarding helper:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
androidctl setup --adb
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If more than one device is connected, pass the ADB serial:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
androidctl setup --adb --serial <adb-serial>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Setup installs the Android agent, starts its foreground RPC server, provisions a
|
|
136
|
+
device token, attempts to enable the AndroidCtl Accessibility service, and checks
|
|
137
|
+
that the daemon can talk to the device. If Android blocks automatic
|
|
138
|
+
Accessibility enablement, follow the manual instructions printed by the command
|
|
139
|
+
and rerun setup.
|
|
140
|
+
|
|
141
|
+
## Optional Wireless ADB
|
|
142
|
+
|
|
143
|
+
Pair and connect from the CLI if you prefer Android wireless debugging:
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
androidctl adb-pair --pair <host:pair-port> --code <pairing-code>
|
|
147
|
+
androidctl adb-connect <host:connect-port>
|
|
148
|
+
androidctl setup --adb --serial <host:connect-port>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Basic Usage
|
|
152
|
+
|
|
153
|
+
Observe the current screen:
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
androidctl observe
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The output is XML intended for scripts and agents. Interactive elements receive
|
|
160
|
+
refs such as `n1`, `n2`, and `n3`; use those refs in later commands.
|
|
161
|
+
|
|
162
|
+
Common commands:
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
androidctl list-apps
|
|
166
|
+
androidctl open app:com.android.settings
|
|
167
|
+
androidctl open https://example.com
|
|
168
|
+
androidctl tap n3
|
|
169
|
+
androidctl long-tap n3
|
|
170
|
+
androidctl focus n4
|
|
171
|
+
androidctl type n4 "hello from androidctl"
|
|
172
|
+
androidctl submit n4
|
|
173
|
+
androidctl scroll n8 down
|
|
174
|
+
androidctl back
|
|
175
|
+
androidctl home
|
|
176
|
+
androidctl recents
|
|
177
|
+
androidctl notifications
|
|
178
|
+
androidctl wait --until screen-change
|
|
179
|
+
androidctl wait --until gone --ref n3
|
|
180
|
+
androidctl wait --until text-present --text "Done"
|
|
181
|
+
androidctl wait --until app --app com.android.settings
|
|
182
|
+
androidctl screenshot
|
|
183
|
+
androidctl close
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Commands use the current workspace by default. For a dedicated runtime state
|
|
187
|
+
directory, pass `--workspace-root <path>` or set `ANDROIDCTL_WORKSPACE_ROOT`.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
Run the default verification suite from the repository root:
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
task test
|
|
195
|
+
task lint
|
|
196
|
+
task quality
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Useful focused commands:
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
task androidctl:test
|
|
203
|
+
task androidctld:test
|
|
204
|
+
task contracts:test
|
|
205
|
+
task android:test
|
|
206
|
+
task format
|
|
207
|
+
task --list
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Source development additionally requires Conda, JDK 17 or newer for Android
|
|
211
|
+
Gradle builds, and `task` for repository shortcuts.
|
|
212
|
+
|
|
213
|
+
Process-level CLI checks are available through:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
task test:extended
|
|
217
|
+
```
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
androidctl/__init__.py,sha256=4QtZe7AlfISNcrAe0ma3ZSkgeDDZd3y24es8U74otFc,88
|
|
2
|
+
androidctl/__main__.py,sha256=GhA_jQK0HPEAxwgfSYLfQz8t5uDWTBxCY5icQ_MuVrw,59
|
|
3
|
+
androidctl/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
4
|
+
androidctl/app.py,sha256=YOr4GQUJhqLsNfVdIqSqMH2CR4NXDjw7_5uSWbIuP6o,2402
|
|
5
|
+
androidctl/cli_options.py,sha256=9jYnxicN8Uonty4ex2D05rXIw5zhDF8KoRIYyaprqhE,611
|
|
6
|
+
androidctl/command_payloads.py,sha256=nJGyfD15COMEvp3XDnVJOIJRIBNGh2c_rbs5kEI_wWA,8878
|
|
7
|
+
androidctl/command_views.py,sha256=AbJgSnPGzb8pBgnjyH1OfIHqHWl-JjjN3TVUnc5vJlc,4483
|
|
8
|
+
androidctl/exit_codes.py,sha256=ZCkgxTVAdN9-jH-EeeTK-xNV3gvEujnqpl9eFJ-BFlU,111
|
|
9
|
+
androidctl/output.py,sha256=dNUnYvmE6660edDFp6lvUxT76sn1cP7_AqSZCk3dtzc,4216
|
|
10
|
+
androidctl/commands/__init__.py,sha256=TOMJAh6GCkJ3gAlu1iZo1eKtdBP7_MzCeUrxozBCW2Y,28
|
|
11
|
+
androidctl/commands/actions.py,sha256=Aq5BoBv3r9SkZ6QIwqLIpr9Y-u5MIMlywrplvtHd1SU,7947
|
|
12
|
+
androidctl/commands/adb_wireless.py,sha256=PC3b2GN1BV4u5ekyfbS6DXk2uBdKN7mcgnDHepzBxas,4817
|
|
13
|
+
androidctl/commands/close.py,sha256=B4yu2bbPdjJSi3P7g_p5zXAS8b4wtcbUZw4mlTHILnM,949
|
|
14
|
+
androidctl/commands/connect.py,sha256=-PEjLMu8eH5DaMyqIKO1DGPGOU3eHrPbOwQ9vCVOoKw,2783
|
|
15
|
+
androidctl/commands/execute.py,sha256=Pn3oehixkwf0PKl2kJlhVmUCPjmsWK2tbUtqMHXSpIM,5215
|
|
16
|
+
androidctl/commands/list_apps.py,sha256=EE8_4EbI0Ku6RKbmNhH6_AA1HIEZecs1tMDBIwONfHI,821
|
|
17
|
+
androidctl/commands/observe.py,sha256=4UtSsP_xtf9wAaa4WZ3ZQ5bzAW5lsAYKYGi5zjhNloY,812
|
|
18
|
+
androidctl/commands/open.py,sha256=H0qJoBhc69UUrfcwS-CM9VjQ74sXREO46oU5sFKK92Q,1386
|
|
19
|
+
androidctl/commands/plumbing.py,sha256=GQjqVe1BMjKWD8EFWB7GhyF4LcEXw5tNuszBHURLiFM,1648
|
|
20
|
+
androidctl/commands/run_pipeline.py,sha256=HIu5AkqE7zYAngreWZkBE4ajEEr7h5gV17VOD5VzMpY,8988
|
|
21
|
+
androidctl/commands/screenshot.py,sha256=IOxiKWaTApAVmDAG6yO7k56heYWuiGYgnchN1q9P1m8,931
|
|
22
|
+
androidctl/commands/setup.py,sha256=l0RClZQY5B0sap1BkHC9qghZTLun_H27Fd9_QE9tLRA,9446
|
|
23
|
+
androidctl/commands/wait.py,sha256=gyrOwVYsn3xiqt9bOMlIMHZqcB2RgsKwbuwftvn5oDg,2239
|
|
24
|
+
androidctl/daemon/__init__.py,sha256=yhRVLJ_xwA8TqEEMVLQjE0aaS27S295SvVMs_mhIAlw,47
|
|
25
|
+
androidctl/daemon/client.py,sha256=QyAOsg0SlrylE2As-HH-z3Ha7H1ykbceotrzIiDQBf8,11337
|
|
26
|
+
androidctl/daemon/discovery.py,sha256=of3aERrkWhSGRu2jxPhne_NnbELWCRB6E8ry6ft2R_g,5683
|
|
27
|
+
androidctl/daemon/launcher.py,sha256=8cN0KwP3nR0hlBQHC277CosoBnCPYQ5G03JKWYWHQP8,653
|
|
28
|
+
androidctl/daemon/owner.py,sha256=MuXC2D3VWlkkERdH8dU3N7DHah5wglqmLX53UI6S7Mc,11037
|
|
29
|
+
androidctl/errors/__init__.py,sha256=is9JaQ9Keci_dD7neHD42h2ArBptl2O_wQ7qbM0re3M,51
|
|
30
|
+
androidctl/errors/mapping.py,sha256=RXIcs_G28GoIgOIMDZw_St7xMHqt7qjmAmo_0a3PzAU,5028
|
|
31
|
+
androidctl/errors/models.py,sha256=Sozu8ynlSPO3xj2Em0H429Wby3K2K2QBfQwjfwcLv-c,316
|
|
32
|
+
androidctl/parsing/__init__.py,sha256=sFJFYJswlm2ScWPZDGRhwrG1kENiKXRb0DTtwYAAAMk,40
|
|
33
|
+
androidctl/parsing/duration.py,sha256=X6K5VhDg9NtVvNIAQyYpKr3nhb97FCh3fwM2MJLQmXQ,468
|
|
34
|
+
androidctl/parsing/open_target.py,sha256=QKLOtjp4lJoDnylLzevx5vy3HeOjfUkWy-qlfCKUd2g,1586
|
|
35
|
+
androidctl/parsing/refs.py,sha256=nP6lF4ooBzZC1cV8b3x3gwy26grkvxOmJKcvQP9XxYY,284
|
|
36
|
+
androidctl/parsing/screen_id.py,sha256=wU47dhXhhwjsPpppI0AOhxGBmamKDDTfQsPdZOxYGxU,276
|
|
37
|
+
androidctl/parsing/wait.py,sha256=OXSHPTNACy9lkqoV692stC4jW9ilj3W_pUT_SizrU1g,2461
|
|
38
|
+
androidctl/renderers/__init__.py,sha256=nVYSLnyjbeXAc6WfowqMRFva5nx1NKfrPJ7GbpetTfA,4093
|
|
39
|
+
androidctl/renderers/_paths.py,sha256=oMW4F60_jrtv5eDR-a1EUkGpH6GjKGuC24oH5J75TYQ,3219
|
|
40
|
+
androidctl/renderers/xml.py,sha256=9qXnPj_Mls9j52Z6uI0BW6KxQQISDRho28aoey-nUEw,7137
|
|
41
|
+
androidctl/renderers/xml_projection.py,sha256=UvwqyPwziBcKZqO0M7c6tMEQIADYcMwSPXYn6m7PNgE,21555
|
|
42
|
+
androidctl/resources/__init__.py,sha256=u59_QkN6Zxtq8l_GSEWaXnVXI9YIvH_4X5D0BG_sZfc,51
|
|
43
|
+
androidctl/resources/androidctl-agent-0.1.0-release.apk,sha256=gtILGdzX3pd4A23mj4CwqfKVsrG0Ir1eX6iIteR1B9U,1817062
|
|
44
|
+
androidctl/setup/__init__.py,sha256=gWBddRbWC4cxkLNSW38ccbqnfMkYUQCL3XbM8mnpdoo,31
|
|
45
|
+
androidctl/setup/accessibility.py,sha256=F6c1THAnTXUPsYZgab0j4NAAZtGscVINb3LbC1-jDVw,5096
|
|
46
|
+
androidctl/setup/adb.py,sha256=sd0tA8AOvBe6jiYXZ1hfNBVA5_zQg6xKdHflB3OxfYc,16808
|
|
47
|
+
androidctl/setup/apk_resource.py,sha256=avl5f6SxwI6Qmwf4t0tEdwxZowNz7GlshCHXUgKDdSM,992
|
|
48
|
+
androidctl/setup/pairing.py,sha256=-6gVN7tmGjONYmzRuWVQ88v-qmR3QCWvosiEi8Yx-Nw,2091
|
|
49
|
+
androidctl/setup/verify.py,sha256=8ZbQzLleRowW1B4PT6wuYUm-1XC73L6pmBHU3qdiDig,5296
|
|
50
|
+
androidctl/workspace/__init__.py,sha256=w3-mYU1pRyZh9GO0Urgk015vprsCDBZcWrrQbi5XR3A,102
|
|
51
|
+
androidctl/workspace/resolve.py,sha256=wA6XnkAnYLGarrDuRDVG5UqeQVPZ9qKlPt1da0oD_tE,826
|
|
52
|
+
androidctl-0.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
53
|
+
androidctl_contracts/__init__.py,sha256=M6xk80zkDwzA3GRvo7gp_fzTYaSAhC7VNI84606QOU0,1706
|
|
54
|
+
androidctl_contracts/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
55
|
+
androidctl_contracts/_wire_helpers.py,sha256=F21mP752Vb2U3ZlkoxbcA4M9JKrHhIvyFfTXIYoTDDU,793
|
|
56
|
+
androidctl_contracts/base.py,sha256=BH0W1UBPqHFQ0zYLBVF_DnCKwgodBdDvKl_JnbDSywo,4455
|
|
57
|
+
androidctl_contracts/command_catalog.py,sha256=Mvd5ehWyuoHThGFhAQcMVD0V0xkhGwLkzSHnIRNUQrQ,13107
|
|
58
|
+
androidctl_contracts/command_results.py,sha256=ziWr74mymmhVJp6ecEPv7sVIWWrmrN8b1eNoMCHLYCY,22623
|
|
59
|
+
androidctl_contracts/daemon_api.py,sha256=DxNg_ub-gM0uDbn3YtxCxFZimvIgw5fd371Wgquzyrg,8846
|
|
60
|
+
androidctl_contracts/errors.py,sha256=5VjpycZ4UqCuEDfWWOn_F7umqe30qu2tYoOrNrffsf8,1600
|
|
61
|
+
androidctl_contracts/paths.py,sha256=vQ45eL41PRzFpX6s_w5S8gKMQpfBaMLIWEgCZk92FpU,133
|
|
62
|
+
androidctl_contracts/public_screen.py,sha256=ejLlBFKDlMOevsOe4H7KOhJr_ByiPWnJApoOakbgzKk,18374
|
|
63
|
+
androidctl_contracts/user_state.py,sha256=ABoI_2RAN-pWEigrBTkrej3lCdqY4AMWNPHU_CBtlrY,459
|
|
64
|
+
androidctl_contracts/vocabulary.py,sha256=eozqR7g2ZLB6feJLzNuSTbf7zxR2oUAdALuoJyoyPRs,1809
|
|
65
|
+
androidctld/__init__.py,sha256=9q6Hoe4SX4bhDh-EahJPl5csFlEBRkTRZ3ZzMm8y95c,119
|
|
66
|
+
androidctld/__main__.py,sha256=kw-DhZgo54nwfB3obhjNIZEGLKLzoNlvFa11OLnT7NA,1734
|
|
67
|
+
androidctld/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
68
|
+
androidctld/app_targets.py,sha256=3AHMB8u_5tbPJWiyN9Ll--tCQJhjveDcsRi9E4ACkLw,2114
|
|
69
|
+
androidctld/config.py,sha256=MVWXvezLo7jZQAgbeNPw7ZQKPcNd7le_zVja4HuW8_E,2365
|
|
70
|
+
androidctld/observation.py,sha256=PvKyqnG78-WLe-TZnmKIPxyz9bNEUWVDgpleoAs6uH8,2883
|
|
71
|
+
androidctld/protocol.py,sha256=eLfaK3OD45PKWgVN7INHOxromDoACmHdiTzndOWtAws,1209
|
|
72
|
+
androidctld/runtime_policy.py,sha256=v058l3tQuS5485d-Xm4hDL4kYZUxm6xPrnUXCPJunKE,4632
|
|
73
|
+
androidctld/text_equivalence.py,sha256=jTrCWds5vsYiXW1DzKs1qQPBcG3XV-GH63BKN4siMBg,1688
|
|
74
|
+
androidctld/actions/__init__.py,sha256=VRHZcFSmhhqFWVtaEQezKTgVer3bCszConeqEGxdMRs,46
|
|
75
|
+
androidctld/actions/action_target.py,sha256=sajRoLf-TRtVBihR2cXkmqo4IjKHTmVWdi-TjfeDl54,4229
|
|
76
|
+
androidctld/actions/capabilities.py,sha256=ssHPhcpc6IHGPbJRQa_-edZY51_vkKumZ2xoLIq_uVU,16290
|
|
77
|
+
androidctld/actions/executor.py,sha256=sSqRjB5u6ULNdkw8cgFeDt20eE7NcGhnmOPuz1layk4,33084
|
|
78
|
+
androidctld/actions/focus_confirmation.py,sha256=ZxCPUbebTq71rfb29B5B02RC6S2C9NvPj_5B-jbBf3Q,5395
|
|
79
|
+
androidctld/actions/focused_input_admissibility.py,sha256=pr6hD0HxJRltuqPy0Iua3QSV6NPY9-uot3BxlfpMl_Y,2880
|
|
80
|
+
androidctld/actions/fresh_current.py,sha256=gGvQooDdXqvwAmZ38DkeYgLuLZf6DAS3nK-541dmc-Y,5383
|
|
81
|
+
androidctld/actions/postconditions.py,sha256=pTrrKFRo5zA5jKZ0w2uqK7DAvo807nzsMxqk_m4SdKA,15279
|
|
82
|
+
androidctld/actions/repair.py,sha256=LElYO95rwO1GdFlKvlDjYTJu9DrSpc_0atwc6reUKhI,3509
|
|
83
|
+
androidctld/actions/request_builder.py,sha256=cCsdeweecx-Xi5OfczgDPVxO2j_dyBtZPDkorjh1G64,6996
|
|
84
|
+
androidctld/actions/settle.py,sha256=BCdAXHofHRfSpDkBRjbLbUBfcr9Ts4io7tB66-Kggps,5241
|
|
85
|
+
androidctld/actions/submit_confirmation.py,sha256=4SIKWuCrbPQdCPyB5qIqqclkVD0nO_js4_7an1uiGkk,6833
|
|
86
|
+
androidctld/actions/submit_routing.py,sha256=gj2UAbLtS9M2hCo20pOZMfYe-sdOAIjNp0IaB9nYGgQ,9877
|
|
87
|
+
androidctld/actions/type_confirmation.py,sha256=WCHSh5jkQN_GRaSj5fGeYbnDvImH6iwULN_l2JfHkgc,7779
|
|
88
|
+
androidctld/artifacts/__init__.py,sha256=pgyeikmFTdMgQhoHeuW5FMSBI1JVHoJAD89CPJYE8lM,40
|
|
89
|
+
androidctld/artifacts/models.py,sha256=Osx_sZ2h_J6sg1xJ_SzqiopgbVFhf1OmSDU_IMZC5Ic,691
|
|
90
|
+
androidctld/artifacts/screen_lookup.py,sha256=28WcIBA4eejzFlOvSh_xJywf2dmkCcsE2HJNo4Tj47s,7447
|
|
91
|
+
androidctld/artifacts/screen_payloads.py,sha256=8h6BRlt3nWzowsDrLuw9ZacizSEacyeTrnm3enmEoGw,3228
|
|
92
|
+
androidctld/artifacts/writer.py,sha256=0jdMzHddOwJdtqmSqYDJ7vPlJOOtTmHsQlfxmogmbyE,9778
|
|
93
|
+
androidctld/auth/__init__.py,sha256=xwCyyzQ8Iu7DzOqyEgSHfsZpwoZ5jXMCuDNGZJCDCmo,46
|
|
94
|
+
androidctld/auth/active_registry.py,sha256=o05fjCsQuvq6eZlRupq3V0mDJWG1SkUk-GLzyQK-y2g,9060
|
|
95
|
+
androidctld/auth/secret_files.py,sha256=94Vr8J_y_msoPeh85xGuDzHPzO-7UTzEyTS4qyq9h1Y,1512
|
|
96
|
+
androidctld/auth/token_store.py,sha256=fGygjQ5pmH4pYR_-N9jorbKBXQ1-PVsIRhknplXx0E4,1722
|
|
97
|
+
androidctld/commands/__init__.py,sha256=4MevNZf54MkxiYjdda4GQE-xD7gIPegkdad6jphxwZY,40
|
|
98
|
+
androidctld/commands/assembly.py,sha256=56QlUQi3CgvNeA2Qz0lS7LpgGyBNjikOV6XVfCxr0v8,8605
|
|
99
|
+
androidctld/commands/command_models.py,sha256=3iAac3W48Xqn-bD1ukIQDUmQ1U2nJpizJPOykxrHnJw,5983
|
|
100
|
+
androidctld/commands/dispatch.py,sha256=DRLChzI_BR6HvAmaym14Bsu4_ItmNXn1gODpy1fBqAE,4154
|
|
101
|
+
androidctld/commands/executor.py,sha256=WxrnZGMoxBR8o6ZHc3NeaBjrhIe0SMeFOpP79EsWnfY,806
|
|
102
|
+
androidctld/commands/from_boundary.py,sha256=f7ypzu7qLGwd5fjDEPnAucqUdcm8DDrn70JHhxrKDdU,5557
|
|
103
|
+
androidctld/commands/models.py,sha256=zhe92Nj5SMar079mo0Nk0NFdykLF3JEB-Yl7luviI9Y,1854
|
|
104
|
+
androidctld/commands/open_targets.py,sha256=gZ2rABIKSmhIBrEoYnVcl23eNqsBQXg1ssyY1QtLCBM,1326
|
|
105
|
+
androidctld/commands/orchestration.py,sha256=S_rZc4YFwVA-6ToDYnrhJ8fGooMAXrW3M7lvaczz_kc,12074
|
|
106
|
+
androidctld/commands/registry.py,sha256=rbXGItAtDrebQB8gvX7zhlWkBHJ0GUZ9Z8e8pjtTxig,3138
|
|
107
|
+
androidctld/commands/result_builders.py,sha256=TVi8d7mi8GKnCfkXtYIgs4y4Ioj5vo8FJVBg29AosZo,1248
|
|
108
|
+
androidctld/commands/result_models.py,sha256=8bMX2vGgC1N_3laFC6xok2HFLhAxXY6qm4d2opa0tNs,17161
|
|
109
|
+
androidctld/commands/results.py,sha256=AURTnob6IpEAva_NB-00L1TZONXFnay1L1Bn_sYeIkU,3847
|
|
110
|
+
androidctld/commands/semantic_command_names.py,sha256=X-3755hwLJwvMteIXU92uK9HynvVO8IhryUUPEfxAfA,573
|
|
111
|
+
androidctld/commands/semantic_error_mapping.py,sha256=BYSpXaJk_ZA9TB70HXibaOopHY2HXi91L0KkFViksnU,2902
|
|
112
|
+
androidctld/commands/semantic_truth.py,sha256=hQBE-plbPNFBbvR2fRz5RhhW6Ym0x5xUReqkH8XE34E,4270
|
|
113
|
+
androidctld/commands/service.py,sha256=_uWM0kl3ljmkv_Vb-kPIjHlEIrHNNKZYcvpZJYvr-GA,2494
|
|
114
|
+
androidctld/commands/handlers/__init__.py,sha256=zaOUCB4TDV38SgtgSOiynznq6iK7ydGEeBhquPxNTbY,549
|
|
115
|
+
androidctld/commands/handlers/action.py,sha256=kfdBFY7u1TeRgixS3tfEzY_XtsG3jVGtLpw9OgCBjuc,16107
|
|
116
|
+
androidctld/commands/handlers/connect.py,sha256=tOntgPC-cjukSYYgIHsoikiybIhLruUL_h36A3DRDuw,3500
|
|
117
|
+
androidctld/commands/handlers/list_apps.py,sha256=I4eqSKpxe6k0abAWOyYfVt3fjPaRoGQ0iAo90lg8wfU,6923
|
|
118
|
+
androidctld/commands/handlers/observe.py,sha256=nPMyjKr5l2ZjvUbufrF2KsApWav_ic1XD6oY7AM4EPM,4759
|
|
119
|
+
androidctld/commands/handlers/screenshot.py,sha256=ifQnrYo2UPAPUbsf9WOqSWq3M_ZqANVBHUqPikNM9iM,4101
|
|
120
|
+
androidctld/commands/handlers/wait.py,sha256=GdO1x2l3xTus8-kLeRfHC0LySQJKLlHqYJ7qLx6iHRY,9430
|
|
121
|
+
androidctld/daemon/__init__.py,sha256=MdeDacbbOgSdghwWIEXu8b5KFuoDP9CZKPsZwS8BS_0,34
|
|
122
|
+
androidctld/daemon/active_slot.py,sha256=DxylWRPgW2ZQCfQxxJlzFStMfTMRAEf4kpoED92OL6w,11215
|
|
123
|
+
androidctld/daemon/envelope.py,sha256=J-Fx7yMjuo62ECH6lh6JOM_8SJH0XQ53CM0b6z5_J5A,920
|
|
124
|
+
androidctld/daemon/http_host.py,sha256=4DUpAUWOvXaLVq4NY5SOPsdGdfRmI_6pOJzKrKBHia0,4169
|
|
125
|
+
androidctld/daemon/ingress.py,sha256=OEzpov43eWlMofr9rTR57H8j-A71FrJEiH5AQzgD9ns,3315
|
|
126
|
+
androidctld/daemon/ownership_probe.py,sha256=ywbRyyjspywbn6OCh0GID3pHHuHpB8Dy0fOD_G_gmEs,6740
|
|
127
|
+
androidctld/daemon/server.py,sha256=oSDgAMwTdVjAy3rgoe8KIFQkcxDlfRxOZ2hOkcBbmnw,10731
|
|
128
|
+
androidctld/daemon/service.py,sha256=RuVt-s7-XsmhgzWDcjGHGgvbIx2JKqUIR63AweYHb9A,3768
|
|
129
|
+
androidctld/device/__init__.py,sha256=kc10OpxuwURGmUtDTLVKcJZZBmZIYSR2lw5-d6aa2RM,59
|
|
130
|
+
androidctld/device/action_models.py,sha256=97ur2nMt6uWEym3YcRlcKcz-6ZCuZY1GDCvbQJiU3RM,3264
|
|
131
|
+
androidctld/device/action_serialization.py,sha256=HJk591MX4EDULwBLS2mPtqfECKKFDeZvvBmywNOvGNw,4083
|
|
132
|
+
androidctld/device/adapters.py,sha256=Rd4uzAOAkC_3iwW8w52pLPYT_hIynwmsjo1bLEUMkDE,5923
|
|
133
|
+
androidctld/device/bootstrap.py,sha256=SYcEqyASjp_gMFMg864oreWWMP1vyaVBMU7WDGKskKM,5452
|
|
134
|
+
androidctld/device/connectors.py,sha256=r_Cmjx9VBDEAd30jkhs7hzvo1UkGw-FRwkTYDt70lDI,7287
|
|
135
|
+
androidctld/device/errors.py,sha256=4XKJb_xQOVGynfC1PKxDVnqtz7jVQiIW4Mj3QZHsFKs,2486
|
|
136
|
+
androidctld/device/interfaces.py,sha256=Tl6SMhqpMkTN09EjrjlNWC-EBO_L77HdXQUv_MIUKB4,1484
|
|
137
|
+
androidctld/device/parsing.py,sha256=TmP416YuYHnb-t-uKWRLfFZTFxE80lGIlhiLvM2Nf6E,10065
|
|
138
|
+
androidctld/device/rpc.py,sha256=TQrgAUQ0qNDJ8BslixBVPDs_DKgjdwyrbi2eSFN3yPM,15503
|
|
139
|
+
androidctld/device/schema.py,sha256=Z6URyIeRtLnCnH900XyeSuapcO6SjCmUuoVdiCI_1p8,2793
|
|
140
|
+
androidctld/device/types.py,sha256=DcwOceyZFFOlR7QgHXIKMIIlzh7jO8-y2U4YooGzraA,3463
|
|
141
|
+
androidctld/errors/__init__.py,sha256=CxzvddDOq84JLElZFBXTbMFi9yMLs3E5PU1S4Oai9dQ,3202
|
|
142
|
+
androidctld/logging/__init__.py,sha256=n-qpNGF8mGw0zKbTwcylW7HfdglwqIHH7MFPJmkLysc,615
|
|
143
|
+
androidctld/refs/__init__.py,sha256=pRcfAuIhh2a1ta76kerdrq8IUCWa6YGOefMKdQ28Xrc,40
|
|
144
|
+
androidctld/refs/models.py,sha256=iRABst8Uv6fgZhSuQipZTHYUjDhAXDIU3UAyOmHGpFI,1059
|
|
145
|
+
androidctld/refs/repair.py,sha256=QWdh8C8HR2YfwgIze-QXCFHoe_jB-Iwqcuq9gmyYuEw,9087
|
|
146
|
+
androidctld/refs/service.py,sha256=cOucNxw0-M_iHhCfBi-qdLfdu2lKV_QjXhv-4_GTik0,13250
|
|
147
|
+
androidctld/rendering/__init__.py,sha256=bS_SsxNNzFB2MmXVTtCh50KEG-ouC1k261ZG34fY1s0,45
|
|
148
|
+
androidctld/rendering/screen_xml.py,sha256=1rp9e6Qp9khkv0M7SIh_Dx7Kk9vLzcGxis1uYk_9VEo,7656
|
|
149
|
+
androidctld/runtime/__init__.py,sha256=06DLg_p5Cpe5oKsUJ8aP2qDm18A36pfK0wDEGefGSb0,639
|
|
150
|
+
androidctld/runtime/kernel.py,sha256=9M9Qnvp1_RezStz2fW6snvXHnhuJY0bJkCFavQ9q4xg,18528
|
|
151
|
+
androidctld/runtime/lifecycle.py,sha256=z-3BzPfK2t0D8A9WOgwIslt1VSEMUuDoDkBv93j9M7Y,521
|
|
152
|
+
androidctld/runtime/models.py,sha256=lLogOA1bOW8_25Fld4qvS9XbluTBa9x4EM0UmLwQIUM,1872
|
|
153
|
+
androidctld/runtime/screen_state.py,sha256=PvT8L1wqiJc4IqgQC6YsDWWL_H64FEyJse3DU5nZz8U,4290
|
|
154
|
+
androidctld/runtime/state_repo.py,sha256=2VXhuXXCL_JxT57tJUJC3u57eWyusg34Qdxd7S20NhM,2286
|
|
155
|
+
androidctld/runtime/store.py,sha256=6j18HcQ7TerigDRhyuXTo0QMD69cs3RRzX_7rhoCg4A,2697
|
|
156
|
+
androidctld/schema/__init__.py,sha256=dyY1QCYdPK8y3KZIyaw0YrZspalIatGr_HyM5Id6D0k,167
|
|
157
|
+
androidctld/schema/base.py,sha256=Qxe3r9EfVOaYYIG1LM7huZq-gXMGRIxEDVq1mvYk62I,4169
|
|
158
|
+
androidctld/schema/core.py,sha256=BgkCM8SLYfg9UVswFEX2DQFxEE7en0z2sJFgsbM5MhA,1053
|
|
159
|
+
androidctld/schema/daemon_api.py,sha256=n9Y4ZVl81h-dWa0lJd1tXSp0RNkbhr364gr9cgVh5iU,3793
|
|
160
|
+
androidctld/schema/persistence.py,sha256=cEBlpwQDWAxfrbGOScsZcC6yjusnw63WUfTx3dWfqFM,4220
|
|
161
|
+
androidctld/schema/persistence_io.py,sha256=Px5T8QJM0PIa7XjhO3taRecRJGe_3k32-QgNuCsCRPo,1214
|
|
162
|
+
androidctld/schema/validation_errors.py,sha256=1YNQz2Jg7IBLMCNPCi2tgG7O6mASPmezbTzcJ2HxiDU,9696
|
|
163
|
+
androidctld/semantics/__init__.py,sha256=zeg60mmCUfgn-klJ80OrqwlImNJuIhwmidByRrKluHI,35
|
|
164
|
+
androidctld/semantics/compiler.py,sha256=O99MifSaytK5NQoJHcchgjVcNrB30UT1CcLzDiWHc3E,20765
|
|
165
|
+
androidctld/semantics/continuity.py,sha256=nSHqV7sIbMj-lQ6p0cimJokrp0fMfxUfXuk1XE196Wc,2912
|
|
166
|
+
androidctld/semantics/labels.py,sha256=mqiNGP36qgd59xlotbd_bbOCB9q1u1IiY6ivblnX3qo,7536
|
|
167
|
+
androidctld/semantics/models.py,sha256=cSu4JtnKhDp0WPq8Bxge6WKhnXyef68FU4NvB3CdR1w,481
|
|
168
|
+
androidctld/semantics/policy.py,sha256=ccdYeVCE6wtIFd39hG-PfIVAcRthJAipBCBrAPAVamM,476
|
|
169
|
+
androidctld/semantics/public_models.py,sha256=Q47DiIlL31pIhhq_312VNLl8EU6j-UFanMntBkNzth4,3188
|
|
170
|
+
androidctld/semantics/registries.py,sha256=SYSM7xFyVcgDQ-i6WnBUzNMFZFE30sqnGOHzyvkY1a4,220
|
|
171
|
+
androidctld/semantics/submit_refs.py,sha256=1MAQbsJP_jHfRiUfoFNXh2--iJmSxvBiWT6ZuWmVNl0,12160
|
|
172
|
+
androidctld/semantics/surface.py,sha256=RDoqnZsyv-ASbls9-XxI4ZWCYWD2Q58-Ub1ztMHpuds,7538
|
|
173
|
+
androidctld/semantics/targets.py,sha256=-sZXnx7XpO6U5u03FZ8JAh2NeNLKhjre0GGrGbpe_zQ,5083
|
|
174
|
+
androidctld/snapshots/__init__.py,sha256=q635p3g0rYMDjvu_IL0gG2BuLrn5WXXylVf03B0El5o,41
|
|
175
|
+
androidctld/snapshots/models.py,sha256=C8snjtlbRp-3fhAZDuhwelkA9kCsGUMIuJRVjHmMvDE,5945
|
|
176
|
+
androidctld/snapshots/refresh.py,sha256=8kuVAGt679txLBNk8OAFf3HdwcQEB_8wwAgDoJ0qNdk,9217
|
|
177
|
+
androidctld/snapshots/schema.py,sha256=CCuVAx8QUWL9_NGiU0a6rhyH-CkdB7XCaJWRC24CuHo,1760
|
|
178
|
+
androidctld/snapshots/service.py,sha256=tb_r2NnJunlSVxk-DR3MBVDtkti8QNlxQhDGZzuxRXY,4489
|
|
179
|
+
androidctld/waits/__init__.py,sha256=n2hzNv2O0TzW0B1Go-OLCW9fImYvUjJlztrgbAl3CPA,36
|
|
180
|
+
androidctld/waits/evaluators.py,sha256=tWvumuwGAcphErsyHXCNQAeaskRjhDrP-ge-9x-DmQY,6174
|
|
181
|
+
androidctld/waits/loop.py,sha256=pWKw_tFvYjd44FF83Lrx77VUKjZJvdYyRE2Tbxfbcok,9367
|
|
182
|
+
androidctld/waits/matcher.py,sha256=R32R0311B_UA1zhBM1vh7RZp4cNRzIEpGRZWvgP4_d4,1133
|
|
183
|
+
androidctl-0.1.0.dist-info/METADATA,sha256=oFMFXzeAlOUrk4-O8Yclxl5fbhCoAOwgqchHYedHJOQ,5721
|
|
184
|
+
androidctl-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
185
|
+
androidctl-0.1.0.dist-info/entry_points.txt,sha256=fUx6Rxjn-AyETBewq1ynQQk0sY_UPvGZGtIuBcKd6f0,90
|
|
186
|
+
androidctl-0.1.0.dist-info/top_level.txt,sha256=lDv6wEqTA3pTFY3eTAJ1tbLEKqujJe_i4ugRxe6_gEY,44
|
|
187
|
+
androidctl-0.1.0.dist-info/RECORD,,
|