Commit Graph
25 Commits
Author SHA1 Message Date
Linus Rath b9db3764ff fix: stop the cold start flashing white and the mail header jumping in
On a cold start the splash was followed by about a second of blank
white, then mail rows whose header sat under the status bar until it
popped in and pushed the list down.

- `AppTheme` had no `android:windowBackground`, so while JS loaded the
  window showed the platform default (near-white, or grey at night).
  It is now the app's own background, #ffffff by day and #09090b at
  night (`values-night`), matching `src/theme/tokens.ts`.
- `NavigationContainer` had no theme, so React Navigation painted its
  light default behind and between screens even in dark mode. It now
  uses the palette's background.
- The mail list took its top inset from the native `SafeAreaView`,
  which on Fabric only learns the insets a few frames after mounting.
  It now pads with `useSafeAreaInsets()`, which the navigator's
  safe-area provider fills from the initial window metrics on the first
  render; the value is the same, it just arrives in time.
2026-09-24 19:35:47 +02:00
Linus Rath 695aa23563 fix: show the Bulwark shield instead of the stock envelope in the status bar 2026-09-24 19:09:36 +02:00
Linus Rath 8618abf1d7 fix: open a group mailbox notification's message in the group account #839
The notification only carried the local account it was posted for, so
tapping one for a message in a group or shared mailbox opened the
thread against the user's own JMAP account, where the message doesn't
exist.

The background task now passes the JMAP account the message was
fetched from as `jmapAccountId`. The native module stores it as an
intent extra, validated like the other ids, and hands it back with the
tap. `App.tsx` routes the open with it, the way the unified inbox does
for group messages. Notifications posted before this change have no
such extra and open against the account's own mail as before.
2026-09-24 19:09:36 +02:00
Linus Rath 24849baca5 fix: let the offline mail cache grow past 6 MB on android
AsyncStorage caps its Android SQLite database at 6 MB unless
`AsyncStorage_db_size_in_MB` is set. The offline cache keeps message
bodies in that database, defaults to 50 MB and can be set to 500 MB,
so it filled the database long before its own limit, after which every
AsyncStorage write failed, including the account registry, the outbox
and the mail list cache. Raise the ceiling to 1 GB. It is a maximum,
not a preallocation, and needs a native rebuild to take effect.
2026-09-24 18:56:37 +02:00
Linus Rath 746572c784 fix: raise the android versionCode with every release
`versionCode` was hard-coded to 1, so every release looked like the
same version to Android. It is now derived from `VERSION` as
`major * 10000000 + minor * 10000 + patch` (0.1.62 gives 10062), which
is above the 1 existing installs have and keeps growing, so Android
never mistakes an update for a downgrade.

The formula only increases while patch stays below 10000 and minor
below 1000. `build.gradle` refuses a `VERSION` outside that range or
outside Android's 2100000000 ceiling, and `scripts/bump-version.mjs`,
which only ever bumps patch, refuses to create such a version before
anything is committed or tagged.
2026-09-24 18:52:15 +02:00
Linus Rath 6f0abb4384 fix: stop signing release apks with the public debug key
Every published APK up to 0.1.62 was signed with the React Native
template's debug keystore, whose key is public. Anyone could sign an
"update" that Android installs over the app, with access to its
SecureStore credentials and mail cache. The release build type fell
back to the debug signing config whenever no release key was passed,
and the workflow carried on silently when `ANDROID_KEYSTORE_BASE64`
was empty.

- `android/app/build.gradle` reads the release key from the
  `BULWARK_RELEASE_*` gradle properties or environment variables and
  has no fallback. Without them a release build fails in the new
  `checkReleaseSigning` task. It only runs for release variants, so
  debug builds and `expo run:android` are unchanged. A local test
  build can opt in with `-PallowDebugSignedRelease=true`, which is
  ignored whenever `CI` is set.
- The release workflow fails in its first step when a signing secret
  is missing, checks the keystore, alias and password before the
  build, and refuses a debug key uploaded as the release key.
- An optional `ANDROID_SIGNING_LINEAGE_BASE64` secret re-signs the APK
  with APK Signature Scheme v3 key rotation from the debug key to the
  release key, from API 28, so existing installs on Android 9+ can
  update and stop trusting the debug key afterwards.
- Before anything is uploaded, `apksigner verify` has to show the
  release key as the Android 9+ signer, never the debug certificate.
- `*.keystore` and `*.lineage` files are gitignored.

Audit item S2 in `docs/audit-2026-09.md`.
2026-09-24 18:52:15 +02:00
Linus Rath 06e89422bd fix: open the composer for mailto links sent with SENDTO
Most apps start an email with `ACTION_SENDTO` and a `mailto:` URI. The
manifest offered the app for it, but React Native's Linking only
forwards VIEW intents, so the app opened on the inbox instead of the
composer.

