Repository navigation
3.4.0: blind drop, notes with a lifetime, sealed notes, shortcuts, keyboard without learning - #53
Merged
Merged
Conversation
… notes Decisions D-040 to D-044, written before the code, with the facts read in the code that shape them. REPRISE points to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
D-040 — Keyboard without learning, on by default (Patrice). Every field asks IME_FLAG_NO_PERSONALIZED_LEARNING while the setting is on; a secret's field always does. The interceptor of SaisieDeCoffre is shared (ClavierSansApprentissage), the note's native body reads a CompositionLocal. Setting in Security, 5 languages. D-041 — Launcher shortcuts "New note" and "Dictation", published by the code (the app has several application ids), in the app's language. They land on a NON-exported activity that deposits the request in memory and opens the app, which carries it out once unlocked: MainActivity keeps ignoring intents. The in-memory deposit of the share receiver becomes a generic DepotEnMemoire. Dictation opens the microphone as a tap on its button would. Checked on the S9: the Samsung launcher starts the non-exported activity; New note opens a blank note to be written; Dictation, without a model, the install screen. D-042 — Blind drop: write a note without unlocking the app, read nothing. DepotActivity (not exported, protected window, text actions of other apps and classifier cut since it can be the first activity of its process, text never in the saved state), its quick settings tile (unlockAndRun when the phone is locked) and a third shortcut. The note goes to the Inbox, never a vault; nothing is written while a panic is pending. The language of an activity and the dark/light choice are shared helpers now (avecLaLangueChoisie, estSombre) instead of living in MainActivity alone. Tests: ClavierSansApprentissageTest (3), ChampDuCorpsTest +1, ReglagesHeritesTest +1 (instrumented, S9); RaccourcisTest (4), DepotViewModelTest (5) on the JVM. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two columns on notes, migration 10 -> 11, additive: expires_at (epoch ms, NULL for never) and read_once (INTEGER NOT NULL DEFAULT 0). Every existing note gets no lifetime. - NotesRepository.setLifetime writes those two columns only, not updated_at: giving a note a lifetime is not editing it. A duration counts from now. - purgeExpired: one DELETE, the one "Delete permanently" runs, so the FTS index (notes_ad, secure-delete), the links (foreign keys) and secure_delete treat an expired note as an erased one. The trash's notes too; a vault note needs no key. - Bulk export (listAllAlive) and the encrypted backup (poidsDesNotes) leave such notes out (Patrice: a restore must not bring them back); a restored note has no lifetime. - audits/verifier-schema-room-vs-flutter.py replays 10 -> 11: no divergence between the Flutter schema migrated to 11 and Room's 11.json. Tests on the S9: MigrationVersDixTest (3, a new case for the base of 3.1 to 3.3 at schema 10, migrated by MIGRATION_10_11 alone; the purge erases that note and that note only), LegacyDatabaseOpeningTest (15), NoteLinkTest (5), NotesRepositoryTest (67), SauvegardeChiffreeTest (9) — 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The editor's ⋮ menu has "Lifetime…": none, 1 hour, 24 hours, 7 days, 30 days,
after reading. A tap applies it. The card shows what is left ("5 h", "after
reading"), TalkBack says it, on a locked vault note too — not a secret.
- Notes whose lifetime is over are erased at the opening of the app
(StartupViewModel) and every minute while the list is on screen.
- "After reading" erases the note in the editor ViewModel's onCleared, after the
last save — not on the screen's disposal, which a rotation triggers. A choice
made while the note is open counts from its next opening; the reader is told
once the note is open.
- detekt's thresholds moved the lifetime out of NotesRepository (DureesDeVie)
and grouped the card's two sheets (FeuillesDeLaFiche) on the editor screen.
- Texts in the five languages, plurals included.
Tests: ResteDeVieTest (5) and DureesDeVieTest (5) on the JVM; on the S9
LectureUniqueTest (3: erased at closing; control, chosen in the session;
witness without lifetime), EditeurTest (36), RechercheDansLaNoteEcranTest (5),
FermetureDuCoffreTest (9), LiensDansUnCoffreTest (3), GestesSurDesNotesTest (14),
AccueilTest (20) — 0 failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The encrypted backup's container — Argon2id, AES-256-GCM, the 48-byte header as AAD — under its own magic, NTSEALED, with its own bound (4 MiB: a note of 500 000 characters may weigh 1.5 MB in UTF-8). FichierDeSauvegarde takes the magic and the bound as parameters whose defaults are the backup's: a backup is written and read exactly as before. One note as JSON (title, content, colour, tags, readOnce), sealed by a generated code of 24 signs (120 bits). Only a code opens it: a typed text that is not one is refused before any derivation. The tag is checked before the JSON is read; a wrong code and a damaged file look the same. The limits of a note are checked on what is read. Tests on the S9: FichierDeNoteScelleeTest (6: round trip however the code is typed and nothing in clear in the file; another code; a damaged file; a text that is not a code; a backup or any other file; past the bound), and the backup unchanged: SauvegardeChiffreeTest (9), LectureDuContenuTest (4), its JVM tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sending — the editor's ⋮ menu, "Share sealed…": the note as it is on screen, sealed off the main thread into note-YYYYMMDD.ntnote (the name says nothing of the note) in the exports directory (purged at start and by the panic), with an option "read once by the recipient". The code is shown once, spelled for TalkBack, can be copied through the sensitive clipboard, and is forgotten when the sheet closes; a secured window while it is open. "Share the file" goes through the exports' FileProvider, as the export does. Receiving — "Open with" (an exported activity, VIEW on application/octet-stream, content:// of another app only, bounded in size and time, magic checked: any other file is said so and the app does not open) and the home screen's ⋮ menu, "Open a sealed note" (the system picker). Both deposit the still-sealed bytes in memory; once the app is unlocked, a dialog asks for the code (never in a Bundle). The right code makes it a note of the Inbox — never a vault —, colour and tags kept, "after reading" if asked, and opens it. The code's display moves to ui/common (CodeAffiche), shared with the backup. Texts in the five languages. Tests: LectureScelleeTest (4, JVM: a sealed note read whole; another file dropped at its first bytes, not read to its end; past the bound; empty). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A file manager gives an unknown extension no type, or a generic one. Two more VIEW filters on the .ntnote path, with no type and with any; the magic is checked in any case. Resolution checked with cmd package query-activities on the S9: no type, octet-stream, another type with a .ntnote path reach the activity; a .jpg does not. Samsung My Files still says no app can open it: with an empty MIME type it decides alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- version.properties: versionCode 507, versionName 3.4.0. - fastlane: changelogs 5071-5073 in the five locales (405 to 428 characters, under 500 bytes too); four lines in each full description (lifetime, sealed note, quick drop, keyboard). - Privacy policy, five languages (dated 9 November 2026): sealed notes (the file, its code, where it goes; a received one), quick drop, notes with a lifetime (left out of backup and export), the keyboard's learning. - README (EN, FR): what is new in 3.4.0. SECURITY (EN, FR): v3.4.0, the new doors and how narrow each is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
External review (GPT): - a received sealed note is created in ONE insert, colour and "after reading" included; - reading a sealed file: one at a time, on a thread of its own, the stream CLOSED past the delay, a zero-byte read refused, any runtime error of another app's provider caught. Coherence audit: the sealing sheet forgets its code whenever it leaves; the keyboard setting's callback has no default; the picker's reading in its own ViewModel; one guarded purge (`purgerSansEchec`); the purge loop runs only while the list is started; KDoc put back in place; no ellipsis on the two new menu entries; `ClavierSansApprentissageTest` on the v2 Compose rule. Translations: Italian and German wording, German changelogs completed. 3-axes audit: - M4: a second sealed file deposited while the first is being opened waits for it — it no longer zeroes the bytes under decryption, nor is it erased by the first one's end; - M5: FLAG_SECURE from the first frame on the dialogs where a code is shown or typed — the two sealed ones and the three of the backup, which had the same defect (`ProprietesDeDialogueSecret`); - M7: a hand-made sealed file's tags are split, trimmed and deduplicated as the import does, its title put on one line without bidirectional overrides; - M1, M2: the lifetime sheet and SECURITY say the time follows the phone's clock, and when "after reading" really erases. Tests: `NotesScelleesRecuesTest` (wrong then right code, one note with what was sealed, no duplicate, the second file waiting), a hand-made file in `FichierDeNoteScelleeTest`, the settings tests with the keyboard row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Notes Tech 3.4.0 (versionCode 507) — five features, all local, no new permission.
Features
IME_FLAG_NO_PERSONALIZED_LEARNINGon every field of the app, on by default (Settings → Security), always on secret fields. Suggestions stay; a keyboard may ignore the request.MainActivitystill ignores intents.unlockAndRun); refused while a panic is pending;FLAG_SECURE.secure-delete, links), at the app's opening and every minute on the list; left out of backups and exports. Room schema 11, additive migration 10 → 11 (expires_at,read_once), tested from a real 3.3.0 database..ntnote(the backup's container under its own magic: Argon2id + AES-256-GCM, a 120-bit code shown once); open one through "Open with" or the home menu, the code asked once the app is unlocked; it becomes one note of the Inbox, never a vault.Reviews
FLAG_SECUREfrom the first frame on every dialog that shows or takes a code (the backup's three had the same defect).docs/15-VERSION-3.4.md: Samsung My Files does not offer Notes Tech for.ntnote(empty MIME type; the home menu works everywhere); a shared file can be purged if the process restarts — via the tile — before a slow receiving app reads it.Tests
NotesScelleesRecuesTest,LectureUniqueTest,MigrationVersDixTest,ClavierSansApprentissageTest.AGP 9.5.0 / Gradle 9.8.2 came with #51; this is the first release built with them — F-Droid has not built one yet (SMS Tech 1.30.0 is still pending there).
🤖 Generated with Claude Code