Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ only use that interface, the libre app uses `NoSyncHooks` (no sync UI), and Plus
- dependencies both apps use go in `gradle/libs.versions.toml` here; MarkNotes Plus reads this catalog as `libs`;
- the Room schema (`data/SyncDatabase.kt`) keeps the sync tables, so the database of users upgrading from versions
that synced, and Plus, keep working.
- `:app` strips `INTERNET` and `ACCESS_NETWORK_STATE` from this offline edition (Plus keeps them through
`:app-shared`), so code that needs the network must live behind `SyncHooks`; `NoSyncHooks` never touches it.

## Build and test

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.maxdac.marknotes

import android.Manifest
import android.content.pm.PackageManager
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

/** This edition is offline only: it requests no network permissions and still launches without them. */
@RunWith(AndroidJUnit4::class)
class NoNetworkPermissionsTest {
private val context = InstrumentationRegistry.getInstrumentation().targetContext

@Test
fun launchesWithoutNetworkPermissions() {
assertEquals(PackageManager.PERMISSION_DENIED, context.checkSelfPermission(Manifest.permission.INTERNET))
assertEquals(
PackageManager.PERMISSION_DENIED,
context.checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE)
)
context.appContainer.settings.setGettingStartedConsumed(true)
ActivityScenario.launch(MainActivity::class.java).use { }
}
}
7 changes: 6 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<!-- This edition is offline only. :app-shared declares these for the cloud providers of MarkNotes Plus. -->
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" tools:node="remove" />

<!-- MainActivity and the FileProvider come from :app-shared. -->
<application
Expand Down
9 changes: 5 additions & 4 deletions docs/fdroid.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,10 @@ To repeat the release smoke check on a **disposable emulator** (the script clear
bash scripts/test-release-apk.sh app/build/outputs/apk/release/app-release-unsigned.apk
```

The inclusion report's remaining permission entries are expected: `INTERNET` and `ACCESS_NETWORK_STATE` come from
`:app-shared` for the cloud providers of MarkNotes Plus (this app ships none and does not use them), `USE_BIOMETRIC` supports optional app lock, and AndroidX's signature-protected
`DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION` protects its receivers. Removing them to silence the report would
break functionality or platform safeguards. Fastlane listing information, the reproducible reference APK,
The APK requests no network permissions: `:app` strips `INTERNET` and `ACCESS_NETWORK_STATE` (declared by
`:app-shared` for the cloud providers of MarkNotes Plus) with `tools:node="remove"`, and the libre app never observes network
state (`NoSyncHooks`). The inclusion report's remaining permission entries are expected: `USE_BIOMETRIC`
supports optional app lock, and AndroidX's signature-protected `DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION` protects its
receivers. Removing them would break functionality or platform safeguards. Fastlane listing information, the reproducible reference APK,
the signing-certificate identity, and ABI/size information are informational, not defects. Preserve both ABIs;
code/resource shrinking, rather than ABI splitting, addresses the bulk of the old APK size.
2 changes: 0 additions & 2 deletions scripts/check-release-apk.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ def check(apk: Path, aapt2: Path) -> None:
).stdout
actual = set(re.findall(r"^uses-permission: name='([^']+)'", permissions, re.MULTILINE))
expected_permissions = {
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.USE_BIOMETRIC",
"io.github.maxdac.marknotes.libre.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
}
Expand Down
2 changes: 0 additions & 2 deletions scripts/test-release-apk.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ def check_fixture(self, *, marker=True, debug=False, missing_native=False, extra
if extra_native:
archive.writestr("lib/armeabi-v7a/libunexpected.so", b"ELF")
permissions = [
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.USE_BIOMETRIC",
"io.github.maxdac.marknotes.libre.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
]
Expand Down
Loading