svharness 0.8.0

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 (134) hide show
  1. package/README.md +531 -0
  2. package/bin/cli.js +3 -0
  3. package/dist/adapters/_frontmatter.js +24 -0
  4. package/dist/adapters/claude-code.js +12 -0
  5. package/dist/adapters/codechat.js +12 -0
  6. package/dist/adapters/cursor.js +19 -0
  7. package/dist/adapters/generic.js +19 -0
  8. package/dist/adapters/index.js +26 -0
  9. package/dist/adapters/qoder.js +12 -0
  10. package/dist/commands/apply.js +272 -0
  11. package/dist/commands/init.js +420 -0
  12. package/dist/core/agent-injector.js +192 -0
  13. package/dist/core/next-steps.js +91 -0
  14. package/dist/core/render-meta.js +81 -0
  15. package/dist/core/repomix-pack.js +54 -0
  16. package/dist/core/scaffold.js +93 -0
  17. package/dist/core/state.js +80 -0
  18. package/dist/index.js +239 -0
  19. package/dist/types.js +5 -0
  20. package/dist/utils/baseline-copy.js +591 -0
  21. package/dist/utils/baseline-defaults.js +106 -0
  22. package/dist/utils/logger.js +56 -0
  23. package/dist/utils/validate-args.js +132 -0
  24. package/dist/utils/version.js +23 -0
  25. package/dist/wiki/abort.js +30 -0
  26. package/dist/wiki/config.js +79 -0
  27. package/dist/wiki/defaults.js +16 -0
  28. package/dist/wiki/envLoader.js +78 -0
  29. package/dist/wiki/index.js +29 -0
  30. package/dist/wiki/openaiCompat.js +219 -0
  31. package/dist/wiki/repowikiCanonicalSections.js +67 -0
  32. package/dist/wiki/repowikiCheckpoint.js +106 -0
  33. package/dist/wiki/repowikiConfig.js +9 -0
  34. package/dist/wiki/repowikiGit.js +73 -0
  35. package/dist/wiki/repowikiIndexer.js +824 -0
  36. package/dist/wiki/repowikiMarkdownPost.js +123 -0
  37. package/dist/wiki/repowikiMetadataContent.js +64 -0
  38. package/dist/wiki/repowikiMetadataJson.js +15 -0
  39. package/dist/wiki/repowikiScanner.js +156 -0
  40. package/dist/wiki/repowikiStructureNav.js +286 -0
  41. package/dist/wiki/repowikiStructureNormalize.js +218 -0
  42. package/dist/wiki/wikiStructureXml.js +316 -0
  43. package/dist/wiki/wikiTasksWriter.js +127 -0
  44. package/package.json +57 -0
  45. package/templates/_shared/apply-skills/harness-apply-skills-main.md +91 -0
  46. package/templates/_shared/build-rules/harness-build-rule-agent-agnostic.md +35 -0
  47. package/templates/_shared/build-rules/harness-build-rule-chinese-only.md +49 -0
  48. package/templates/_shared/build-rules/harness-build-rule-memory-write.md +31 -0
  49. package/templates/_shared/build-rules/harness-build-rule-orchestrator-flow.md +25 -0
  50. package/templates/_shared/build-rules/harness-build-rule-skills-tasks-output.md +35 -0
  51. package/templates/_shared/build-rules/harness-build-rule-specs-schema.md +32 -0
  52. package/templates/_shared/build-rules/harness-build-rule-user-interaction.md +63 -0
  53. package/templates/_shared/build-skills/harness-build-skill-knowledge-builder.md +120 -0
  54. package/templates/_shared/build-skills/harness-build-skill-orchestrator.md +87 -0
  55. package/templates/_shared/build-skills/harness-build-skill-spec-builder.md +85 -0
  56. package/templates/_shared/build-skills/harness-build-skill-wiki-writer.md +77 -0
  57. package/templates/_shared/meta/AGENTS.md.ejs +53 -0
  58. package/templates/_shared/meta/CHANGELOG.md.ejs +15 -0
  59. package/templates/_shared/meta/README.md.ejs +51 -0
  60. package/templates/_shared/meta/VERSION.ejs +1 -0
  61. package/templates/_shared/meta/harness.yaml.ejs +52 -0
  62. package/templates/_shared/skeleton/agent-env/memory/categories/.gitkeep +1 -0
  63. package/templates/_shared/skeleton/agent-env/memory/inbox/.gitkeep +1 -0
  64. package/templates/_shared/skeleton/agent-env/skills/.gitkeep +1 -0
  65. package/templates/_shared/skeleton/agent-env/tools/.gitkeep +1 -0
  66. package/templates/_shared/skeleton/assets/baseline/code/.gitkeep +1 -0
  67. package/templates/_shared/skeleton/assets/baseline/repomix/.gitkeep +1 -0
  68. package/templates/_shared/skeleton/assets/baseline/wiki/.gitkeep +1 -0
  69. package/templates/_shared/skeleton/assets/raw/.gitkeep +1 -0
  70. package/templates/_shared/skeleton/assets/requirements/.gitkeep +1 -0
  71. package/templates/_shared/skeleton/commands/install/.gitkeep +1 -0
  72. package/templates/_shared/skeleton/commands/update/.gitkeep +1 -0
  73. package/templates/_shared/skeleton/specs/behavior/schema.json +39 -0
  74. package/templates/_shared/skeleton/specs/interfaces/schema.json +38 -0
  75. package/templates/_shared/skeleton/specs/signals/schema.json +37 -0
  76. package/templates/_shared/skeleton/specs/ui/schema.json +44 -0
  77. package/templates/_shared/skeleton/tasks/templates/.gitkeep +0 -0
  78. package/templates/android-compose/skeleton/agent-env/rules/harness-compose-mandatory.mdc +49 -0
  79. package/templates/android-compose/skeleton/agent-env/rules/harness-coroutines-scope.mdc +52 -0
  80. package/templates/android-compose/skeleton/agent-env/rules/harness-hilt-injection.mdc +47 -0
  81. package/templates/android-compose/skeleton/agent-env/rules/harness-mvi-layering.mdc +58 -0
  82. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/SKILL.md +260 -0
  83. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/gradle-module-patterns.md +66 -0
  84. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/implementation-checklist.md +45 -0
  85. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/udf-data-flow.md +80 -0
  86. package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/SKILL.md +79 -0
  87. package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/interact.md +83 -0
  88. package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/journeys.md +97 -0
  89. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/SKILL.md +162 -0
  90. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/canonical-sources.md +116 -0
  91. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/diagnostics.md +182 -0
  92. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/report-template.md +135 -0
  93. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/scoring.md +277 -0
  94. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/search-playbook.md +303 -0
  95. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/scripts/compose-reports.init.gradle +58 -0
  96. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-state/SKILL.md +196 -0
  97. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/SKILL.md +192 -0
  98. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/composable-api-guide.md +123 -0
  99. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/performance-recipes.md +97 -0
  100. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/state-patterns.md +93 -0
  101. package/templates/android-compose/skeleton/agent-env/skills/harness-kotlin-coroutines/SKILL.md +167 -0
  102. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/SKILL.md +45 -0
  103. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/CONFIGURATION.md +44 -0
  104. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/KEEP-RULES-IMPACT-HIERARCHY.md +83 -0
  105. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REDUNDANT-RULES.md +222 -0
  106. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REFLECTION-GUIDE.md +139 -0
  107. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/topic/performance/app-optimization/enable-app-optimization.md +176 -0
  108. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/training/testing/other-components/ui-automator.md +312 -0
  109. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/SKILL.md +87 -0
  110. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/analysis-of-the-project-and-layout.md +42 -0
  111. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md +168 -0
  112. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md +183 -0
  113. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/identify-optimal-xml-candidate.md +31 -0
  114. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/xml-layout-migration.md +86 -0
  115. package/templates/android-xml/skeleton/agent-env/rules/seed-aidl-thread.md +29 -0
  116. package/templates/android-xml/skeleton/agent-env/rules/seed-lifecycle-awareness.md +32 -0
  117. package/templates/android-xml/skeleton/agent-env/rules/seed-mvc-layering.md +32 -0
  118. package/templates/android-xml/skeleton/agent-env/rules/seed-view-binding.md +33 -0
  119. package/templates/android-xml/skeleton/agent-env/rules/seed-xml-styling.md +27 -0
  120. package/templates/cpp/skeleton/agent-env/rules/seed-cmake-explicit-sources.md +31 -0
  121. package/templates/cpp/skeleton/agent-env/rules/seed-header-guards.md +34 -0
  122. package/templates/cpp/skeleton/agent-env/rules/seed-include-layering.md +39 -0
  123. package/templates/cpp/skeleton/agent-env/rules/seed-no-cyclic-deps.md +29 -0
  124. package/templates/cpp/skeleton/agent-env/rules/seed-raii.md +30 -0
  125. package/templates/python/skeleton/agent-env/rules/seed-context-managers.md +60 -0
  126. package/templates/python/skeleton/agent-env/rules/seed-docstrings.md +48 -0
  127. package/templates/python/skeleton/agent-env/rules/seed-import-order.md +49 -0
  128. package/templates/python/skeleton/agent-env/rules/seed-pep8-naming.md +45 -0
  129. package/templates/python/skeleton/agent-env/rules/seed-type-annotations.md +43 -0
  130. package/templates/web-react/skeleton/agent-env/rules/seed-controlled-component.md +43 -0
  131. package/templates/web-react/skeleton/agent-env/rules/seed-effect-cleanup.md +43 -0
  132. package/templates/web-react/skeleton/agent-env/rules/seed-hook-rules.md +42 -0
  133. package/templates/web-react/skeleton/agent-env/rules/seed-key-stability.md +39 -0
  134. package/templates/web-react/skeleton/agent-env/rules/seed-no-props-drilling.md +43 -0
