ui: a switch for screenshot protection on Android and macOS #51

Closed
asxpi wants to merge 0 commits from asxpi/anotherim-js:feat/screenshot-protection into develop
First-time contributor

Until now, screenshots were blocked only as a side effect of the app lock: FLAG_SECURE on Android while the lock was on, and nothing on macOS. That left two cases uncovered: someone who uses the lock but wants to screenshot their chats, and someone who wants screenshots blocked without a lock.

What it does

  • The switch: "Screenshot protection" in Settings › Privacy, in the "Lock and encryption" card. It appears only where the system can block captures: Android and macOS.
  • Android: the shell's existing setSecure (FLAG_SECURE). Screenshots and recordings come out black, and the recent-apps card is blank.
  • macOS: a new screen_protect command (src-tauri/src/screen_protect.rs) sets the content protection of every window: the main window, page windows and XML consoles, including ones opened later. Screenshots, recordings and screen sharing show them empty. The command is in build.rs and capabilities/default.json.
  • Default: the setting screen_protect is '1' or '0'. While it's unset, protection follows the app lock, so nothing changes for anyone who hasn't touched the switch.
  • When the window is told: only after both the lock and the setting have been read, so a default that hasn't loaded yet never leaves the chats open to a screenshot. <aim-app-lock> still does the telling, as it did before. The logic is in ui/src/state/screen-protect.ts.
  • Strings: 3 new ones, in all catalogues (i18n-extract --check --strict passes). The CHANGELOG gets an Unreleased Added entry.

Not covered

  • Linux: neither X11 nor Wayland lets an app refuse capture, and Tauri's content protection does nothing there.
  • Browser tabs: there's no API for it.
  • Windows: supports it through the same Tauri call (SetWindowDisplayAffinity). Turning it on would take a line in screenProtectKind() plus a Windows wording of the description; it's left out of this PR.

Tested

  • test/screen-protect.test.ts, 4 tests:
    • On Android, it follows the lock until the switch is used, then keeps the switch's value both ways.
    • The row is in the card, shows the lock's state, and writes the setting.
    • macOS calls screen_protect.
    • No row in a browser.
  • Existing tests: app-lock-views and preferences-views still pass, 41 tests across the three files.
  • make check STRICT=1 is clean.
  • Rust: cargo check --features desktop passes on Linux.
  • Android build: a debug APK built from this branch with make docker-android.
  • Not yet tried by hand: a phone (GrapheneOS should behave like stock Android here) and a Mac.

Before merging

Rebase onto the current develop. If newer commits open another kind of window from Rust, call crate::screen_protect::dress(&window) after building it, as console_window.rs and page_window.rs do.

🤖 Generated with Claude Code

Until now, screenshots were blocked only as a side effect of the app lock: FLAG_SECURE on Android while the lock was on, and nothing on macOS. That left two cases uncovered: someone who uses the lock but wants to screenshot their chats, and someone who wants screenshots blocked without a lock. ## What it does - **The switch:** "Screenshot protection" in Settings › Privacy, in the "Lock and encryption" card. It appears only where the system can block captures: Android and macOS. - **Android:** the shell's existing `setSecure` (FLAG_SECURE). Screenshots and recordings come out black, and the recent-apps card is blank. - **macOS:** a new `screen_protect` command (`src-tauri/src/screen_protect.rs`) sets the content protection of every window: the main window, page windows and XML consoles, including ones opened later. Screenshots, recordings and screen sharing show them empty. The command is in `build.rs` and `capabilities/default.json`. - **Default:** the setting `screen_protect` is `'1'` or `'0'`. While it's unset, protection follows the app lock, so nothing changes for anyone who hasn't touched the switch. - **When the window is told:** only after both the lock and the setting have been read, so a default that hasn't loaded yet never leaves the chats open to a screenshot. `<aim-app-lock>` still does the telling, as it did before. The logic is in `ui/src/state/screen-protect.ts`. - **Strings:** 3 new ones, in all catalogues (`i18n-extract --check --strict` passes). The CHANGELOG gets an Unreleased **Added** entry. ## Not covered - **Linux:** neither X11 nor Wayland lets an app refuse capture, and Tauri's content protection does nothing there. - **Browser tabs:** there's no API for it. - **Windows:** supports it through the same Tauri call (`SetWindowDisplayAffinity`). Turning it on would take a line in `screenProtectKind()` plus a Windows wording of the description; it's left out of this PR. ## Tested - **`test/screen-protect.test.ts`**, 4 tests: - On Android, it follows the lock until the switch is used, then keeps the switch's value both ways. - The row is in the card, shows the lock's state, and writes the setting. - macOS calls `screen_protect`. - No row in a browser. - **Existing tests:** `app-lock-views` and `preferences-views` still pass, 41 tests across the three files. - **`make check STRICT=1`** is clean. - **Rust:** `cargo check --features desktop` passes on Linux. - **Android build:** a debug APK built from this branch with `make docker-android`. - **Not yet tried by hand:** a phone (GrapheneOS should behave like stock Android here) and a Mac. ## Before merging Rebase onto the current `develop`. If newer commits open another kind of window from Rust, call `crate::screen_protect::dress(&window)` after building it, as `console_window.rs` and `page_window.rs` do. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking screenshots came only with the app lock: FLAG_SECURE on
Android while the lock was on, nothing on macOS. Someone who wants the
lock but takes screenshots of their chats, or wants no screenshots
without a lock, had no say.

Settings > Privacy now has "Screenshot protection" in the lock and
encryption card, where the system has it. On Android it is the shell's
existing FLAG_SECURE; on macOS a new screen_protect command sets the
content protection of every window, those opened later included, so
screenshots, recordings and screen sharing show them empty. Until the
switch is used it follows the app lock, as before, and the window is
told only once both are read.

Assisted-by: Claude:opus-5-5
Owner

Merged into develop by hand as ca94b14b (gate: make check STRICT=1 clean, make test-ui 2667 passed, cargo check --features desktop clean). Thank you.

Merged into develop by hand as ca94b14b (gate: make check STRICT=1 clean, make test-ui 2667 passed, cargo check --features desktop clean). Thank you.
ann closed this pull request 2026-10-24 22:08:45 +00:00

Pull request closed

Sign in to join this conversation.
No description provided.