deveco_hmigbot 0.21.5

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 (101) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +50 -0
  3. package/agents/hmigbot-worker.md +61 -0
  4. package/agents/hmigbot.md +22 -0
  5. package/agents/workflow-subagent.md +55 -0
  6. package/commands/hmigbot.md +17 -0
  7. package/dist/index.js +1 -0
  8. package/manifest.json +19 -0
  9. package/package.json +29 -0
  10. package/skills/migrate-core/FILES.md +26 -0
  11. package/skills/migrate-core/SKILL.md +484 -0
  12. package/skills/migrate-core/references/README.md +64 -0
  13. package/skills/migrate-core/references/flow/arkts-vector-gate.md +55 -0
  14. package/skills/migrate-core/references/flow/build-error-patterns.md +52 -0
  15. package/skills/migrate-core/references/flow/conventions-template.md +244 -0
  16. package/skills/migrate-core/references/flow/navigation-migration.md +42 -0
  17. package/skills/migrate-core/references/flow/platform-api-guards.md +59 -0
  18. package/skills/migrate-core/references/flow/platform-model-gaps.md +43 -0
  19. package/skills/migrate-core/references/flow/resource-conversion.md +46 -0
  20. package/skills/migrate-core/references/flow/ui-layout-semantics.md +124 -0
  21. package/skills/migrate-core/references/flow/unit-breakdown.md +42 -0
  22. package/skills/migrate-core/references/host-capabilities.md +24 -0
  23. package/skills/migrate-core/references/topics/app-identity.md +214 -0
  24. package/skills/migrate-core/references/topics/env-doctor.md +245 -0
  25. package/skills/migrate-core/references/topics/i18n/README.md +458 -0
  26. package/skills/migrate-core/references/topics/i18n/references/code-examples.md +304 -0
  27. package/skills/migrate-core/references/topics/i18n/references/common-pitfalls.md +354 -0
  28. package/skills/migrate-core/references/topics/i18n/references/dynamic-language-switch.md +464 -0
  29. package/skills/migrate-core/references/topics/i18n/references/language-codes.md +104 -0
  30. package/skills/migrate-core/references/topics/icon-sizing.md +98 -0
  31. package/skills/migrate-core/references/topics/library-migration/README.md +234 -0
  32. package/skills/migrate-core/references/topics/library-migration/closed-source-sdk.md +128 -0
  33. package/skills/migrate-core/references/topics/library-migration/download-api-decision.md +84 -0
  34. package/skills/migrate-core/references/topics/library-migration/library-mapping-table.md +100 -0
  35. package/skills/migrate-core/references/topics/library-migration/napi-compile-guide.md +84 -0
  36. package/skills/migrate-core/references/topics/library-migration/ohpm-search-guide.md +73 -0
  37. package/skills/migrate-core/references/topics/library-migration/stdlib-mapping-table.md +34 -0
  38. package/skills/migrate-core/references/topics/resources/aar-decompile.md +25 -0
  39. package/skills/migrate-core/references/topics/resources/conversion-rules.md +625 -0
  40. package/skills/migrate-core/references/topics/resources/dependency-analysis-rules.md +328 -0
  41. package/skills/migrate-core/references/topics/resources/material-design-icons.md +173 -0
  42. package/skills/migrate-core/references/topics/resources/svg-fix-patterns.md +175 -0
  43. package/skills/migrate-core/references/topics/resources/xml-drawable-to-svg-rules.md +513 -0
  44. package/skills/migrate-core/references/topics/system-capabilities/README.md +331 -0
  45. package/skills/migrate-core/references/topics/system-capabilities/avplayer-guide.md +161 -0
  46. package/skills/migrate-core/references/topics/system-capabilities/background-tasks.md +403 -0
  47. package/skills/migrate-core/references/topics/system-capabilities/browser-intent.md +121 -0
  48. package/skills/migrate-core/references/topics/system-capabilities/camera-picker.md +118 -0
  49. package/skills/migrate-core/references/topics/system-capabilities/document-picker.md +246 -0
  50. package/skills/migrate-core/references/topics/system-capabilities/file-utils.md +131 -0
  51. package/skills/migrate-core/references/topics/system-capabilities/permission-helper.md +112 -0
  52. package/skills/migrate-core/references/topics/system-capabilities/photo-access-helper.md +208 -0
  53. package/skills/migrate-core/references/topics/system-capabilities/print-management.md +213 -0
  54. package/skills/migrate-core/references/topics/system-capabilities/share-panel.md +177 -0
  55. package/skills/migrate-core/references/topics/system-capabilities/system-settings.md +322 -0
  56. package/skills/migrate-core/references/topics/system-capabilities/telephony-dial.md +49 -0
  57. package/skills/migrate-core/references/topics/system-capabilities/video-playback.md +42 -0
  58. package/skills/migrate-core/references/topics/system-capabilities/webview-patterns.md +38 -0
  59. package/skills/migrate-core/references/topics/ui-alignment/README.md +344 -0
  60. package/skills/migrate-core/references/topics/ui-alignment/references/dark-mode.md +47 -0
  61. package/skills/migrate-core/references/topics/ui-alignment/references/layout-mapping.md +301 -0
  62. package/skills/migrate-core/references/topics/ui-alignment/references/visual-patterns.md +411 -0
  63. package/skills/migrate-core/scripts/closure/check-anchors.mjs +186 -0
  64. package/skills/migrate-core/scripts/closure/check-api-guards.mjs +175 -0
  65. package/skills/migrate-core/scripts/closure/check-consumers.mjs +301 -0
  66. package/skills/migrate-core/scripts/closure/check-permissions.mjs +165 -0
  67. package/skills/migrate-core/scripts/closure/check-resources.mjs +130 -0
  68. package/skills/migrate-core/scripts/closure/check-routes.mjs +527 -0
  69. package/skills/migrate-core/scripts/closure/check-safearea.mjs +122 -0
  70. package/skills/migrate-core/scripts/closure/check-stubs.mjs +69 -0
  71. package/skills/migrate-core/scripts/closure/closure-suite.mjs +256 -0
  72. package/skills/migrate-core/scripts/closure/idioms.json +105 -0
  73. package/skills/migrate-core/scripts/convert/convert-resources.mjs +437 -0
  74. package/skills/migrate-core/scripts/feasibility/feasibility.mjs +235 -0
  75. package/skills/migrate-core/scripts/feasibility/tables/cross-platform.json +11 -0
  76. package/skills/migrate-core/scripts/feasibility/tables/deprecated-api.json +10 -0
  77. package/skills/migrate-core/scripts/feasibility/tables/imported-arkts-core.json +425 -0
  78. package/skills/migrate-core/scripts/feasibility/tables/lib-equivalence.json +206 -0
  79. package/skills/migrate-core/scripts/feasibility/tables/system-capabilities.json +22 -0
  80. package/skills/migrate-core/scripts/front.mjs +107 -0
  81. package/skills/migrate-core/scripts/interface/ark-extract.mjs +172 -0
  82. package/skills/migrate-core/scripts/interface/interface.mjs +152 -0
  83. package/skills/migrate-core/scripts/ledger/ledger.mjs +383 -0
  84. package/skills/migrate-core/scripts/ledger/parse-cards.mjs +98 -0
  85. package/skills/migrate-core/scripts/lib/literals.mjs +37 -0
  86. package/skills/migrate-core/scripts/lib/scan.mjs +315 -0
  87. package/skills/migrate-core/scripts/smoke/align-sdk.mjs +118 -0
  88. package/skills/migrate-core/scripts/smoke/ensure-sign.mjs +53 -0
  89. package/skills/migrate-core/scripts/smoke/smoke.mjs +238 -0
  90. package/skills/migrate-core/scripts/smoke/verdict.mjs +31 -0
  91. package/skills/migrate-core/scripts/smoke/walk.mjs +480 -0
  92. package/skills/migrate-core/scripts/transpile/mapping.json +76 -0
  93. package/skills/migrate-core/scripts/transpile/transpile-layout.mjs +404 -0
  94. package/skills/migrate-core/scripts/vectors/run-arkts-vectors.mjs +107 -0
  95. package/skills/migrate-core/scripts/vectors/setup-arkts-test.mjs +90 -0
  96. package/skills/migrate-core/scripts/wire/extractors.mjs +258 -0
  97. package/skills/migrate-core/scripts/wire/wire-routes.mjs +507 -0
  98. package/skills/migrate-core/templates/acceptance.js +365 -0
  99. package/skills/migrate-core/templates/explore.js +86 -0
  100. package/skills/migrate-core/templates/implement.js +211 -0
  101. package/skills/migrate-core/templates/mig_slices.js +491 -0
