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
androidctld/__main__.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Command-line entry point for running androidctld."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import signal
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from threading import Event
|
|
10
|
+
from types import FrameType
|
|
11
|
+
|
|
12
|
+
from androidctld.auth.token_store import DaemonTokenStore
|
|
13
|
+
from androidctld.config import DEFAULT_HOST, DaemonConfig
|
|
14
|
+
from androidctld.daemon.server import AndroidctldHttpServer
|
|
15
|
+
from androidctld.runtime_policy import MAIN_LOOP_SLEEP_SECONDS
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def build_arg_parser() -> argparse.ArgumentParser:
|
|
19
|
+
parser = argparse.ArgumentParser(prog="androidctld")
|
|
20
|
+
parser.add_argument("--workspace-root", required=True)
|
|
21
|
+
parser.add_argument("--owner-id", required=True)
|
|
22
|
+
parser.add_argument("--host", default=DEFAULT_HOST)
|
|
23
|
+
parser.add_argument("--port", type=int, default=0)
|
|
24
|
+
return parser
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main(argv: list[str] | None = None) -> int:
|
|
28
|
+
args = build_arg_parser().parse_args(argv)
|
|
29
|
+
config = DaemonConfig(
|
|
30
|
+
workspace_root=Path(args.workspace_root),
|
|
31
|
+
owner_id=args.owner_id,
|
|
32
|
+
host=args.host,
|
|
33
|
+
port=args.port,
|
|
34
|
+
)
|
|
35
|
+
should_stop = Event()
|
|
36
|
+
|
|
37
|
+
def request_shutdown() -> None:
|
|
38
|
+
should_stop.set()
|
|
39
|
+
|
|
40
|
+
server = AndroidctldHttpServer(
|
|
41
|
+
config=config,
|
|
42
|
+
token_store=DaemonTokenStore(config),
|
|
43
|
+
shutdown_callback=request_shutdown,
|
|
44
|
+
)
|
|
45
|
+
server.start()
|
|
46
|
+
|
|
47
|
+
def request_stop(signum: int, frame: FrameType | None) -> None:
|
|
48
|
+
del signum, frame
|
|
49
|
+
request_shutdown()
|
|
50
|
+
|
|
51
|
+
signal.signal(signal.SIGINT, request_stop)
|
|
52
|
+
signal.signal(signal.SIGTERM, request_stop)
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
while not should_stop.wait(MAIN_LOOP_SLEEP_SECONDS):
|
|
56
|
+
pass
|
|
57
|
+
finally:
|
|
58
|
+
server.stop()
|
|
59
|
+
return 0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
sys.exit(main())
|
androidctld/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Action runtime helpers for androidctld."""
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Public-safe actionTarget projection helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
|
|
7
|
+
from androidctl_contracts.command_results import (
|
|
8
|
+
ActionTargetEvidence,
|
|
9
|
+
ActionTargetIdentityStatus,
|
|
10
|
+
ActionTargetPayload,
|
|
11
|
+
)
|
|
12
|
+
from androidctld.refs.models import NodeHandle
|
|
13
|
+
from androidctld.semantics.compiler import CompiledScreen, SemanticNode
|
|
14
|
+
from androidctld.semantics.public_models import PublicScreen, iter_public_nodes
|
|
15
|
+
from androidctld.snapshots.models import RawNode
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def public_ref_for_handle(
|
|
19
|
+
*,
|
|
20
|
+
compiled_screen: CompiledScreen | None,
|
|
21
|
+
public_screen: PublicScreen | None,
|
|
22
|
+
handle: NodeHandle | None,
|
|
23
|
+
) -> str | None:
|
|
24
|
+
if compiled_screen is None or public_screen is None or handle is None:
|
|
25
|
+
return None
|
|
26
|
+
if compiled_screen.screen_id != public_screen.screen_id:
|
|
27
|
+
return None
|
|
28
|
+
if compiled_screen.source_snapshot_id != handle.snapshot_id:
|
|
29
|
+
return None
|
|
30
|
+
return _unique_public_ref_for_raw_rid(
|
|
31
|
+
compiled_screen=compiled_screen,
|
|
32
|
+
public_screen=public_screen,
|
|
33
|
+
raw_rid=handle.rid,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def public_ref_for_raw_node(
|
|
38
|
+
*,
|
|
39
|
+
compiled_screen: CompiledScreen | None,
|
|
40
|
+
public_screen: PublicScreen | None,
|
|
41
|
+
node: RawNode | None,
|
|
42
|
+
) -> str | None:
|
|
43
|
+
if compiled_screen is None or public_screen is None or node is None:
|
|
44
|
+
return None
|
|
45
|
+
if compiled_screen.screen_id != public_screen.screen_id:
|
|
46
|
+
return None
|
|
47
|
+
return _unique_public_ref_for_raw_rid(
|
|
48
|
+
compiled_screen=compiled_screen,
|
|
49
|
+
public_screen=public_screen,
|
|
50
|
+
raw_rid=node.rid,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def build_action_target_payload(
|
|
55
|
+
*,
|
|
56
|
+
source_ref: str,
|
|
57
|
+
source_screen_id: str,
|
|
58
|
+
subject_ref: str | None,
|
|
59
|
+
next_screen_id: str,
|
|
60
|
+
identity_status: ActionTargetIdentityStatus,
|
|
61
|
+
evidence: Iterable[ActionTargetEvidence],
|
|
62
|
+
dispatched_ref: str | None = None,
|
|
63
|
+
next_ref: str | None = None,
|
|
64
|
+
) -> ActionTargetPayload | None:
|
|
65
|
+
if subject_ref is None:
|
|
66
|
+
return None
|
|
67
|
+
payload_kwargs = {
|
|
68
|
+
"source_ref": source_ref,
|
|
69
|
+
"source_screen_id": source_screen_id,
|
|
70
|
+
"subject_ref": subject_ref,
|
|
71
|
+
"next_screen_id": next_screen_id,
|
|
72
|
+
"identity_status": identity_status,
|
|
73
|
+
"evidence": tuple(evidence),
|
|
74
|
+
}
|
|
75
|
+
if dispatched_ref is not None:
|
|
76
|
+
payload_kwargs["dispatched_ref"] = dispatched_ref
|
|
77
|
+
if next_ref is not None:
|
|
78
|
+
payload_kwargs["next_ref"] = next_ref
|
|
79
|
+
return ActionTargetPayload(**payload_kwargs)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def build_same_or_successor_action_target(
|
|
83
|
+
*,
|
|
84
|
+
source_ref: str,
|
|
85
|
+
source_screen_id: str,
|
|
86
|
+
subject_ref: str | None,
|
|
87
|
+
dispatched_ref: str | None,
|
|
88
|
+
next_screen_id: str,
|
|
89
|
+
next_ref: str | None,
|
|
90
|
+
evidence: Iterable[ActionTargetEvidence],
|
|
91
|
+
) -> ActionTargetPayload | None:
|
|
92
|
+
if subject_ref is None or next_ref is None:
|
|
93
|
+
return None
|
|
94
|
+
identity_status: ActionTargetIdentityStatus = (
|
|
95
|
+
"sameRef" if next_ref == subject_ref else "successor"
|
|
96
|
+
)
|
|
97
|
+
return build_action_target_payload(
|
|
98
|
+
source_ref=source_ref,
|
|
99
|
+
source_screen_id=source_screen_id,
|
|
100
|
+
subject_ref=subject_ref,
|
|
101
|
+
dispatched_ref=dispatched_ref,
|
|
102
|
+
next_screen_id=next_screen_id,
|
|
103
|
+
next_ref=next_ref,
|
|
104
|
+
identity_status=identity_status,
|
|
105
|
+
evidence=evidence,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _unique_public_ref_for_raw_rid(
|
|
110
|
+
*,
|
|
111
|
+
compiled_screen: CompiledScreen,
|
|
112
|
+
public_screen: PublicScreen,
|
|
113
|
+
raw_rid: str,
|
|
114
|
+
) -> str | None:
|
|
115
|
+
refs = {
|
|
116
|
+
node.ref
|
|
117
|
+
for node in _compiled_nodes(compiled_screen)
|
|
118
|
+
if node.raw_rid == raw_rid and node.ref
|
|
119
|
+
}
|
|
120
|
+
if len(refs) != 1:
|
|
121
|
+
return None
|
|
122
|
+
ref = next(iter(refs))
|
|
123
|
+
return ref if _public_ref_is_unique(public_screen, ref) else None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _compiled_nodes(compiled_screen: CompiledScreen) -> tuple[SemanticNode, ...]:
|
|
127
|
+
return (
|
|
128
|
+
*compiled_screen.targets,
|
|
129
|
+
*compiled_screen.context,
|
|
130
|
+
*compiled_screen.dialog,
|
|
131
|
+
*compiled_screen.keyboard,
|
|
132
|
+
*compiled_screen.system,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _public_ref_is_unique(public_screen: PublicScreen, ref: str) -> bool:
|
|
137
|
+
count = 0
|
|
138
|
+
for group in public_screen.groups:
|
|
139
|
+
for node in iter_public_nodes(group.nodes):
|
|
140
|
+
if node.ref == ref:
|
|
141
|
+
count += 1
|
|
142
|
+
return count == 1
|