Skip to content

feat: target Android 17 and ask for local network access - #6977

Open
AndyScherzinger wants to merge 3 commits into
masterfrom
feat/target-sdk-37
Open

AndyScherzinger wants to merge 3 commits into
masterfrom
feat/target-sdk-37

Conversation

@AndyScherzinger

@AndyScherzinger AndyScherzinger commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Raises targetSdk from 36 to 37 (lint OldTargetApi, 14 → 13) and adds what Android 17 needs for that: the local network permission. Without it, a server on the LAN is unreachable: requests time out after 45 s with no hint about a permission (verified on an Android 17 emulator).

📡 Local network permission (ACCESS_LOCAL_NETWORK)

Asked only on Android 17+, and only where it matters:

  • Server selection (typed URL and login QR code): when the server is a .local name or resolves to a private, link-local, CGNAT or unique local address. The resolved address is checked, not just the URL, so LAN host names are covered.
  • Conversation list start, for the current account: covers existing accounts after the update and servers that only resolve locally at home (split DNS).
  • First call: lets peers on the same network connect directly. Calls still work through TURN without it, so a denial isn't asked again.

When it's denied, a dialog explains why it's needed and offers to ask again, or to open the app settings once the system no longer shows its prompt (after two denials). Dismissing it on server selection shows an error instead of running into the timeout. Chrome asks for its own Nearby devices permission during browser login for a LAN server; there's deliberately no warning for that for now.

Verified on the Android 17 emulator (gplay build of this branch, RESTRICT_LOCAL_NETWORK enforced, server on 10.0.2.2):

  • The permission is needed for plain HTTP to the server, not only for mDNS/NSD: a TCP request made under the app's UID (run-as, app in the foreground) to 10.0.2.2:8081 times out after 8 s with the permission revoked and returns 200 OK with it granted. A request to the public 1.1.1.1:80 succeeds either way.
  • Existing LAN account: the system prompt appears when the conversation list opens. Denying it shows the dialog ("Set permissions" asks again); after the second denial the button turns into "Open settings", which opens the app's settings page. Allowing it loads the list from the server.
  • Server selection with a LAN address and the permission denied: the dialog appears at once instead of the 45 s timeout; Dismiss shows "Allow local network access to connect to this server."
  • Server selection with a public server (cloud.nextcloud.com) and the permission denied: no prompt, browser login opens.
  • QR code path: not run on the emulator. The server is read from the QR code by ServerSelectionActivity.serverFromQr, unit-tested for both QR formats (nc://login/, nc://onetime-login/) and any element order, and then goes through the same check as a typed URL.
  • Not exercised: the first-call prompt (needs an account on a public server; with a LAN server the conversation list has already asked).

🔍 Rest of the Android 17 changes

Checked against the codebase and on an Android 17 emulator (API 37, generic and gplay builds at target 37); no code change needed:

  • Background audio hardening: voice messages auto-advance in the background, calls, picture-in-picture and voice recording keep audio focus.
  • Background activity launch: incoming call full-screen intent on the lock screen and Answer from the heads-up notification work.
  • ContactsContract column removal: contact sync still finds and updates linked contacts.
  • Static final reflection and MessageQueue: Robolectric 4.17 supports SDK 37; the full gplay unit test suite passes (1128 tests); no runtime reflection or native-load errors on device.
  • Certificate Transparency on by default: a public HTTPS server works through the custom trust manager.
  • gplay: Firebase token registration and push delivery (app in background and killed) work.

🖼️ Screenshots

Android's own "Nearby devices" permission prompt over the conversation list The app's dialog after the first denial, with "Set permissions" The same dialog after the second denial, with "Open settings" Server selection with a local network server and the permission denied, showing the error text
t2 t3 t5 t9

🚧 TODO

  • Screenshots of the permission prompt and the denial dialog
  • On a real Android 17 device: Bluetooth / wired headset switches during a call in the background
  • LAN peer-to-peer call with and without the permission
  • Self-signed and user-CA servers (Certificate Transparency)
  • Background blur in a video call on a gplay build (MediaPipe native libraries; the emulator ran out of memory)
  • connectedAndroidTest on an API 37 emulator (gplay debug, 51 tests passed; LoginIT and ShareUtilsIT are @Ignored in the code)
  • Rebase and recount the lint score after chore(res): move the adaptive launcher icon to mipmap-anydpi (lint 14 → 13) #6975 (both lower it by one)

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔖 Capability is checked or not needed
  • 🔙 Backport requests are created or not needed: /backport to stable-xx.x
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@AndyScherzinger AndyScherzinger added this to the 26.0.0 milestone Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

📱 QA build

Download app-qa-debug.apk
QR code Open the QR code for this download
Commit 33e7a54
Version 6977
Available until 7 days after this build

The QA build installs alongside a released Nextcloud app, so you can keep
using your existing install while testing.

Downloading the file requires a GitHub account, so open this link on the
device you want to test on, or transfer the APK to it.

@AndyScherzinger
AndyScherzinger force-pushed the feat/target-sdk-37 branch 2 times, most recently from 4bb0c96 to 07697ce Compare October 29, 2026 07:17
Apps targeting API 37 need ACCESS_LOCAL_NETWORK to reach the local
network. Without it, a request to a server on the LAN never reaches
it and times out after 45 s with no hint about a permission.

Ask for it where it matters, and only on Android 17 and later:
- on server selection, and for a scanned login QR code, when the
  server is a .local name or resolves to a private, link-local, CGNAT
  or unique local address
- when the conversation list opens, for the current account, so
  existing accounts and servers that only resolve locally at home
  are covered too
- on the first call, so peers on the same network can connect
  directly; calls still work through TURN without it, so a denial is
  not asked again

When the permission is denied, a dialog explains why it's needed and
offers to ask again, or to open the app settings once the system no
longer shows its prompt.

While the app targets API 36 the permission is granted implicitly
through INTERNET, so nothing is asked before the targetSdk bump.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Andy Scherzinger <[email protected]>
Verified on an Android 17 emulator with generic and gplay builds:
local network access, voice messages and calls in the background,
picture-in-picture, incoming calls on the lock screen and from the
heads-up notification, push delivery, contact sync, Certificate
Transparency against a public server, and the Robolectric tests on
SDK 37.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Andy Scherzinger <[email protected]>
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Andy Scherzinger <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

Codacy

Lint

TypemasterPR
Warnings1413
Errors00

SpotBugs

CategoryBaseNew
Bad practice77
Correctness88
Dodgy code4040
Internationalization33
Malicious code vulnerability33
Performance88
Security1111
Total8080

@AndyScherzinger
AndyScherzinger marked this pull request as ready for review October 30, 2026 14:16
@AndyScherzinger AndyScherzinger added the 3. to review Waiting for reviews label Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews AI assisted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant