Skip to content

Commit d133464

Browse files
update docs
1 parent 293be6c commit d133464

5 files changed

Lines changed: 124 additions & 2 deletions

File tree

docs/architecture/intents.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,78 @@ class WiFiActivity(Activity):
814814

815815
**Pattern:** Method chaining with `startActivityForResult()` for specialized camera modes.
816816

817+
---
818+
819+
## Deep Links & URL Handling
820+
821+
MicroPythonOS supports opening URLs (e.g., from QR codes) through a deep-link mechanism. The system parses the URL and either opens the App Store on a linked app or dispatches an intent to a third-party URL handler.
822+
823+
### Official Store Links
824+
825+
QR codes can point directly to an app in the App Store using these link formats:
826+
827+
```
828+
https://apps.micropythonos.com/app/<app_id>[?v=<min_version>&s=<source>]
829+
microPythonOS://app/<app_id>[?...]
830+
mpos://app/<app_id>[?...]
831+
```
832+
833+
All three forms are equivalent and case-insensitive (`MPOS://APP/COM.EXAMPLE.PAINT` works too). The link only carries the app's identity — never a download URL — so the App Store resolves it against its trusted catalog.
834+
835+
Opening a store link launches the App Store on the linked app's detail page:
836+
837+
```python
838+
from mpos.content.deeplink import open_url
839+
840+
open_url("https://apps.micropythonos.com/app/com.example.myapp")
841+
```
842+
843+
### Third-Party URL Handlers
844+
845+
Apps can register URL handlers in their `MANIFEST.JSON` via a `urlPattern` in an activity's `intent_filters`:
846+
847+
```json
848+
{
849+
"activities": [
850+
{
851+
"entrypoint": "main.py",
852+
"classname": "MainActivity",
853+
"intent_filters": [
854+
{ "action": "view_url", "urlPattern": "https://store.acme.example/app/*" }
855+
]
856+
}
857+
]
858+
}
859+
```
860+
861+
Rules for `urlPattern`:
862+
863+
- Must look like `scheme://host/...` with a literal host (no wildcards in host).
864+
- A trailing `*` is the only wildcard allowed and matches any suffix.
865+
- Patterns matching the official store host (`apps.micropythonos.com`) or the `mpos://` / `microPythonOS://` schemes are reserved for the system and rejected at registration.
866+
- Matching is a case-insensitive scheme-and-host prefix match.
867+
868+
When a URL is opened, the system checks for matching third-party handlers. One match dispatches directly; several open the chooser. No sticky default is set, so a later-installed app is never permanently shadowed.
869+
870+
```python
871+
from mpos.content.deeplink import open_url
872+
873+
# Dispatches to the app whose urlPattern matches the URL
874+
open_url("https://store.acme.example/app/123")
875+
```
876+
877+
### QR Code Integration
878+
879+
QR scanners (e.g., the Camera app) can check whether decoded text is a dispatchable link:
880+
881+
```python
882+
from mpos.content.deeplink import open_action_label
883+
884+
label = open_action_label(scanned_text)
885+
if label:
886+
print(f"Offer action: {label}") # "Open in App Store" or "Open link"
887+
```
888+
817889
## Best Practices
818890

819891
### 1. Choose the Right Intent Type
@@ -991,7 +1063,7 @@ MicroPythonOS Intents are inspired by Android's Intent system but simplified for
9911063
| **Intent Filters** | ✅ Manifest + programmatic | ✅ In manifest | File-type filters in `MANIFEST.JSON`, generic handlers via code |
9921064
| **Categories** | ❌ Not supported | ✅ Supported | Simplified routing |
9931065
| **Data Types** | ⚠️ Path patterns | ✅ MIME types | `pathPattern` suffix matching; `mimeType` is stored but not used for matching |
994-
| **URI Schemes** | ❌ Not matched | ✅ Supported | No scheme filtering |
1066+
| **URI Schemes** | `mpos://` / `microPythonOS://` | ✅ Supported | Official schemes reserved for system; third-party `urlPattern` matching available |
9951067
| **Chooser UI** | ✅ ChooserActivity | ✅ Intent chooser | Custom implementation |
9961068
| **Result Callbacks** | ✅ Callback-based | ✅ onActivityResult() | Different mechanism |
9971069
| **Method Chaining** | ✅ putExtra() returns self | ❌ No chaining | MicroPythonOS advantage |

docs/frameworks/download-manager.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ The `DownloadManager.download_url()` method automatically detects whether it's c
7878

7979
This means you can use the same API in both async and sync code without any wrapper functions.
8080

81+
## Redirect Handling
82+
83+
DownloadManager follows HTTP redirects with the following constraints:
84+
85+
- **Status codes followed:** 301 (Moved Permanently), 302 (Found), 303 (See Other).
86+
- **Status codes NOT followed:** 307 (Temporary Redirect), 308 (Permanent Redirect). These are treated as the final response.
87+
- **Maximum redirects: 1 hop.** The HTTP client (`aiohttp`) makes at most 2 requests per call — the original URL plus one redirect. A chain of 2 or more redirects will fail: the final redirect response body (typically empty) is treated as the download content, resulting in a parse error or corrupt file.
88+
89+
!!! warning
90+
If you need to redirect `https://updates.micropythonos.org/...` to `https://updates.micropythonos.com/...`, ensure the `.com` endpoint responds directly with a 200 — do not chain another redirect. A 2-hop chain (`.org``.com``.com?__direct=1`) will exhaust the redirect budget.
91+
8192
## API Reference
8293

8394
### `DownloadManager.download_url()`

docs/frameworks/notification-manager.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ Available sounds:
7676
| `Scale up` | `scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b` |
7777
| `Superhappy` | `superhappy:d=8,o=5,b=635:c,e,g,c,e,g,c,e,g,c6,e6,g6,c6,e6,g6,c7,e7,g7,c7,e7,g7,c7,e7,g7` |
7878

79-
The default sound is `Coin`. If no buzzer output is available, the notification posts silently. Apps can change the sound programmatically:
79+
The default sound is `Coin`.
80+
81+
On macOS desktop builds the notification buzzer sound is skipped because it was causing `tests/test_graphical_topmenu_drawer.py` to hang on the GitHub test workflow, possibly because the GitHub CI server doesn't have a sound card. It would be better to only skip this on the CI server, or only skip it if there's no sound card.
82+
83+
On other platforms, if no buzzer output is available, the notification posts silently. Apps can change the sound programmatically:
8084

8185
```python
8286
from mpos import SharedPreferences

docs/os-development/automated-testing.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,29 @@ To run all unit tests, do:
6363
./tests/unittest.sh --ondevice # this takes a long time
6464
```
6565

66+
## Test Runner Flags
67+
68+
The `test_runner.py` script (used by `unittest.sh` internally) supports these additional flags:
69+
70+
| Flag | Description |
71+
|------|-------------|
72+
| `--no-install-test-apps` | Skip automatic installation of test apps before on-device runs. By default, `--ondevice` runs call `install_test_apps.sh` automatically. |
73+
| `--logserial <filename>` | Write raw serial output to a file for debugging communication issues. |
74+
| `--coverage` | Enable code coverage tracking on desktop builds (requires a coverage build — see `./scripts/build_mpos.sh unix coverage`). |
75+
| `--coverage-save <file.json>` | Save coverage data to a JSON file for later aggregation or HTML report generation. |
76+
| `--coverage-load <file.json>` | Load previously saved coverage data to merge with the current run. |
77+
78+
### Coverage Example
79+
80+
```
81+
# Build with coverage support
82+
./scripts/build_mpos.sh unix coverage
83+
84+
# Run tests with coverage and save results
85+
python3 scripts/test_runner.py --coverage --coverage-save cov.json tests/test_a.py tests/test_b.py
86+
87+
# Generate an HTML report
88+
python3 scripts/coverage_report.py cov.json -o coverage/index.html
89+
```
90+
6691

docs/os-development/running-on-desktop.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ Native Windows builds are not supported. [Users report](https://github.com/Micro
112112

113113
---
114114

115+
## Keyboard shortcuts
116+
117+
The desktop emulator supports these keyboard shortcuts:
118+
119+
| Shortcut | Action |
120+
|----------|--------|
121+
| Ctrl+Shift+S (Cmd+Shift+S on macOS) | Save a screenshot as BMP in the working directory |
122+
123+
Screenshots are saved with a timestamped filename like `screenshot-YYYYMMDD-HHMMSS.bmp`. The path is printed to the console so you know exactly where the file was written.
124+
115125
## Deploying to hardware
116126

117127
Once your app works on desktop, install it on a supported ESP32 device.

0 commit comments

Comments
 (0)