@@ -0,0 +1,625 @@
1
+ # Android to HarmonyOS Resource Conversion Rules
2
+
3
+ This document contains the complete, detailed rules for converting Android resources to HarmonyOS format. Read this before performing any conversions.
4
+
5
+ ## Table of Contents
6
+ 1. [Android Resource Directory Structure](#android-resource-directory-structure)
7
+ 2. [HarmonyOS Resource Directory Structure](#harmonyos-resource-directory-structure)
8
+ 3. [Values XML to Element JSON Conversion](#values-xml-to-element-json-conversion)
9
+ 4. [Media Resource Conversion](#media-resource-conversion)
10
+ 5. [Qualifier Mapping](#qualifier-mapping)
11
+ 6. [Special Cases and Edge Cases](#special-cases-and-edge-cases)
12
+
13
+ ---
14
+
15
+ ## Android Resource Directory Structure
16
+
17
+ Android resources live under `app/src/main/res/`. Common subdirectories:
18
+
19
+ | Directory | Contents |
20
+ |---|---|
21
+ | `drawable/` | Images (PNG, JPG, GIF, WEBP, BMP) and XML drawables (shapes, selectors, layer-lists, vector drawables) |
22
+ | `drawable-<qualifier>/` | Qualified drawable variants (e.g., `drawable-hdpi`, `drawable-night`) |
23
+ | `mipmap/` | Launcher icons (usually at multiple densities) |
24
+ | `mipmap-<qualifier>/` | Qualified launcher icon variants |
25
+ | `values/` | XML files defining strings, colors, dimensions, styles, themes, arrays, etc. |
26
+ | `values-<qualifier>/` | Qualified value variants (e.g., `values-ar`, `values-zh-rCN`, `values-night`) |
27
+ | `layout/` | XML layout definitions |
28
+ | `anim/` | Tween animation XML |
29
+ | `animator/` | Property animation XML |
30
+ | `color/` | Color state list XML |
31
+ | `menu/` | Menu definition XML |
32
+ | `raw/` | Arbitrary files copied as-is |
33
+ | `xml/` | Arbitrary XML files (preferences, configs, etc.) |
34
+ | `font/` | Font files (TTF, OTF, TTC) |
35
+ | `transition/` | Transition animation XML |
36
+ | `interpolator/` | Animation interpolator XML |
37
+
38
+ ## HarmonyOS Resource Directory Structure
39
+
40
+ HarmonyOS resources live under `entry/src/main/resources/`. Structure:
41
+
42
+ ```
43
+ resources/
44
+ ├── base/ # Default resources
45
+ │ ├── element/ # Key-value resources (JSON)
46
+ │ │ ├── string.json
47
+ │ │ ├── color.json
48
+ │ │ ├── float.json
49
+ │ │ ├── integer.json
50
+ │ │ ├── boolean.json
51
+ │ │ ├── plural.json
52
+ │ │ ├── strarray.json
53
+ │ │ └── intarray.json
54
+ │ ├── media/ # Images, audio, video
55
+ │ │ ├── icon.png
56
+ │ │ └── ...
57
+ │ └── profile/ # JSON configuration files
58
+ │ └── ...
59
+ ├── <qualifier>/ # Qualified resources (e.g., zh_CN, dark, ldpi)
60
+ │ ├── element/
61
+ │ ├── media/
62
+ │ └── profile/
63
+ ├── rawfile/ # Raw files (accessed by path)
64
+ └── resfile/ # Raw files (decompressed to sandbox)
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Values XML to Element JSON Conversion
70
+
71
+ ### strings.xml → string.json
72
+
73
+ **Android format:**
74
+ ```xml
75
+ <resources>
76
+ <string name="app_name">My App</string>
77
+ <string name="greeting">Hello, %1$s! You have %2$d messages.</string>
78
+ <string name="with_apostrophe">It\'s a test</string>
79
+ <string name="with_html"><![CDATA[<b>Bold</b> text]]></string>
80
+ </resources>
81
+ ```
82
+
83
+ **HarmonyOS format:**
84
+ ```json
85
+ {
86
+ "string": [
87
+ {
88
+ "name": "app_name",
89
+ "value": "My App"
90
+ },
91
+ {
92
+ "name": "greeting",
93
+ "value": "Hello, %1$s! You have %2$d messages."
94
+ },
95
+ {
96
+ "name": "with_apostrophe",
97
+ "value": "It's a test"
98
+ },
99
+ {
100
+ "name": "with_html",
101
+ "value": "<b>Bold</b> text"
102
+ }
103
+ ]
104
+ }
105
+ ```
106
+
107
+ **Rules:**
108
+ - Remove Android escape sequences: `\'` → `'`, `\"` → `"`
109
+ - Decode XML entities: `&amp;` → `&`, `&lt;` → `<`, `&gt;` → `>`, `&quot;` → `"`, `&apos;` → `'`
110
+ - Extract text from CDATA sections
111
+ - Preserve format placeholders (`%1$s`, `%2$d`, etc.) — HarmonyOS uses the same format
112
+ - ⚠️ **DO NOT drop the `$`**: Android positional format is `%1$s` / `%2$d`. A common silent bug is emitting `%1s` / `%2d` (no `$`). HarmonyOS `resourceManager.getStringSync(id, arg)` / `getPluralStringValueSync` only recognize `%s` / `%d` / `%1$s`; `%1s` / `%1d` are **invalid.
113
+ - **Mandatory self-check after writing string.json / plural.json**: `grep -rEn "%[0-9]+[a-z]" <out>/element/*.json` — any hit of `%<digit><letter>` WITHOUT a `$` (e.g. `%1s`, `%2d`) is a malformed placeholder; fix to `%1$s` / `%2$d`.
114
+ - If the string value is wrapped in quotes in Android XML (`"some text"`), remove the outer quotes
115
+ - Skip `<string>` elements with `translatable="false"` attribute? No — still include them, as they may be used at runtime. But note the translatable status.
116
+
117
+ ### colors.xml → color.json
118
+
119
+ **Android format:**
120
+ ```xml
121
+ <resources>
122
+ <color name="primary">#FF6200EE</color>
123
+ <color name="background">#FFFFFF</color>
124
+ <color name="semi_transparent">#80000000</color>
125
+ <color name="shorthand">#F00</color>
126
+ </resources>
127
+ ```
128
+
129
+ **HarmonyOS format:**
130
+ ```json
131
+ {
132
+ "color": [
133
+ {
134
+ "name": "primary",
135
+ "value": "#FF6200EE"
136
+ },
137
+ {
138
+ "name": "background",
139
+ "value": "#ffFFFFFF"
140
+ },
141
+ {
142
+ "name": "semi_transparent",
143
+ "value": "#80000000"
144
+ },
145
+ {
146
+ "name": "shorthand",
147
+ "value": "#ffFF0000"
148
+ }
149
+ ]
150
+ }
151
+ ```
152
+
153
+ **Rules:**
154
+ - `#AARRGGBB` (8 digits) → keep as-is (HarmonyOS uses same format: first 2 = opacity)
155
+ - `#RRGGBB` (6 digits) → prepend `ff` → `#ffRRGGBB`
156
+ - `#ARGB` (4 digits) → expand each: `#8F00` → `#88FF0000`
157
+ - `#RGB` (3 digits) → expand each and add `ff`: `#F00` → `#ffFF0000`
158
+ - Color values are case-insensitive in Android; preserve original case or normalize
159
+
160
+ ### dimens.xml → float.json
161
+
162
+ **Android format:**
163
+ ```xml
164
+ <resources>
165
+ <dimen name="text_size">16sp</dimen>
166
+ <dimen name="margin_large">24dp</dimen>
167
+ <dimen name="border_width">1px</dimen>
168
+ <dimen name="line_height">20dp</dimen>
169
+ </resources>
170
+ ```
171
+
172
+ **HarmonyOS format:**
173
+ ```json
174
+ {
175
+ "float": [
176
+ {
177
+ "name": "text_size",
178
+ "value": "16fp"
179
+ },
180
+ {
181
+ "name": "margin_large",
182
+ "value": "24vp"
183
+ },
184
+ {
185
+ "name": "border_width",
186
+ "value": "1px"
187
+ },
188
+ {
189
+ "name": "line_height",
190
+ "value": "20vp"
191
+ }
192
+ ]
193
+ }
194
+ ```
195
+
196
+ **Unit mapping:**
197
+ | Android Unit | HarmonyOS Unit | Notes |
198
+ |---|---|---|
199
+ | `dp` | `vp` | Density-independent pixels → virtual pixels |
200
+ | `dip` | `vp` | Same as dp |
201
+ | `sp` | `fp` | Scale-independent pixels → font pixels |
202
+ | `px` | `px` | Physical pixels (keep as-is) |
203
+ | `pt` | `vp` | Points → convert to vp (multiply by 2.22 — 1pt = 1/72 inch = 160/72 dp; same 160dp/inch baseline as `in`/`mm` below) |
204
+ | `in` | `vp` | Inches → convert to vp (multiply by 160) |
205
+ | `mm` | `vp` | Millimeters → convert to vp (multiply by 6.3) |
206
+ | (no unit) | `vp` | Plain number → append `vp` |
207
+
208
+ ### integers.xml → integer.json
209
+
210
+ **Android format:**
211
+ ```xml
212
+ <resources>
213
+ <integer name="max_items">10</integer>
214
+ <integer name="animation_duration">300</integer>
215
+ </resources>
216
+ ```
217
+
218
+ **HarmonyOS format:**
219
+ ```json
220
+ {
221
+ "integer": [
222
+ {
223
+ "name": "max_items",
224
+ "value": 10
225
+ },
226
+ {
227
+ "name": "animation_duration",
228
+ "value": 300
229
+ }
230
+ ]
231
+ }
232
+ ```
233
+
234
+ ### bools.xml → boolean.json
235
+
236
+ **Android format:**
237
+ ```xml
238
+ <resources>
239
+ <bool name="is_tablet">false</bool>
240
+ <bool name="show_ads">true</bool>
241
+ </resources>
242
+ ```
243
+
244
+ **HarmonyOS format:**
245
+ ```json
246
+ {
247
+ "boolean": [
248
+ {
249
+ "name": "is_tablet",
250
+ "value": false
251
+ },
252
+ {
253
+ "name": "show_ads",
254
+ "value": true
255
+ }
256
+ ]
257
+ }
258
+ ```
259
+
260
+ ### arrays.xml → strarray.json / intarray.json
261
+
262
+ **Android string-array:**
263
+ ```xml
264
+ <resources>
265
+ <string-array name="colors">
266
+ <item>Red</item>
267
+ <item>Green</item>
268
+ <item>Blue</item>
269
+ </string-array>
270
+ </resources>
271
+ ```
272
+
273
+ **HarmonyOS strarray.json:**
274
+ ```json
275
+ {
276
+ "strarray": [
277
+ {
278
+ "name": "colors",
279
+ "value": [
280
+ {
281
+ "value": "Red"
282
+ },
283
+ {
284
+ "value": "Green"
285
+ },
286
+ {
287
+ "value": "Blue"
288
+ }
289
+ ]
290
+ }
291
+ ]
292
+ }
293
+ ```
294
+
295
+ **Android integer-array:**
296
+ ```xml
297
+ <resources>
298
+ <integer-array name="scores">
299
+ <item>100</item>
300
+ <item>200</item>
301
+ <item>300</item>
302
+ </integer-array>
303
+ </resources>
304
+ ```
305
+
306
+ **HarmonyOS intarray.json:**
307
+ ```json
308
+ {
309
+ "intarray": [
310
+ {
311
+ "name": "scores",
312
+ "value": [
313
+ {
314
+ "value": 100
315
+ },
316
+ {
317
+ "value": 200
318
+ },
319
+ {
320
+ "value": 300
321
+ }
322
+ ]
323
+ }
324
+ ]
325
+ }
326
+ ```
327
+
328
+ ### plurals.xml → plural.json
329
+
330
+ **Android format:**
331
+ ```xml
332
+ <resources>
333
+ <plurals name="items_count">
334
+ <item quantity="one">%d item</item>
335
+ <item quantity="other">%d items</item>
336
+ </plurals>
337
+ </resources>
338
+ ```
339
+
340
+ **HarmonyOS format:**
341
+ ```json
342
+ {
343
+ "plural": [
344
+ {
345
+ "name": "items_count",
346
+ "value": [
347
+ {
348
+ "quantity": "one",
349
+ "value": "%d item"
350
+ },
351
+ {
352
+ "quantity": "other",
353
+ "value": "%d items"
354
+ }
355
+ ]
356
+ }
357
+ ]
358
+ }
359
+ ```
360
+
361
+ **Supported quantities (same for both):** `zero`, `one`, `two`, `few`, `many`, `other`
362
+
363
+ ---
364
+
365
+ ## Media Resource Conversion
366
+
367
+ ### Drawable images → media
368
+
369
+ Copy image files directly from Android `drawable/` to HarmonyOS `base/media/`:
370
+ - Supported formats in HarmonyOS: PNG, JPG, GIF, SVG, WEBP, BMP
371
+ - All these are also common Android formats, so direct copy works
372
+ - **Do NOT copy XML drawables** (shapes, selectors, vector drawables, layer-lists, ripple effects) — these have no direct HarmonyOS equivalent
373
+
374
+ ### Identifying XML vs image drawables
375
+
376
+ In `drawable/` directories, files can be either images or XML:
377
+ - `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.bmp`, `.svg` → image files, copy to `media/`
378
+ - `.xml` → XML drawable, **convert to SVG** (see `xml-drawable-to-svg-rules.md` for detailed rules). HarmonyOS supports SVG natively in `media/`. Output as `<original_name>.svg` in the target `media/` directory.
379
+ - `.9.png` → nine-patch image, copy to `media/` (note: HarmonyOS doesn't natively support nine-patch, but the file can still be used)
380
+
381
+ ### XML Drawable → SVG Conversion (Summary)
382
+
383
+ Android XML drawables should be converted to SVG format for HarmonyOS. The main convertible types are:
384
+
385
+ 1. **VectorDrawable** (`<vector>`) — Most straightforward. Android's `pathData` uses the same syntax as SVG `d` attribute. Convert `<path>`, `<group>`, `<clip-path>` elements to SVG equivalents.
386
+
387
+ 2. **ShapeDrawable** (`<shape>`) — Convert rectangles, ovals, lines, and rings to SVG `<rect>`, `<ellipse>`, `<line>`, or `<circle>` elements with appropriate fill, stroke, and gradient attributes.
388
+
389
+ 3. **LayerListDrawable** (`<layer-list>`) — Each `<item>` becomes a nested SVG element, layered in document order.
390
+
391
+ 4. **StateListDrawable** (`<selector>`) — Extract the default (no-state) `<item>` or the last `<item>` as fallback, and convert it to SVG. Log the state-dependent items in the conversion report as requiring manual handling.
392
+
393
+ 5. **Unconvertible types** — `<ripple>`, `<animated-vector>`, `<animated-selector>`, `<transition>` remain logged as unmappable because they involve runtime behavior that SVG cannot represent.
394
+
395
+ For the complete, detailed conversion rules with examples, read `xml-drawable-to-svg-rules.md`.
396
+
397
+ ### Mipmap → media
398
+
399
+ Launcher icons from `mipmap/` directories go to `base/media/` (or qualified `media/`):
400
+ - Typically named `ic_launcher.png`, `ic_launcher_round.png`, `ic_launcher_foreground.png`, `ic_launcher_background.png`
401
+ - PNG/WEBP launcher icons → direct copy to target `media/` directory
402
+ - **Adaptive icon XML files** (`<adaptive-icon>` root element, commonly found in `mipmap-anydpi-v26/`) → convert to HarmonyOS layered-image JSON. Parse the XML, extract the `background` and `foreground` layer references, and convert them using the rules below. Output as `<original_name>_layered_image.json` in the target `media/` directory. Only `background` and `foreground` are valid keys under the `"layered-image"` object — skip `monochrome` or any other elements.
403
+
404
+ **Reference conversion rules for layered-image values:**
405
+ - `@drawable/xxx` → `$media:xxx`
406
+ - `@mipmap/xxx` → `$media:xxx`
407
+ - `@color/xxx` → **must NOT use `$color:xxx`** — `layered-image` only accepts `$media:` references. See color-background handling below.
408
+
409
+ **Color background handling (critical):**
410
+
411
+ HarmonyOS `layered-image` does not support `$color:xxx` — only `$media:xxx` is valid for both `background` and `foreground`. When an Android `<background>` (or `<foreground>`) points to a color resource (`@color/xxx`):
412
+
413
+ 1. Resolve the actual hex color value by looking it up in the converted `color.json` or the Android `colors.xml`. If the color itself references another color, follow the chain to get the final hex value.
414
+ 2. Generate a solid-color PNG image filled entirely with that hex value. Any reasonable dimensions work (e.g., 1×1 px or 108×108 px).
415
+ 3. Save the PNG as `<color_name>_bg.png` in `base/media/` (e.g., `md_orange_700_bg.png`).
416
+ 4. Use `$media:<color_name>_bg` in the layered-image JSON.
417
+
418
+ **Adaptive icon JSON format example:**
419
+
420
+ For `ic_launcher.xml`:
421
+ ```xml
422
+ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
423
+ <background android:drawable="@color/md_orange_700" />
424
+ <foreground android:drawable="@mipmap/ic_launcher_foreground" />
425
+ <monochrome android:drawable="@drawable/ic_launcher_monochrome" />
426
+ </adaptive-icon>
427
+ ```
428
+
429
+ Suppose `@color/md_orange_700` resolves to `#F57C00`. Generate `base/media/md_orange_700_bg.png` (solid `#F57C00`). Converts to `ic_launcher_layered_image.json`:
430
+ ```json
431
+ {
432
+ "layered-image": {
433
+ "background": "$media:md_orange_700_bg",
434
+ "foreground": "$media:ic_launcher_foreground"
435
+ }
436
+ }
437
+ ```
438
+
439
+ Note: The `monochrome` element has no HarmonyOS `layered-image` equivalent, so omit it from the JSON output. But do not ignore it entirely — the drawable it references (e.g., `@drawable/ic_launcher_monochrome`) is a real resource that should be converted as a normal drawable and included in dependency analysis. If it's missing from the source `res/` directory (i.e., it comes from a library), record it as an unsatisfied dependency and attempt to recover it via APK decompilation in Step 5, just like any other missing resource.
440
+ - **VectorDrawable XML files** (if found in mipmap directories with `<vector>` root element) → convert to SVG, same as drawable vectors
441
+
442
+ **Common pattern**: `mipmap-anydpi-v26/` is extremely common in Android projects. The qualifier `anydpi-v26` should be parsed as `anydpi` (→ `base`) + `v26` (→ strip). The files inside are typically `<adaptive-icon>` XMLs — process them by reading the XML root element to classify the content type, not by rejecting based on the directory qualifier.
443
+
444
+ ### Raw files → rawfile
445
+
446
+ Copy all files from Android `raw/` to HarmonyOS `rawfile/`:
447
+ - Preserve original filenames
448
+ - These are accessed by path in both systems
449
+
450
+ ### Font files → rawfile/fonts
451
+
452
+ Copy font files from Android `font/` to HarmonyOS `rawfile/fonts/`:
453
+ - `.ttf`, `.otf`, `.ttc` files → direct copy
454
+ - Font XML files (font family definitions) → log as unmappable
455
+
456
+ ---
457
+
458
+ ## Qualifier Mapping
459
+
460
+ ### Density Qualifiers
461
+
462
+ The naming conventions differ between Android and HarmonyOS because HarmonyOS uses different DPI range labels:
463
+
464
+ | Android Qualifier | Approx DPI | HarmonyOS Qualifier | HarmonyOS DPI Range |
465
+ |---|---|---|---|
466
+ | `ldpi` | 120 | `sdpi` | (0, 120] |
467
+ | `mdpi` | 160 | `mdpi` | (120, 160] |
468
+ | `tvdpi` | 213 | `ldpi` | (160, 240] |
469
+ | `hdpi` | 240 | `ldpi` | (160, 240] |
470
+ | `xhdpi` | 320 | `xldpi` | (240, 320] |
471
+ | `xxhdpi` | 480 | `xxldpi` | (320, 480] |
472
+ | `xxxhdpi` | 640 | `xxxldpi` | (480, 640] |
473
+ | `nodpi` | N/A | `base` | No density qualifier; use base |
474
+ | `anydpi` | N/A | `base` | No density qualifier; use base |
475
+
476
+ ### Language/Region Qualifiers
477
+
478
+ Android format: `<type>-<language>` or `<type>-<language>-r<REGION>`
479
+ HarmonyOS format: `<language>` or `<language>_<REGION>`
480
+
481
+ **Examples:**
482
+ | Android | HarmonyOS |
483
+ |---|---|
484
+ | `values-ar` | `ar/element/` |
485
+ | `values-zh` | `zh/element/` |
486
+ | `values-zh-rCN` | `zh_CN/element/` |
487
+ | `values-zh-rTW` | `zh_TW/element/` |
488
+ | `values-en` | `en/element/` |
489
+ | `values-en-rUS` | `en_US/element/` |
490
+ | `values-en-rGB` | `en_GB/element/` |
491
+ | `values-fr-rFR` | `fr_FR/element/` |
492
+ | `values-ja` | `ja/element/` |
493
+ | `values-ko` | `ko/element/` |
494
+ | `drawable-zh-rCN-hdpi` | `zh_CN-ldpi/media/` |
495
+
496
+ **Parsing Android language qualifiers:**
497
+ - Language code: 2 or 3 lowercase letters (ISO 639)
498
+ - Region code: preceded by `r`, 2 uppercase letters (ISO 3166-1) — strip the `r` prefix
499
+ - Script code (BCP 47): preceded by `b+`, e.g., `b+sr+Latn` → `sr_Latn`
500
+
501
+ ### Orientation Qualifiers
502
+
503
+ | Android | HarmonyOS |
504
+ |---|---|
505
+ | `land` | `horizontal` |
506
+ | `port` | `vertical` |
507
+
508
+ ### Night Mode Qualifiers
509
+
510
+ | Android | HarmonyOS |
511
+ |---|---|
512
+ | `night` | `dark` |
513
+ | `notnight` | `light` |
514
+
515
+ ### Combining Multiple Qualifiers
516
+
517
+ Android directory names can contain multiple qualifiers separated by hyphens, e.g., `drawable-zh-rCN-night-hdpi` or `mipmap-anydpi-v26`.
518
+
519
+ **Parsing algorithm for any Android resource directory name:**
520
+
521
+ 1. Split the directory name by `-` to get segments
522
+ 2. The first segment is the resource type (`drawable`, `mipmap`, `values`, etc.)
523
+ 3. The remaining segments are qualifiers. Parse them left-to-right, recognizing:
524
+ - Language codes: 2-3 lowercase letters (e.g., `zh`, `ar`, `en`)
525
+ - Region codes: `r` + 2 uppercase letters (e.g., `rCN`, `rUS`) — always follows a language
526
+ - Density: `ldpi`, `mdpi`, `hdpi`, `xhdpi`, `xxhdpi`, `xxxhdpi`, `nodpi`, `anydpi`, `tvdpi`
527
+ - Orientation: `land`, `port`
528
+ - Night mode: `night`, `notnight`
529
+ - API level: `v` followed by digits (e.g., `v26`, `v21`) — **strip, do not reject**
530
+ - Screen size qualifiers: `sw<N>dp`, `w<N>dp`, `h<N>dp`, `small`, `normal`, `large`, `xlarge` — **skip entire directory, mark as unmapped**
531
+ - Other unsupported qualifiers — **strip, do not reject**
532
+ 4. Map each recognized qualifier to its HarmonyOS equivalent
533
+ 5. Strip only API-level, layout direction, screen shape, HDR, and aspect qualifiers (see "Unsupported Android Qualifiers" below)
534
+ 6. If any screen-size qualifiers remain (`sw<N>dp`, `w<N>dp`, `h<N>dp`, `small`/`normal`/`large`/`xlarge`), skip the entire directory — mark all resources as "unmapped" with reason "Unsupported qualifier"
535
+ 7. If no mappable or preserved qualifiers remain after stripping, use `base/`
536
+ 8. Reassemble remaining HarmonyOS qualifiers in correct order: MCC_MNC-language_script_country/region-orientation-device-colormode-density (preserved qualifiers go at the end)
537
+
538
+ **Examples:**
539
+ | Android Directory | Type | Qualifiers | HarmonyOS Dir |
540
+ |---|---|---|---|
541
+ | `drawable-hdpi` | drawable | hdpi→ldpi | `ldpi/media/` |
542
+ | `mipmap-anydpi-v26` | mipmap | anydpi→base, v26→stripped | `base/media/` |
543
+ | `drawable-zh-rCN-night-hdpi` | drawable | zh-rCN→zh_CN, night→dark, hdpi→ldpi | `zh_CN-dark-ldpi/media/` |
544
+ | `values-ko-rKR` | values | ko-rKR→ko_KR | `ko_KR/element/` |
545
+ | `drawable-night-v21` | drawable | night→dark, v21→stripped | `dark/media/` |
546
+
547
+ ### Unsupported Android Qualifiers
548
+
549
+ These Android qualifiers have no HarmonyOS equivalent. When encountered, **strip them** from the qualifier list (do not reject the directory). If stripping leaves no remaining qualifiers, use `base/`. If other valid qualifiers remain, use those.
550
+
551
+ Unsupported qualifiers to strip:
552
+ - API level `v<N>` (e.g., `v26`, `v21`, `v31`)
553
+ - Layout direction (`ldrtl`, `ldltr`)
554
+ - `round`, `notround` (screen shape)
555
+ - `highdr`, `lowdr` (HDR)
556
+ - `long`, `notlong` (screen aspect)
557
+
558
+ **Qualifiers without a HarmonyOS equivalent** (skip entirely, do NOT convert):
559
+ - `sw<N>dp` (smallest width, e.g., `sw600dp`)
560
+ - `w<N>dp` (available width, e.g., `w480dp`, `w600dp`)
561
+ - `h<N>dp` (available height)
562
+ - `small`, `normal`, `large`, `xlarge` (screen size)
563
+
564
+ These qualifiers have no HarmonyOS mapping. When a directory's only remaining qualifiers (after stripping API level etc.) are from this list, **skip all resources in that directory entirely**. Mark them as "unmapped" in the conversion report with reason "Unsupported qualifier: no HarmonyOS equivalent". Do NOT place them in `base/` or preserve the qualifier as-is — skipping avoids incorrect conversions.
565
+
566
+ **Important: multi-qualifier directory handling.** Android directory names often combine multiple qualifiers with hyphens. When parsing, extract ALL qualifiers, map each one independently, strip any unsupported ones, and then assemble the HarmonyOS qualifier from whatever remains.
567
+
568
+ **Examples of stripping unsupported qualifiers:**
569
+
570
+ | Android Directory | Qualifiers Parsed | After Mapping | HarmonyOS Target |
571
+ |---|---|---|---|
572
+ | `mipmap-anydpi-v26` | `anydpi` + `v26` | `anydpi` → `base`, `v26` → stripped | `base/media/` |
573
+ | `drawable-night-v21` | `night` + `v21` | `night` → `dark`, `v21` → stripped | `dark/media/` |
574
+ | `values-sw600dp` | `sw600dp` | **skip — unmapped** | N/A (skipped) |
575
+ | `values-w480dp` | `w480dp` | **skip — unmapped** | N/A (skipped) |
576
+ | `drawable-hdpi-v4` | `hdpi` + `v4` | `hdpi` → `ldpi`, `v4` → stripped | `ldpi/media/` |
577
+
578
+ The key principle: API-level qualifiers (`v<N>`) and a few others (layout direction, screen shape, HDR, aspect) are **silently stripped**. Screen-size qualifiers (`sw<N>dp`, `w<N>dp`, `h<N>dp`, `small`/`normal`/`large`/`xlarge`) cause the **entire directory to be skipped** — resources are marked as "unmapped" in the report because HarmonyOS has no equivalent qualifier. This avoids incorrect conversions and keeps the output clean.
579
+
580
+ ---
581
+
582
+ ## Special Cases and Edge Cases
583
+
584
+ ### Multiple values files contributing to the same JSON
585
+
586
+ Android projects often have multiple XML files under `values/` that all contain `<string>` or `<color>` entries. For example:
587
+ - `values/strings.xml` — main strings
588
+ - `values/strings_feature.xml` — feature-specific strings
589
+ - `values/google_strings.xml` — library strings
590
+
591
+ All `<string>` entries from any file go into a single `string.json`. Similarly for colors, dimens, etc. Collect entries across all files before writing.
592
+
593
+ ### Resource name conflicts
594
+
595
+ If two files define the same resource name, the last one wins (matching Android's behavior where later entries override earlier ones). Log these conflicts in the report.
596
+
597
+ ### Android resource references
598
+
599
+ Android values may reference other resources: `@string/other_string`, `@color/primary`, `@dimen/margin`. These references don't have a direct equivalent in HarmonyOS element JSON. Convert them as:
600
+ - `@string/name` → `$string:name`
601
+ - `@color/name` → `$color:name`
602
+ - `@dimen/name` → `$float:name`
603
+ - `@integer/name` → `$integer:name`
604
+ - `@bool/name` → `$boolean:name`
605
+ - `?attr/name` → log as unmappable (theme attribute reference)
606
+
607
+ ### Android system resource references
608
+
609
+ References like `@android:color/black` or `@android:string/ok` are Android system resources. Map known ones to literal values or HarmonyOS system resources where possible. Unknown ones should be logged in the report.
610
+
611
+ ### Empty or comment-only XML files
612
+
613
+ Skip these silently — don't create empty JSON files.
614
+
615
+ ### Large resource sets
616
+
617
+ When an Android project has hundreds of resources, process them systematically:
618
+ 1. First scan and inventory all resources
619
+ 2. Group by type and qualifier
620
+ 3. Convert each group
621
+ 4. Verify completeness
622
+
623
+ ### XML encoding and BOM
624
+
625
+ Some Android XML files may have BOM (Byte Order Mark) or non-UTF-8 encoding declarations. Handle these gracefully — read with the declared encoding, output UTF-8 JSON.