diff --git a/data/runs.json b/data/runs.json index 0c87a0b..333d549 100644 --- a/data/runs.json +++ b/data/runs.json @@ -674,5 +674,45 @@ "verbatim": true, "exit": 0, "output": "the Download folder holds 1 file\n mobium-report.txt 44 bytes 2026-09-29 03:41" + }, + "app_press[2]": { + "tool": "app_press", + "index": 2, + "command": "mobium press dpad-down", + "verbatim": true, + "exit": 0, + "output": "pressed dpad-down — focus moved to homepage_container" + }, + "app_press[3]": { + "tool": "app_press", + "index": 3, + "command": "mobium press back --gesture", + "verbatim": true, + "exit": 0, + "output": "swiped back from the left edge, halfway down — com.android.settings is still in the foreground; app_map shows which screen" + }, + "app_upload[1]": { + "tool": "app_upload", + "index": 1, + "command": "mobium upload ./seed --device-path /sdcard/seed", + "verbatim": true, + "exit": 0, + "output": "uploaded …/seed to /sdcard/seed (a folder of 2 files, 8 bytes) — confirmed by each of its 2 files' sizes read back on the device" + }, + "app_download[2]": { + "tool": "app_download", + "index": 2, + "command": "mobium download --device-path /sdcard/seed -o seed-copy", + "verbatim": true, + "exit": 0, + "output": "downloaded seed from /sdcard/seed to …/seed-copy (a folder of 2 files, 8 bytes) — confirmed by each of its 2 files' sizes read back against the device's" + }, + "app_fill[1]": { + "tool": "app_fill", + "index": 1, + "command": "mobium fill label=Volume 0.3", + "verbatim": true, + "exit": 0, + "output": "moved label=Volume to position 0.3 — it reads \"3.0\", was \"5.0\"" } } diff --git a/examples/canonical.json b/examples/canonical.json index af36f79..f6d43a3 100644 --- a/examples/canonical.json +++ b/examples/canonical.json @@ -230,6 +230,14 @@ "title": "List what the folder holds", "cli": "mobium download", "args": {} + }, + { + "title": "Bring back a folder from a path on the device", + "cli": "mobium download --device-path /sdcard/seed -o seed-copy", + "args": { + "device_path": "/sdcard/seed", + "path": "seed-copy" + } } ], "app_drag": [ @@ -259,6 +267,14 @@ "target": "testid=search", "text": "coffee" } + }, + { + "title": "Move a slider to a position", + "cli": "mobium fill label=Volume 0.3", + "args": { + "target": "label=Volume", + "text": "0.3" + } } ], "app_find": [ @@ -468,6 +484,21 @@ "args": { "button": "home" } + }, + { + "title": "Move focus with a TV remote's D-pad", + "cli": "mobium press dpad-down", + "args": { + "button": "dpad-down" + } + }, + { + "title": "Go back with a swipe in from the edge", + "cli": "mobium press back --gesture", + "args": { + "button": "back", + "gesture": true + } } ], "app_press_drag": [ @@ -763,6 +794,14 @@ "args": { "path": "invoice-42.txt" } + }, + { + "title": "Send a folder to a path on the device", + "cli": "mobium upload ./seed --device-path /sdcard/seed", + "args": { + "path": "./seed", + "device_path": "/sdcard/seed" + } } ], "app_wait_for": [ diff --git a/examples/dotnet.json b/examples/dotnet.json index 38091c4..da20055 100644 --- a/examples/dotnet.json +++ b/examples/dotnet.json @@ -120,6 +120,9 @@ }, { "code": "foreach (var f in device.Downloads())\n{\n Console.WriteLine($\"{f[\"name\"]} {f[\"bytes\"]}\");\n}" + }, + { + "code": "var got = device.PullPath(\"/sdcard/seed\", \"seed-copy\");\nConsole.WriteLine($\"{got[\"files\"]} {got[\"path\"]}\");" } ], "app_drag": [ @@ -135,6 +138,9 @@ "app_fill": [ { "code": "device.Fill(\"testid=search\", \"coffee\");" + }, + { + "code": "device.Fill(\"label=Volume\", \"0.3\"); // a slider: its position, from 0 to 1" } ], "app_find": [ @@ -241,6 +247,12 @@ }, { "code": "device.Press(\"home\");" + }, + { + "code": "device.Press(\"dpad-down\");" + }, + { + "code": "var went = device.Back(gesture: true);\nConsole.WriteLine($\"{went[\"foreground\"]} {went[\"confirmed\"]}\");" } ], "app_press_drag": [ @@ -393,6 +405,9 @@ "app_upload": [ { "code": "var sent = device.Upload(\"invoice-42.txt\");\nConsole.WriteLine($\"{sent[\"where\"]} {sent[\"bytes\"]}\");" + }, + { + "code": "var sent = device.PushPath(\"seed\", \"/sdcard/seed\");\nConsole.WriteLine($\"{sent[\"files\"]} {sent[\"checked\"]}\");" } ], "app_wait_for": [ diff --git a/examples/go.json b/examples/go.json index 3c8484d..d6cb7eb 100644 --- a/examples/go.json +++ b/examples/go.json @@ -120,6 +120,9 @@ }, { "code": "files, err := dev.Downloads(ctx, \"\")\nif err != nil {\n\treturn err\n}\nfor _, f := range files {\n\tfmt.Println(f.Name, f.Bytes)\n}" + }, + { + "code": "got, err := dev.PullPath(ctx, \"/sdcard/seed\", \"seed-copy\", \"\")\nif err != nil {\n\treturn err\n}\nfmt.Println(got.Files, got.Path)" } ], "app_drag": [ @@ -135,6 +138,9 @@ "app_fill": [ { "code": "if err := dev.Fill(ctx, \"testid=search\", \"coffee\"); err != nil {\n\treturn err\n}" + }, + { + "code": "// A slider: its position, from 0 to 1.\nif err := dev.Fill(ctx, \"label=Volume\", \"0.3\"); err != nil {\n\treturn err\n}" } ], "app_find": [ @@ -241,6 +247,12 @@ }, { "code": "if err := dev.Press(ctx, \"home\"); err != nil {\n\treturn err\n}" + }, + { + "code": "if err := dev.Press(ctx, \"dpad-down\"); err != nil {\n\treturn err\n}" + }, + { + "code": "went, err := dev.Back(ctx, true)\nif err != nil {\n\treturn err\n}\nfmt.Println(went.Foreground, went.Confirmed)" } ], "app_press_drag": [ @@ -393,6 +405,9 @@ "app_upload": [ { "code": "sent, err := dev.Upload(ctx, \"invoice-42.txt\", nil)\nif err != nil {\n\treturn err\n}\nfmt.Println(sent.Where, sent.Bytes, sent.Checked)" + }, + { + "code": "sent, err := dev.PushPath(ctx, \"seed\", \"/sdcard/seed\", \"\")\nif err != nil {\n\treturn err\n}\nfmt.Println(sent.Files, sent.Checked)" } ], "app_wait_for": [ diff --git a/examples/java.json b/examples/java.json index 90ba203..25531d7 100644 --- a/examples/java.json +++ b/examples/java.json @@ -120,6 +120,9 @@ }, { "code": "for (Map f : device.downloads()) {\n System.out.println(f.get(\"name\") + \" \" + f.get(\"bytes\"));\n}" + }, + { + "code": "Map got = device.pullPath(\"/sdcard/seed\", \"seed-copy\");\nSystem.out.println(got.get(\"files\") + \" \" + got.get(\"path\"));" } ], "app_drag": [ @@ -135,6 +138,9 @@ "app_fill": [ { "code": "device.fill(\"testid=search\", \"coffee\");" + }, + { + "code": "device.fill(\"label=Volume\", \"0.3\"); // a slider: its position, from 0 to 1" } ], "app_find": [ @@ -241,6 +247,12 @@ }, { "code": "device.press(\"home\");" + }, + { + "code": "device.press(\"dpad-down\");" + }, + { + "code": "Map went = device.back(true);\nSystem.out.println(went.get(\"foreground\") + \" \" + went.get(\"confirmed\"));" } ], "app_press_drag": [ @@ -393,6 +405,9 @@ "app_upload": [ { "code": "Map sent = device.upload(\"invoice-42.txt\");\nSystem.out.println(sent.get(\"where\") + \" \" + sent.get(\"bytes\"));" + }, + { + "code": "Map sent = device.pushPath(\"seed\", \"/sdcard/seed\");\nSystem.out.println(sent.get(\"files\") + \" \" + sent.get(\"checked\"));" } ], "app_wait_for": [ diff --git a/examples/javascript.json b/examples/javascript.json index d91f4da..6d529f0 100644 --- a/examples/javascript.json +++ b/examples/javascript.json @@ -120,6 +120,9 @@ }, { "code": "for (const f of await device.downloads()) {\n console.log(f.name, f.bytes)\n}" + }, + { + "code": "const got = await device.pullPath('/sdcard/seed', { path: 'seed-copy' })\nconsole.log(got.files, got.path)" } ], "app_drag": [ @@ -135,6 +138,9 @@ "app_fill": [ { "code": "await device.fill('testid=search', 'coffee')" + }, + { + "code": "await device.fill('label=Volume', '0.3') // a slider: its position, from 0 to 1" } ], "app_find": [ @@ -241,6 +247,12 @@ }, { "code": "await device.press('home')" + }, + { + "code": "await device.press('dpad-down')" + }, + { + "code": "const went = await device.back({ gesture: true })\nconsole.log(went.foreground, went.confirmed)" } ], "app_press_drag": [ @@ -393,6 +405,9 @@ "app_upload": [ { "code": "const sent = await device.upload('invoice-42.txt')\nconsole.log(sent.where, sent.bytes, sent.checked)" + }, + { + "code": "const sent = await device.pushPath('seed', '/sdcard/seed')\nconsole.log(sent.files, sent.checked)" } ], "app_wait_for": [ diff --git a/examples/python.json b/examples/python.json index 1f6ce7a..3166f6d 100644 --- a/examples/python.json +++ b/examples/python.json @@ -120,6 +120,9 @@ }, { "code": "for f in device.downloads():\n print(f[\"name\"], f[\"bytes\"])" + }, + { + "code": "got = device.pull_path(\"/sdcard/seed\", path=\"seed-copy\")\nprint(got[\"files\"], got[\"path\"])" } ], "app_drag": [ @@ -135,6 +138,9 @@ "app_fill": [ { "code": "device.fill(\"testid=search\", \"coffee\")" + }, + { + "code": "device.fill(\"label=Volume\", \"0.3\") # a slider: its position, from 0 to 1" } ], "app_find": [ @@ -241,6 +247,12 @@ }, { "code": "device.press(\"home\")" + }, + { + "code": "device.press(\"dpad-down\")" + }, + { + "code": "went = device.back(gesture=True)\nprint(went[\"foreground\"], went[\"confirmed\"])" } ], "app_press_drag": [ @@ -393,6 +405,9 @@ "app_upload": [ { "code": "sent = device.upload(\"invoice-42.txt\")\nprint(sent[\"where\"], sent[\"bytes\"], sent[\"checked\"])" + }, + { + "code": "sent = device.push_path(\"seed\", \"/sdcard/seed\")\nprint(sent[\"files\"], sent[\"checked\"])" } ], "app_wait_for": [ diff --git a/scripts/capture.py b/scripts/capture.py index 3f431e6..c507fb0 100644 --- a/scripts/capture.py +++ b/scripts/capture.py @@ -9,7 +9,7 @@ Emulators only. It changes settings — appearance, orientation, locale, timezone, the clipboard — and puts each back, but it is not for a phone. - python3 scripts/capture.py --bin ./mobium --device emulator-5554 [--only app_tap] + python3 scripts/capture.py --bin ./mobium --device emulator-5554 [--only app_tap] [--only 'app_press[2]'] """ import argparse @@ -113,7 +113,7 @@ def app_screen(name): pause=3.0, restore=[f"reset-permissions {APP}"]), dict(tool="app_location", i=1), # The Clock app's big digits, not Settings' Date & time: there the zone - # and the time are grey text, and the two pictures looked the same. + # and the time are gray text, and the two pictures looked the same. dict(tool="app_timezone", i=0, setup=["terminate com.google.android.deskclock", "launch com.google.android.deskclock", "tap testid=tab_menu_clock", "wait 'label=Add city'"], @@ -219,6 +219,13 @@ def app_screen(name): restore=["$adb shell rm -f /sdcard/Download/mobium-report.txt", "$adb shell content delete --uri content://media/external/downloads " "--where \"\\\"_display_name='mobium-report.txt'\\\"\""]), + # Since 2026-10-05: the D-pad and an edge-swipe back, a folder to and from a + # device path, and a slider. Output only: each page already has its picture. + dict(tool="app_press", i=2, setup=settings_root()), + dict(tool="app_press", i=3, setup=settings_root() + ["tap 'text=Network & internet'", "wait text=Internet"]), + dict(tool="app_upload", i=1, setup=["$mkdir -p seed && printf 'one\\n' > seed/a.txt && printf 'two\\n' > seed/b.txt"]), + dict(tool="app_download", i=2, setup=["$rm -rf seed-copy"], restore=["$adb shell rm -rf /sdcard/seed"]), + dict(tool="app_fill", i=1, setup=app_screen("Slider Demo")), dict(tool="app_session", i=0), dict(tool="app_session", i=1), ] @@ -262,9 +269,11 @@ def save(png, name): timezone = json.loads(tz).get("timezone", "") if tz.strip().startswith("{") else "" for p in PLAN: tool, i = p["tool"], p["i"] - if a.only and tool not in a.only: - continue key = f"{tool}[{i}]" if i is not None else f"{tool}:{p['cmd']}" + # --only takes a tool (every run of it) or one run's key, app_press[2], + # so adding a scenario does not re-take the pictures beside it. + if a.only and tool not in a.only and key not in a.only: + continue def steps(ss): for s in ss: if s.startswith("$"):