@@ -0,0 +1,176 @@
1
+ For the best user experience, you should optimize your app to make it as small
2
+ and fast as possible. Our app optimizer, called R8, streamlines your app by
3
+ removing unused code and resources, rewriting code to optimize runtime
4
+ performance, and more. To your users, this means:
5
+
6
+ - Faster startup time
7
+ - Reduced memory usage
8
+ - Improved rendering and runtime performance
9
+ - Fewer [ANRs](https://developer.android.com/topic/performance/anrs/keep-your-app-responsive)
10
+
11
+ > [!IMPORTANT]
12
+ > **Important:** You should always enable optimization for your app's release build; however, you probably don't want to enable it for tests or libraries. For more information about using R8 with tests, see [Test and troubleshoot the
13
+ > optimization](https://developer.android.com/topic/performance/app-optimization/test-and-troubleshoot-the-optimization). For more information about enabling R8 from libraries, see [Optimization for library authors](https://developer.android.com/topic/performance/app-optimization/library-optimization).
14
+
15
+ > [!IMPORTANT]
16
+ > **Important:** We released an agent skill that you can use to improve your app performance with R8. Try out the skill from the [Android skills repository](https://github.com/android/skills).
17
+
18
+ ## R8 optimization overview
19
+
20
+ R8 uses a multi-phase process to optimize your app for size and speed. Key
21
+ operations include the following:
22
+
23
+ - **Code shrinking (also known as tree shaking)** : R8 identifies and removes
24
+ unreachable code from your application and its library dependencies. By
25
+ analyzing the entry points of your app (such as `Activities` or `Services`
26
+ defined in the manifest), R8 builds a graph of referenced code and removes
27
+ anything that remains unreferenced.
28
+
29
+ - **Logical optimizations**: R8 rewrites your code to improve execution
30
+ efficiency and reduce overhead. Key techniques include:
31
+
32
+ - **Method inlining**: R8 replaces a method call site with the actual body
33
+ of the called method. This eliminates the overhead of a function call
34
+ and lets R8 conduct further optimizations.
35
+
36
+ - **Class merging**: R8 combines sets of classes and interfaces into a
37
+ single class. This reduces the number of classes in the app, lowering
38
+ memory pressure and improving startup speed.
39
+
40
+ - **Obfuscation (also known as minification)** : To reduce the size of the DEX
41
+ file, R8 shortens the names of classes, fields, and methods (for example,
42
+ `com.example.MyActivity` could become `a.b.a`).
43
+
44
+ Since 8.12.0 version of Android Gradle Plugin (AGP), R8 also optimizes resources
45
+ as part of its optimization phases. For more information, see [Optimized
46
+ resource shrinking](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization#optimize-resource-shrinking).
47
+
48
+ ## Enable optimization
49
+
50
+ To enable app optimization, set `isMinifyEnabled = true` (for code optimization)
51
+ and `isShrinkResources = true` (for resource optimization) in your [release
52
+ build's](https://developer.android.com/studio/publish/preparing#turn-off-debugging) app-level build script as shown in the following code. We recommend
53
+ that you always enable both settings. We also recommend enabling app
54
+ optimization only in the final version of your app that you test before
55
+ publishing---usually your release build---because the optimizations increase the
56
+ build time of your project and can make debugging harder due to the way it
57
+ modifies code.
58
+
59
+ ### Kotlin
60
+
61
+ ```kotlin
62
+ android {
63
+ buildTypes {
64
+ release {
65
+
66
+ // Enables code-related app optimization.
67
+ isMinifyEnabled = true
68
+
69
+ // Enables resource shrinking.
70
+ isShrinkResources = true
71
+
72
+ proguardFiles(
73
+ // Default file with automatically generated optimization rules.
74
+ getDefaultProguardFile("proguard-android-optimize.txt"),
75
+
76
+ ...
77
+ )
78
+ ...
79
+ }
80
+ }
81
+ ...
82
+ }
83
+ ```
84
+
85
+ ### Groovy
86
+
87
+ ```groovy
88
+ android {
89
+ buildTypes {
90
+ release {
91
+
92
+ // Enables code-related app optimization.
93
+ minifyEnabled = true
94
+
95
+ // Enables resource shrinking.
96
+ shrinkResources = true
97
+
98
+ // Default file with automatically generated optimization rules.
99
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
100
+
101
+ ...
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ## Optimize resource shrinking for even smaller apps
108
+
109
+ The 8.12.0 version of Android Gradle Plugin (AGP) introduces optimized resource
110
+ shrinking, which aims to integrate resource and code optimization to create even
111
+ smaller and faster apps.
112
+
113
+ Before optimized resource shrinking, Android Asset Packaging Tool (AAPT2)
114
+ generated keep rules that effectively treating resource shrinking separately
115
+ from code, often retaining inaccessible code or resources that referenced each
116
+ other.
117
+
118
+ With optimized resource shrinking, resources are considered like a part of
119
+ program code, forming the reference graph. When a collection of code or
120
+ resources is not referenced, it is not protected by a keep rule, and can be
121
+ removed.
122
+
123
+ ### Enable optimized resource shrinking
124
+
125
+ To enable the new optimized resource shrinking pipeline for AGP 8.12 or 8.13,
126
+ add the following to your project's `gradle.properties` file:
127
+
128
+ android.r8.optimizedResourceShrinking=true
129
+
130
+ If you are using AGP 9.0.0 or a newer version, you don't need to set
131
+ `android.r8.optimizedResourceShrinking=true`. Optimized resource shrinking is
132
+ automatically applied when `isShrinkResources = true` is enabled in your build
133
+ configuration.
134
+
135
+ ## Verify and configure R8 optimization settings
136
+
137
+ To enable R8 to use its [full optimization capabilities](https://developer.android.com/topic/performance/app-optimization/full-mode), remove the
138
+ following line from your project's `gradle.properties` file, if it exists:
139
+
140
+ android.enableR8.fullMode=false # Remove this line from your codebase.
141
+
142
+ Note that enabling app optimization makes stack traces difficult to understand,
143
+ especially if R8 renames class or method names. To get stack traces that
144
+ correctly correspond to your source code, see [Recover the original stack
145
+ trace](https://developer.android.com/topic/performance/app-optimization/test-and-troubleshoot-the-optimization#recover-original-stack-trace).
146
+
147
+ If R8 is enabled, you should also [create Startup Profiles](https://developer.android.com/topic/performance/baselineprofiles/dex-layout-optimizations) for even better
148
+ startup performance.
149
+
150
+ If you enable app optimization and it causes errors, here are some strategies to
151
+ fix them:
152
+
153
+ - [Add keep rules](https://developer.android.com/topic/performance/app-optimization/add-keep-rules) to keep some code untouched.
154
+ - [Adopt optimizations incrementally](https://developer.android.com/topic/performance/app-optimization/adopt-optimizations-incrementally).
155
+ - Update your code to [use libraries that are better suited for
156
+ optimization](https://developer.android.com/topic/performance/app-optimization/choose-libraries-wisely).
157
+
158
+ > [!CAUTION]
159
+ > **Caution:** Tools that replace or modify R8's output can negatively impact runtime performance. R8 is careful about including and testing many optimizations at the code level, in [DEX layout](https://developer.android.com/topic/performance/baselineprofiles/dex-layout-optimizations), and in correctly producing Baseline Profiles - other tools producing or modifying DEX files can break these optimizations, or otherwise regress performance.
160
+
161
+ If you are interested in optimizing your build speed, see [Configure how R8
162
+ runs](https://developer.android.com/build/r8-execution-profiles) for information on how to configure R8 based on your environment.
163
+
164
+ ## AGP and R8 version behavior changes
165
+
166
+ The following table outlines the key features introduced in various versions of
167
+ the Android Gradle Plugin (AGP) and the R8 compiler.
168
+
169
+ | AGP version | Features introduced |
170
+ |---|---|
171
+ | 9.1 | **Classes repackaged by default:** R8 repackages classes (moving them to the unnamed package, at the top level) to compact DEX further, eliminating the need to specify `-repackageclasses` option. For information about how this works and how to opt out, see [global options](https://developer.android.com/topic/performance/app-optimization/global-options#global-options). |
172
+ | 9.0 | **Optimized resource shrinking:** Enabled by default (controlled using `android.r8.optimizedResourceShrinking`). [Optimized resource shrinking](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization#optimize-resource-shrinking) helps integrate resource shrinking with the code optimization pipeline, leading to smaller, faster apps. By optimizing both code and resource references simultaneously, it identifies and removes resources referenced exclusively from unused code. This is a significant improvement over the previous separate optimization processes. This is especially useful for apps that share substantial resources and code across different form factor verticals, with measured improvements of over 50% in app size. The resulting size reduction leads to smaller downloads, faster installations, and a better user experience with faster startup, improved rendering, and fewer ANRs. **Library rule filtering:** Support for global options (for example, `-dontobfuscate`) in library consumer rules has been dropped, and apps will filter them out. For more information, see [Add global options](https://developer.android.com/topic/performance/app-optimization/global-options). **Kotlin null checks:** Optimized by default (controlled using `-processkotlinnullchecks`). This version also introduced significant improvements in build speed. For more information, see [Global options for additional optimization](https://developer.android.com/topic/performance/app-optimization/global-options#global-options). **Optimize specific packages:** You can use `packageScope` to optimize specific packages. This is in experimental support. For more information, see [Optimize specified packages with `packageScope`](https://developer.android.com/topic/performance/app-optimization/optimize-specified-packages). **Optimized by default:** Support for `getDefaultProguardFile("proguard-android.txt")` has been dropped, because it includes `-dontoptimize`, which should be avoided. Instead, use `"proguard-android-optimize.txt"`. If you need to globally disable optimization in your app, [add the flag manually to a proguard file](https://developer.android.com/topic/performance/app-optimization/global-options#global-options-2). |
173
+ | 8.12 | **Optimized resource shrinking:** Initial support added (controlled using `android.r8.optimizedResourceShrinking`). [Optimized resource shrinking](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization#optimize-resource-shrinking) helps integrate resource shrinking with the code optimization pipeline. You must manually enable it in this version of AGP. **Logcat retracing:** Support for automatic retracing in the Android Studio [Logcat window](https://developer.android.com/studio/debug/logcat). |
174
+ | 8.6 | **Improved retracing:** Includes filename and line number retracing by default for all `minSdk` levels (previously required `minSdk` 26+ in version 8.2). Updating R8 helps ensure that stack traces from obfuscated builds are readily and clearly readable. This version improves how line numbers and source files are mapped, making it easier for tools like the Android Studio Logcat to automatically retrace crashes to the original source code. |
175
+ | 8.0 | **Full mode by default:** [R8 full mode](https://developer.android.com/topic/performance/app-optimization/full-mode) provides significantly more powerful optimization. It is enabled by default. You can opt out using `android.enableR8.fullMode=false`. |
176
+ | 7.0 | **Full mode available:** Introduced as an opt-in feature using `android.enableR8.fullMode=true`. Full mode applies more powerful optimizations by making stricter assumptions about how your code uses reflection and other dynamic features. While it reduces app size and improves performance, it might require additional keep rules to prevent necessary code from being stripped. |
@@ -0,0 +1,312 @@
1
+ The UI Automator testing framework provides a set of APIs to build UI tests that
2
+ interact with user apps and system apps.
3
+
4
+ > [!NOTE]
5
+ > **Note:** This documentation covers the modern approach to writing UI Automator tests, introduced with [UI Automator 2.4](https://developer.android.com/jetpack/androidx/releases/test-uiautomator#2.4.0). This approach makes your tests more concise, readable, and robust. The API is under development, and we strongly recommend using it for any new development with UI Automator. The [legacy API guidance](https://developer.android.com/training/testing/other-components/ui-automator-legacy) is also available.
6
+
7
+ ## Introduction to modern UI Automator testing
8
+
9
+ UI Automator 2.4 introduces a streamlined, Kotlin-friendly Domain Specific
10
+ Language (DSL) that simplifies writing UI tests for Android. This new API
11
+ surface focuses on predicate-based element finding and explicit control over app
12
+ states. Use it to create more maintainable and reliable automated tests.
13
+
14
+ UI Automator lets you test an app from outside of the app's process. This
15
+ lets you test release versions with minification applied. UI Automator also
16
+ helps when writing macrobenchmark tests.
17
+
18
+ Key features of the modern approach include:
19
+
20
+ - A dedicated `uiAutomator` test scope for cleaner and more expressive test code.
21
+ - Methods like `onElement`, `onElements`, and `onElementOrNull` for finding UI elements with clear predicates.
22
+ - Built-in waiting mechanism for conditional elements `onElement*(timeoutMs:
23
+ Long = 10000)`
24
+ - Explicit app state management such as `waitForStable` and `waitForAppToBeVisible`.
25
+ - Direct interaction with accessibility window nodes for multi-window testing scenarios.
26
+ - Built-in screenshot capabilities and a `ResultsReporter` for visual testing and debugging.
27
+
28
+ ## Set up your project
29
+
30
+ To begin using the modern UI Automator APIs, update your project's
31
+ `build.gradle.kts` file to include the [latest dependency](https://developer.android.com/jetpack/androidx/releases/test-uiautomator#2.4.0):
32
+
33
+ ### Kotlin
34
+
35
+ dependencies {
36
+ ...
37
+ androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
38
+ }
39
+
40
+ ### Groovy
41
+
42
+ dependencies {
43
+ ...
44
+ androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
45
+ }
46
+
47
+ ## Core API concepts
48
+
49
+ The following sections describe core concepts of the modern UI Automator API.
50
+
51
+ ### The uiAutomator test scope
52
+
53
+ Access all new UI Automator APIs within the **`uiAutomator { ... }`**
54
+ block. This function creates a `UiAutomatorTestScope` that provides a concise
55
+ and type-safe environment for your test operations.
56
+
57
+ uiAutomator {
58
+ // All your UI Automator actions go here
59
+ startApp("com.example.targetapp")
60
+ onElement { textAsString() == "Hello, World!" }.click()
61
+ }
62
+
63
+ ### Find UI elements
64
+
65
+ Use UI Automator APIs with predicates to locate UI elements. These predicates
66
+ let you define conditions for properties such as text, selected or focused
67
+ state, and content description.
68
+
69
+ - `onElement { predicate }`: Returns the first UI element that matches the
70
+ predicate within a default timeout. The function throws an exception if it
71
+ doesn't locate a matching element.
72
+
73
+ // Find a button with the text "Submit" and click it
74
+ onElement { textAsString() == "Submit" }.click()
75
+
76
+ // Find a UI element by its resource ID
77
+ onElement { viewIdResourceName == "my_button_id" }.click()
78
+
79
+ // Allow a permission request
80
+ watchFor(PermissionDialog) {
81
+ clickAllow()
82
+ }
83
+
84
+ - `onElementOrNull { predicate }`: Similar to `onElement`, but returns
85
+ `null` if the function finds no matching element within the timeout. It
86
+ doesn't throw an exception. Use this method for optional elements.
87
+
88
+ val optionalButton = onElementOrNull { textAsString() == "Skip" }
89
+ optionalButton?.click() // Click only if the button exists
90
+
91
+ - `onElements { predicate }`: Waits until at least one UI element matches
92
+ the given predicate, then returns a list of all matching UI elements.
93
+
94
+ // Get all items in a list Ui element
95
+ val listItems = onElements { className == "android.widget.TextView" && isClickable }
96
+ listItems.forEach { it.click() }
97
+
98
+ Here are some tips for using `onElement` calls:
99
+
100
+ - Chain `onElement` calls for nested elements: You can chain `onElement`
101
+ calls to find elements within other elements, following a parent-child
102
+ hierarchy.
103
+
104
+ // Find a parent Ui element with ID "first", then its child with ID "second",
105
+ // then its grandchild with ID "third", and click it.
106
+ onElement { viewIdResourceName == "first" }
107
+ .onElement { viewIdResourceName == "second" }
108
+ .onElement { viewIdResourceName == "third" }
109
+ .click()
110
+
111
+ - Specify a timeout for `onElement*` functions by passing a value representing
112
+ milliseconds.
113
+
114
+ // Find a Ui element with a zero timeout (instant check)
115
+ onElement(0) { viewIdResourceName == "something" }.click()
116
+
117
+ // Find a Ui element with a custom timeout of 10 seconds
118
+ onElement(10_000) { textAsString() == "Long loading text" }.click()
119
+
120
+ ### Interact with UI elements
121
+
122
+ Interact with UI elements by simulating clicks or setting text in editable
123
+ fields.
124
+
125
+ // Click a Ui element
126
+ onElement { textAsString() == "Tap Me" }.click()
127
+
128
+ // Set text in an editable field
129
+ onElement { className == "android.widget.EditText" }.setText("My input text")
130
+
131
+ // Perform a long click
132
+ onElement { contentDescription == "Context Menu" }.longClick()
133
+
134
+ ## Handle app states and watchers
135
+
136
+ Manage the lifecycle of your app and handle unexpected UI elements that might
137
+ appear during your tests.
138
+
139
+ ### App lifecycle management
140
+
141
+ The APIs provide ways to control the state of the app under test:
142
+
143
+ // Start a specific app by package name. Used for benchmarking and other
144
+ // self-instrumenting tests.
145
+ startApp("com.example.targetapp")
146
+
147
+ // Start a specific activity within the target app
148
+ startActivity(SomeActivity::class.java)
149
+
150
+ // Start an intent
151
+ startIntent(myIntent)
152
+
153
+ // Clear the app's data (resets it to a fresh state)
154
+ clearAppData("com.example.targetapp")
155
+
156
+ ### Handle unexpected UI
157
+
158
+ The `watchFor` API lets you define handlers for unexpected UI elements,
159
+ such as permission dialogs, that might appear during your test flow. This
160
+ uses the internal watcher mechanism but offers more flexibility.
161
+
162
+ import androidx.test.uiautomator.PermissionDialog
163
+
164
+ @Test
165
+ fun myTestWithPermissionHandling() = uiAutomator {
166
+ startActivity(MainActivity::class.java)
167
+
168
+ // Register a watcher to click "Allow" if a permission dialog appears
169
+ watchFor(PermissionDialog) { clickAllow() }
170
+
171
+ // Your test steps that might trigger a permission dialog
172
+ onElement { textAsString() == "Request Permissions" }.click()
173
+
174
+ // Example: You can register a different watcher later if needed
175
+ clearAppData("com.example.targetapp")
176
+
177
+ // Now deny permissions
178
+ startApp("com.example.targetapp")
179
+ watchFor(PermissionDialog) { clickDeny() }
180
+ onElement { textAsString() == "Request Permissions" }.click()
181
+ }
182
+
183
+ `PermissionDialog` is an example of a `ScopedWatcher<T>`, where `T` is the
184
+ object passed as a scope to the block in `watchFor`. You can create custom
185
+ watchers based on this pattern.
186
+
187
+ ### Wait for app visibility and stability
188
+
189
+ Sometimes tests need to wait for elements to become visible or stable.
190
+ UI Automator offers several APIs to help with this.
191
+
192
+ The `waitForAppToBeVisible("com.example.targetapp")` waits for a UI element with
193
+ the given package name to appear on the screen within a customizable timeout.
194
+
195
+ // Wait for the app to be visible after launching it
196
+ startApp("com.example.targetapp")
197
+ waitForAppToBeVisible("com.example.targetapp")
198
+
199
+ Use the `waitForStable()` API to verify that the app's UI is considered stable
200
+ before interacting with it.
201
+
202
+ // Wait for the entire active window to become stable
203
+ activeWindow().waitForStable()
204
+
205
+ // Wait for a specific Ui element to become stable (e.g., after a loading animation)
206
+ onElement { viewIdResourceName == "my_loading_indicator" }.waitForStable()
207
+
208
+ > [!NOTE]
209
+ > **Note:** In most cases, `waitForStable()` isn't strictly necessary when using `onElement { ... }` because `onElement` already includes a timeout. Use `waitForStable()` primarily in combination with `onElements { ... }` to verify that all UI elements are visible, when you know that the UI is in an unstable state, or for specific screenshot testing scenarios where you need the UI to completely settle before capturing. `waitForStable()` works by waiting until no changes are detected in the accessibility tree for a set period. Note that this UI stability check doesn't guarantee that the app is fully idle, as background tasks might still be running.
210
+
211
+ ## Use UI Automator for Macrobenchmarks and Baseline Profiles
212
+
213
+ Use UI Automator for performance testing with [Jetpack Macrobenchmark](https://developer.android.com/topic/performance/benchmarking/macrobenchmark-overview)
214
+ and for generating [Baseline Profiles](https://developer.android.com/topic/performance/baselineprofiles/overview), as it provides a reliable way to
215
+ interact with your app and measure performance from an end-user perspective.
216
+
217
+ Macrobenchmark uses UI Automator APIs to drive the UI and measure interactions.
218
+ For example, in startup benchmarks, you can use `onElement` to detect when UI
219
+ content is fully loaded, enabling you to measure [Time to Full Display
220
+ (TTFD)](https://developer.android.com/topic/performance/vitals/launch-time#time-full). In jank benchmarks, UI Automator APIs are used to scroll lists or
221
+ run animations to measure frame timings. Functions like `startActivity()` or
222
+ `startIntent()` are useful for getting the app into the correct state before
223
+ measurement begins.
224
+
225
+ When [generating Baseline Profiles](https://developer.android.com/topic/performance/baselineprofiles/create-baselineprofile), you automate your app's critical user
226
+ journeys (CUJs) to record which classes and methods require pre-compilation. UI
227
+ Automator is an ideal tool for writing these automation scripts. The modern
228
+ DSL's predicate-based element finding and built-in wait mechanisms (`onElement`)
229
+ lead to more robust and deterministic test execution compared to other methods.
230
+ This stability reduces flakiness and ensures that the generated Baseline Profile
231
+ accurately reflects the code paths executed during your most important user
232
+ flows.
233
+
234
+ ## Advanced features
235
+
236
+ The following features are useful for more complex testing scenarios.
237
+
238
+ ### Interact with multiple windows
239
+
240
+ The UI Automator APIs let you directly interact with and inspect UI
241
+ elements. This is particularly useful for scenarios involving multiple windows,
242
+ such as Picture-in-Picture (PiP) mode or split-screen layouts.
243
+
244
+ // Find the first window that is in Picture-in-Picture mode
245
+ val pipWindow = windows()
246
+ .first { it.isInPictureInPictureMode == true }
247
+
248
+ // Now you can interact with elements within that specific window
249
+ pipWindow.onElement { textAsString() == "Play" }.click()
250
+
251
+ ### Screenshots and visual assertions
252
+
253
+ Capture screenshots of the entire screen, specific windows, or
254
+ individual UI elements directly within your tests. This is helpful for visual
255
+ regression testing and debugging.
256
+
257
+ uiautomator {
258
+ // Take a screenshot of the entire active window
259
+ val fullScreenBitmap: Bitmap = activeWindow().takeScreenshot()
260
+ fullScreenBitmap.saveToFile(File("/sdcard/Download/full_screen.png"))
261
+
262
+ // Take a screenshot of a specific UI element (e.g., a button)
263
+ val buttonBitmap: Bitmap = onElement { viewIdResourceName == "my_button" }.takeScreenshot()
264
+ buttonBitmap.saveToFile(File("/sdcard/Download/my_button_screenshot.png"))
265
+
266
+ // Example: Take a screenshot of a PiP window
267
+ val pipWindowScreenshot = windows()
268
+ .first { it.isInPictureInPictureMode == true }
269
+ .takeScreenshot()
270
+ pipWindowScreenshot.saveToFile(File("/sdcard/Download/pip_screenshot.png"))
271
+ }
272
+
273
+ The `saveToFile` extension function for Bitmap simplifies saving the captured
274
+ image to a specified path.
275
+
276
+ ### Use ResultsReporter for debugging
277
+
278
+ The `ResultsReporter` helps you associate test artifacts, like screenshots,
279
+ directly with your test results in Android Studio for easier inspection and
280
+ debugging.
281
+
282
+ uiAutomator {
283
+ startApp("com.example.targetapp")
284
+
285
+ val reporter = ResultsReporter("MyTestArtifacts") // Name for this set of results
286
+ val file = reporter.addNewFile(
287
+ filename = "my_screenshot",
288
+ title = "Accessible button image" // Title that appears in Android Studio test results
289
+ )
290
+
291
+ // Take a screenshot of an element and save it using the reporter
292
+ onElement { textAsString() == "Accessible button" }
293
+ .takeScreenshot()
294
+ .saveToFile(file)
295
+
296
+ // Report the artifacts to instrumentation, making them visible in Android Studio
297
+ reporter.reportToInstrumentation()
298
+ }
299
+
300
+ ## Migrate from older UI Automator versions
301
+
302
+ If you have existing UI Automator tests written with older API surfaces, use the
303
+ following table as a reference to migrate to the modern approach:
304
+
305
+ | Action type | Old UI Automator method | New UI Automator method |
306
+ |---|---|---|
307
+ | Entry point | `UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())` | Wrap test logic in the `uiAutomator { ... }` scope. |
308
+ | Find UI elements | `device.findObject(By.res("com.example.app:id/my_button"))` | `onElement { viewIdResourceName == "my\_button" }` |
309
+ | Find UI elements | `device.findObject(By.text("Click Me"))` | `onElement { textAsString() == "Click Me" }` |
310
+ | Wait for idle UI | `device.waitForIdle()` | Prefer `onElement`'s built-in timeout mechanism; otherwise, `activeWindow().waitForStable()` |
311
+ | Find child elements | Manually nested `findObject` calls | `onElement().onElement()` chaining |
312
+ | Handle permission dialogs | `UiAutomator.registerWatcher()` | `watchFor(PermissionDialog)` |
@@ -0,0 +1,87 @@
1
+ ---
2
+ name: harness-xml-to-compose
3
+ description: 提供结构化的 Android XML View 迁移到 Jetpack Compose 的工作流。详细说明从规划、依赖设置、主题和布局迁移、验证到 XML 清理的分步过程。当需要在 Android 项目中将 XML View 迁移到 Jetpack Compose 时使用。
4
+ license: Complete terms in LICENSE.txt
5
+ metadata:
6
+ author: Google LLC
7
+ keywords:
8
+ - Jetpack Compose
9
+ - 迁移
10
+ - XML
11
+ - Views
12
+ - 互操作性
13
+ - 渐进式采用
14
+ - UI 开发
15
+ ---
16
+
17
+ 本技能引导完成将现有 Android XML View 迁移到 Jetpack Compose 的过程。它遵循结构化的 10 步方法论,执行稳定、安全且视觉一致的过渡。本技能仅迁移 UI(XML → Jetpack Compose)。
18
+
19
+ ## 目标
20
+
21
+ 系统地将单个传统 XML 布局转换为现代声明式 Jetpack Compose UI,同时保持像素级视觉一致性和功能完整性。
22
+
23
+ ## 10 步迁移流程概览
24
+
25
+ 1. **识别最佳 XML 迁移候选**
26
+ 2. **分析项目与布局**
27
+ 3. **制定计划**
28
+ 4. **捕获 XML View UI 截图**
29
+ 5. **设置 Compose 依赖和编译器**
30
+ 6. **设置 Compose 主题**
31
+ 7. **将 XML 布局迁移到 Compose**
32
+ 8. **验证迁移结果**
33
+ 9. **替换使用处**
34
+ 10. **清理 XML 代码**
35
+
36
+ ## 详细步骤
37
+
38
+ ### 步骤 1:识别最佳 XML 迁移候选
39
+
40
+ 如果用户已明确指定目标 XML 布局,直接进入步骤 2。否则,按照 [references/identify-optimal-xml-candidate.md](references/identify-optimal-xml-candidate.md) 识别最佳迁移候选。
41
+
42
+ ### 步骤 2:分析项目与布局
43
+
44
+ 使用 [references/analysis-of-the-project-and-layout.md](references/analysis-of-the-project-and-layout.md) 指导对布局和项目上下文的技术审计。
45
+
46
+ ### 步骤 3:制定计划
47
+
48
+ 利用步骤 1 和 2 的输出和分析,生成迁移的分步计划。向用户展示计划并在继续前请求确认。
49
+
50
+ ### 步骤 4:捕获 XML View UI 截图
51
+
52
+ 请用户上传 XML View UI 的截图或提供文件绝对路径。将此截图作为步骤 7 布局迁移的视觉参考。
53
+
54
+ ### 步骤 5:设置 Compose 依赖和编译器
55
+
56
+ 检查 `build.gradle` 或 `libs.versions.toml` 中的 Compose 依赖和编译器配置。如缺失,参考 [设置 Compose 依赖和编译器](references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md)。
57
+
58
+ ### 步骤 6:设置 Compose 主题
59
+
60
+ 如果缺少 Compose 主题,进行初始化。对于基于 Material 的项目,遵循 [Material 3 迁移指南](references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md)。
61
+
62
+ **约束:** 不要迁移整个主题。仅实现特定 XML 候选所需的最小主题。保留原始 XML 主题以保持互操作性。
63
+
64
+ ### 步骤 7:将 XML View 迁移到 Compose
65
+
66
+ 将 XML 候选转换为 Jetpack Compose 代码,参考 [references/xml-layout-migration.md](references/xml-layout-migration.md) 和步骤 4 的截图。必须为新创建的可组合函数包含 **Compose Preview** 以便视觉验证。
67
+
68
+ ### 步骤 8:替换使用处
69
+
70
+ 将已迁移 XML 布局的使用替换为新的 Compose 组件。
71
+
72
+ ### 步骤 9:验证迁移结果
73
+
74
+ 将基线截图与新建可组合函数的 Compose Preview 渲染结果进行对比。迭代修改直到视觉一致。验证通过后,为新可组合函数编写 Compose UI 测试。
75
+
76
+ ### 步骤 10:清理 XML 代码
77
+
78
+ 删除已迁移的 XML 文件及其关联的旧测试。**注意:** 仅删除项目中其他部分未引用的代码和资源。
79
+
80
+ ---
81
+
82
+ ## 必须遵守的约束规则
83
+
84
+ > rules 引用路径:`../rules/<rule-name>.mdc`
85
+
86
+ - harness-compose-mandatory
87
+ - harness-mvi-layering
@@ -0,0 +1,42 @@
1
+ ## 1. Project health \& build validation
2
+
3
+ Before performing any analysis, you must confirm the project is in a functional state.
4
+ \* **Integrity check:** Verify the project syncs (Gradle) and builds successfully.
5
+ \* **Error resolution:** If there are pre-existing build errors or sync failures, you must report these immediately and attempt to fix. **Do not proceed** with migration until a stable baseline is established.
6
+
7
+ ## 2. Compose pattern \& consistency analysis
8
+
9
+ If Jetpack Compose is already present, you must align with the established implementation style.
10
+ \* **Pattern identification:** Scan the codebase for `@Composable` functions. Identify the project's "Best Practices" regarding state hoisting, composable construction and naming conventions, and file organization.
11
+ \* **Theming review:** Determine how `MaterialTheme` or custom theme systems are implemented.
12
+ \* Identify if the project uses a custom design system theme.
13
+ \* Map how attributes, styles, and other theme components are accessed in Compose.
14
+
15
+ ## 3. Design system \& infrastructure audit
16
+
17
+ Understand the design system classification (e.g. Material 2, Material 3, or custom design system).
18
+ \* **Resource mapping:** Locate central XML definitions:
19
+ \* `colors.xml` (Light/Dark variants)
20
+ \* `dimens.xml`
21
+ \* `styles.xml` / `themes.xml`
22
+ \* **Hybrid analysis:** Determine if the project is **XML-only** , **Compose-only** , or **Hybrid** .
23
+ \* **Reuse constraint:** If a Compose theming layer (e.g., `AppTheme.kt`) already exists, **DO NOT** generate a new one. You must reuse the existing infrastructure and contribute to it by following its existing implementation pattern.
24
+
25
+ ## 4. Candidate layout decomposition
26
+
27
+ Analyze the specific XML layout targeted for migration. You must extract and document the following requirements for the new composable:
28
+ \* **Inputs:** UI State objects, primitive parameters, and click listeners.
29
+ \* **Styling:** Specific color constants, typography styles, and shape definitions referenced in the XML.
30
+ \* **Resources:** Identifying string resources, drawables, and dimensions.
31
+ \* **Layout logic:** Modifiers required to replicate the XML constraints (padding, alignment, weight).
32
+
33
+ ## 5. Architectural \& non-UI analysis
34
+
35
+ Understand the environment in which the UI resides to ensure proper integration.
36
+ \* **State management:** Identify the usage of `ViewModel`, `Flow`, or `LiveData`.
37
+ \* **Dependency Injection:** Check for Hilt, Koin, or manual DI to understand how dependencies are provided to the UI layer.
38
+ \* **Testing \& architecture:** Note the architectural pattern (MVI, MVVM, or custom architecture setup.) and existing UI testing frameworks to ensure the migrated code remains testable. Unless the user explicitly requests, **DO NOT** make any changes to any non-UI code that aren't strictly required for the migration of the XML View.
39
+
40
+ *** ** * ** ***
41
+
42
+ > **Pro-tip:** Always prioritize the "Existing infrastructure" over "Default templates." If the project has a custom way of handling spacing or colors, composable code, or any other project layer, your generated Compose code must reflect that specific implementation.