MainActivity now rewrites a `SENDTO mailto:` intent into the equivalent
`VIEW mailto:` link before React Native sees it, on a cold start and
when the running app receives it. The EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC,
EXTRA_SUBJECT and EXTRA_TEXT extras are folded into the link's query.
Bcc recipients of a mailto link now reach the composer too; they were
dropped for VIEW links as well.
2026-09-24 18:43:43 +02:00
Linus Rath cd4ce9d08b fix: upload files shared into the app with their real name and type
Sharing a photo or document from another app into Bulwark failed every
time: the upload task was handed the share's `content://` URI, but it
can only stream from a file path, so it failed with "Directory for
'/external/images/media/…' doesn't exist". The attachment was also named
after the URI's last segment (a MediaStore row id such as "1000000027"),
and SEND_MULTIPLE shares only carried a wildcard type like `image/*`.

- `uploadBlob` copies `content://` URIs into the cache, uploads the copy
  and deletes it afterwards, also when the upload fails
- `ShareIntentStore` asks the providing app for the display name, size
  and MIME type when the intent arrives, falling back to the URI segment
  plus an extension for the MIME type
- the composer gets the real name, type and size, so the size limit
  check now applies to shared files too
2026-09-24 18:43:43 +02:00
Linus Rath ee04e95d4f feat: add UnifiedPush as an alternative to FCM for push notifications 2026-09-24 18:17:43 +02:00
Linus Rath 5802caeea9 feat: open deep links, mailto: URLs and share-sheet payloads in the app 2026-08-29 18:20:01 +02:00
Linus Rath 7f9f5af7e6 fix: keep the mail cache and outbox out of Android auto-backup 2026-08-29 18:11:07 +02:00
Linus Rath 6f747db858 fix: resolve redirects in JS for client-certificate requests and pass blob deadlines to the native path (#627) 2026-08-29 18:03:24 +02:00
Linus Rath 00faceb25f fix: subscribe to EmailDelivery only, use the relay's email ids and route pushes per account (#45) 2026-08-29 17:53:53 +02:00
Linus Rath ac95a2bc39 feat: QR code sign-in 2026-06-05 19:25:00 +02:00
Linus Rath 1858d08dd0 feat: enhance notification handling with accountId support and improve file management functions 2026-05-14 12:57:03 +02:00
Linus Rath e9b93bc6e5 fix: import ByteArrayOutputStream in BulwarkFcmModule 2026-05-08 01:03:11 +02:00
Linus Rath 29b06a3a4f security: fix push SSE breakage, harden APK updates and email rendering 2026-05-05 22:06:07 +02:00
Linus Rath 6d5195d9fa feat: implement offline mail caching and sync functionality 2026-05-03 18:40:01 +02:00
Linus Rath c7ea4d757c feat: implement client certificate support with secure fetch and alias management 2026-05-03 17:33:54 +02:00
Linus Rath a76e0fe8c0 feat: enhance APK installation process with progress tracking and UI updates 2026-04-26 22:22:52 +02:00
Linus Rath 5ac2a142b5 feat: update Android build configuration to use arm64-v8a architecture and improve caching mechanism 2026-04-26 21:58:08 +02:00
Linus Rath a8a0d475db chore: update readme 2026-04-26 04:57:10 +02:00
Linus Rath 96bddad289 chore: update gradlew file permissions to executable 2026-04-26 04:18:58 +02:00
Linus Rath ef63d8fa86 feat: update versioning system and remove app.json 2026-04-26 04:15:57 +02:00
Linus Rath 365ffefd33 chore: add Android release CI and sync local work
CI:
- .github/workflows/release-android.yml builds APK on release publish
  and via workflow_dispatch, attaches it to the release.
- android/app/build.gradle: optional release signingConfig driven by
  Gradle properties (ANDROID_KEYSTORE_BASE64 secret etc.); falls back
  to the debug keystore when no secrets are set.
- .gitignore: untrack /android so the runner can build directly;
  ignore build outputs (build/, .cxx/), Metro/Expo dev logs, scratch.

Track android/ sources including BulwarkFcmPackage.kt and
google-services.json (Firebase Android keys are public per Google's
docs and intended to ship in the APK).

JS sync: push notifications + background task, vacation responder
(api + store), contact activity component, search utilities, settings
polish, calendar/contacts/email store and screen tweaks.

Tooling: scripts/poll-reload.mjs — Windows polling-watcher that hits
Metro /reload on file change (workaround for unreliable fs.watch
without Watchman).
2026-04-26 04:12:08 +02:00