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.
Files changed (187) hide show
  1. androidctl/__init__.py +5 -0
  2. androidctl/__main__.py +4 -0
  3. androidctl/_version.py +1 -0
  4. androidctl/app.py +73 -0
  5. androidctl/cli_options.py +27 -0
  6. androidctl/command_payloads.py +264 -0
  7. androidctl/command_views.py +157 -0
  8. androidctl/commands/__init__.py +1 -0
  9. androidctl/commands/actions.py +236 -0
  10. androidctl/commands/adb_wireless.py +157 -0
  11. androidctl/commands/close.py +30 -0
  12. androidctl/commands/connect.py +69 -0
  13. androidctl/commands/execute.py +179 -0
  14. androidctl/commands/list_apps.py +26 -0
  15. androidctl/commands/observe.py +26 -0
  16. androidctl/commands/open.py +41 -0
  17. androidctl/commands/plumbing.py +58 -0
  18. androidctl/commands/run_pipeline.py +307 -0
  19. androidctl/commands/screenshot.py +29 -0
  20. androidctl/commands/setup.py +301 -0
  21. androidctl/commands/wait.py +60 -0
  22. androidctl/daemon/__init__.py +1 -0
  23. androidctl/daemon/client.py +348 -0
  24. androidctl/daemon/discovery.py +190 -0
  25. androidctl/daemon/launcher.py +26 -0
  26. androidctl/daemon/owner.py +349 -0
  27. androidctl/errors/__init__.py +1 -0
  28. androidctl/errors/mapping.py +149 -0
  29. androidctl/errors/models.py +16 -0
  30. androidctl/exit_codes.py +8 -0
  31. androidctl/output.py +147 -0
  32. androidctl/parsing/__init__.py +1 -0
  33. androidctl/parsing/duration.py +17 -0
  34. androidctl/parsing/open_target.py +51 -0
  35. androidctl/parsing/refs.py +12 -0
  36. androidctl/parsing/screen_id.py +10 -0
  37. androidctl/parsing/wait.py +70 -0
  38. androidctl/renderers/__init__.py +110 -0
  39. androidctl/renderers/_paths.py +109 -0
  40. androidctl/renderers/xml.py +234 -0
  41. androidctl/renderers/xml_projection.py +732 -0
  42. androidctl/resources/__init__.py +1 -0
  43. androidctl/resources/androidctl-agent-0.1.0-release.apk +0 -0
  44. androidctl/setup/__init__.py +1 -0
  45. androidctl/setup/accessibility.py +159 -0
  46. androidctl/setup/adb.py +586 -0
  47. androidctl/setup/apk_resource.py +29 -0
  48. androidctl/setup/pairing.py +70 -0
  49. androidctl/setup/verify.py +175 -0
  50. androidctl/workspace/__init__.py +3 -0
  51. androidctl/workspace/resolve.py +27 -0
  52. androidctl-0.1.0.dist-info/METADATA +217 -0
  53. androidctl-0.1.0.dist-info/RECORD +187 -0
  54. androidctl-0.1.0.dist-info/WHEEL +5 -0
  55. androidctl-0.1.0.dist-info/entry_points.txt +3 -0
  56. androidctl-0.1.0.dist-info/licenses/LICENSE +674 -0
  57. androidctl-0.1.0.dist-info/top_level.txt +3 -0
  58. androidctl_contracts/__init__.py +55 -0
  59. androidctl_contracts/_version.py +1 -0
  60. androidctl_contracts/_wire_helpers.py +31 -0
  61. androidctl_contracts/base.py +142 -0
  62. androidctl_contracts/command_catalog.py +414 -0
  63. androidctl_contracts/command_results.py +630 -0
  64. androidctl_contracts/daemon_api.py +335 -0
  65. androidctl_contracts/errors.py +44 -0
  66. androidctl_contracts/paths.py +5 -0
  67. androidctl_contracts/public_screen.py +579 -0
  68. androidctl_contracts/user_state.py +23 -0
  69. androidctl_contracts/vocabulary.py +82 -0
  70. androidctld/__init__.py +5 -0
  71. androidctld/__main__.py +63 -0
  72. androidctld/_version.py +1 -0
  73. androidctld/actions/__init__.py +1 -0
  74. androidctld/actions/action_target.py +142 -0
  75. androidctld/actions/capabilities.py +539 -0
  76. androidctld/actions/executor.py +894 -0
  77. androidctld/actions/focus_confirmation.py +177 -0
  78. androidctld/actions/focused_input_admissibility.py +120 -0
  79. androidctld/actions/fresh_current.py +176 -0
  80. androidctld/actions/postconditions.py +473 -0
  81. androidctld/actions/repair.py +101 -0
  82. androidctld/actions/request_builder.py +204 -0
  83. androidctld/actions/settle.py +146 -0
  84. androidctld/actions/submit_confirmation.py +211 -0
  85. androidctld/actions/submit_routing.py +311 -0
  86. androidctld/actions/type_confirmation.py +257 -0
  87. androidctld/app_targets.py +71 -0
  88. androidctld/artifacts/__init__.py +1 -0
  89. androidctld/artifacts/models.py +26 -0
  90. androidctld/artifacts/screen_lookup.py +241 -0
  91. androidctld/artifacts/screen_payloads.py +109 -0
  92. androidctld/artifacts/writer.py +286 -0
  93. androidctld/auth/__init__.py +1 -0
  94. androidctld/auth/active_registry.py +266 -0
  95. androidctld/auth/secret_files.py +52 -0
  96. androidctld/auth/token_store.py +59 -0
  97. androidctld/commands/__init__.py +1 -0
  98. androidctld/commands/assembly.py +231 -0
  99. androidctld/commands/command_models.py +254 -0
  100. androidctld/commands/dispatch.py +99 -0
  101. androidctld/commands/executor.py +31 -0
  102. androidctld/commands/from_boundary.py +175 -0
  103. androidctld/commands/handlers/__init__.py +15 -0
  104. androidctld/commands/handlers/action.py +439 -0
  105. androidctld/commands/handlers/connect.py +94 -0
  106. androidctld/commands/handlers/list_apps.py +215 -0
  107. androidctld/commands/handlers/observe.py +121 -0
  108. androidctld/commands/handlers/screenshot.py +105 -0
  109. androidctld/commands/handlers/wait.py +286 -0
  110. androidctld/commands/models.py +65 -0
  111. androidctld/commands/open_targets.py +56 -0
  112. androidctld/commands/orchestration.py +353 -0
  113. androidctld/commands/registry.py +116 -0
  114. androidctld/commands/result_builders.py +40 -0
  115. androidctld/commands/result_models.py +555 -0
  116. androidctld/commands/results.py +108 -0
  117. androidctld/commands/semantic_command_names.py +17 -0
  118. androidctld/commands/semantic_error_mapping.py +93 -0
  119. androidctld/commands/semantic_truth.py +135 -0
  120. androidctld/commands/service.py +67 -0
  121. androidctld/config.py +75 -0
  122. androidctld/daemon/__init__.py +1 -0
  123. androidctld/daemon/active_slot.py +326 -0
  124. androidctld/daemon/envelope.py +30 -0
  125. androidctld/daemon/http_host.py +123 -0
  126. androidctld/daemon/ingress.py +112 -0
  127. androidctld/daemon/ownership_probe.py +204 -0
  128. androidctld/daemon/server.py +286 -0
  129. androidctld/daemon/service.py +99 -0
  130. androidctld/device/__init__.py +1 -0
  131. androidctld/device/action_models.py +154 -0
  132. androidctld/device/action_serialization.py +121 -0
  133. androidctld/device/adapters.py +220 -0
  134. androidctld/device/bootstrap.py +153 -0
  135. androidctld/device/connectors.py +231 -0
  136. androidctld/device/errors.py +100 -0
  137. androidctld/device/interfaces.py +58 -0
  138. androidctld/device/parsing.py +320 -0
  139. androidctld/device/rpc.py +483 -0
  140. androidctld/device/schema.py +114 -0
  141. androidctld/device/types.py +161 -0
  142. androidctld/errors/__init__.py +94 -0
  143. androidctld/logging/__init__.py +22 -0
  144. androidctld/observation.py +98 -0
  145. androidctld/protocol.py +53 -0
  146. androidctld/refs/__init__.py +1 -0
  147. androidctld/refs/models.py +54 -0
  148. androidctld/refs/repair.py +284 -0
  149. androidctld/refs/service.py +422 -0
  150. androidctld/rendering/__init__.py +1 -0
  151. androidctld/rendering/screen_xml.py +256 -0
  152. androidctld/runtime/__init__.py +21 -0
  153. androidctld/runtime/kernel.py +548 -0
  154. androidctld/runtime/lifecycle.py +19 -0
  155. androidctld/runtime/models.py +48 -0
  156. androidctld/runtime/screen_state.py +117 -0
  157. androidctld/runtime/state_repo.py +70 -0
  158. androidctld/runtime/store.py +76 -0
  159. androidctld/runtime_policy.py +127 -0
  160. androidctld/schema/__init__.py +5 -0
  161. androidctld/schema/base.py +132 -0
  162. androidctld/schema/core.py +35 -0
  163. androidctld/schema/daemon_api.py +108 -0
  164. androidctld/schema/persistence.py +161 -0
  165. androidctld/schema/persistence_io.py +41 -0
  166. androidctld/schema/validation_errors.py +309 -0
  167. androidctld/semantics/__init__.py +1 -0
  168. androidctld/semantics/compiler.py +610 -0
  169. androidctld/semantics/continuity.py +107 -0
  170. androidctld/semantics/labels.py +252 -0
  171. androidctld/semantics/models.py +25 -0
  172. androidctld/semantics/policy.py +23 -0
  173. androidctld/semantics/public_models.py +123 -0
  174. androidctld/semantics/registries.py +13 -0
  175. androidctld/semantics/submit_refs.py +417 -0
  176. androidctld/semantics/surface.py +254 -0
  177. androidctld/semantics/targets.py +167 -0
  178. androidctld/snapshots/__init__.py +1 -0
  179. androidctld/snapshots/models.py +219 -0
  180. androidctld/snapshots/refresh.py +273 -0
  181. androidctld/snapshots/schema.py +74 -0
  182. androidctld/snapshots/service.py +138 -0
  183. androidctld/text_equivalence.py +67 -0
  184. androidctld/waits/__init__.py +1 -0
  185. androidctld/waits/evaluators.py +216 -0
  186. androidctld/waits/loop.py +305 -0
  187. androidctld/waits/matcher.py +41 -0
@@ -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())
@@ -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