From 79a24ac0686411e3fd8118298bb60de085bcd474 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 4 Sep 2026 08:49:56 +0200 Subject: [PATCH] Take odrcore 6.13.0 Two releases in one: 6.12.0 and 6.13.0. Almost all of it arrives without a line of app code - the ODF drawing and chart work, the docx anchors and table borders, the metafile decoder, the PDF stroke state, and the spreadsheet memory and repeat-count fixes. CHANGELOG says what a user gets. Three things the app had to answer for: A document only held decrypted is no longer savable, so `host` closes it and no Edit button appears over it. That already works - `isEditable && isSavable` is what decides - and `testDecryptedDocumentIsNotEditable` holds it, because saving one used to write the content back out with its protection stripped. 6.12.0 named html in the format table without giving it a decoder, so `declaredType` now answers only for a type the core can open. Otherwise every `.html` - read as text, correctly - was reopened as html, failed, and fell back. render-sweep's list of claimed extensions was missing `md` and `markdown`, which the manifest has had since 6.11.0. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01T9iat7kbbySjhjy2agH2w1 --- CHANGELOG.md | 28 +++++++++++++++++++ .../app/opendocument/droid/test/CoreTest.kt | 22 +++++++++++++++ .../droid/background/CoreLoader.kt | 5 +++- gradle/libs.versions.toml | 2 +- tools/render-sweep/render-sweep.sh | 2 +- 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f608b43c1ad..f61457fc55bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,34 @@ version code per locale under `fastlane/metadata/android//changelogs/`, written by `scripts/store-copy.py` before the release and uploaded by it. Play takes 500 characters, so not everything here reaches the store. +## Unreleased + +- Charts in OpenDocument files are drawn from the chart itself - bar, line, + area, scatter, pie and ring, with their titles, legends, axes and colours - + rather than from the flat picture saved beside it. +- Shapes in OpenDocument drawings and presentations appear as the shapes they + are, and where the file puts them. Arrows, stars, callouts, curves, + connectors, ellipses and measures used to come out as plain rectangles or not + at all, and a rotated or mirrored one sat square. +- Pictures and charts stored as Windows metafiles draw: their lines, curves, + gradients, bitmaps and labels, each in the encoding the file names. Such an + image used to be an empty frame, or a table's rules a row of floating numbers. +- A floating picture in a Word document floats where it was anchored, with the + text wrapping around it, instead of sitting in the line. +- A Word table's own borders are drawn, and at the thickness the file asks for + rather than four times it. A table cell's content starts at the top of the + cell, as Word and OpenDocument show it. +- A manual page break starts a new page, on screen and in print. +- Lines in a PDF are drawn at the width the file sets. A PDF from Canva had + every stroke at the same weight, whatever it was meant to be. +- Spreadsheets open in about half the memory, and two more of them open at all: + a sheet whose repeated cells claimed billions of positions, and one with a + merged range naming more cells than the sheet has. +- Pictures in a document load side by side rather than one after another: two + parts of the same file can be read at once now. +- A password-protected document opens read-only. Saving it wrote the content + back out without the protection its author asked for, and said nothing. + ## 4.18.0 - A spreadsheet shows ten times as many rows: the cap rises from 10,000 to diff --git a/app/src/androidTest/java/app/opendocument/droid/test/CoreTest.kt b/app/src/androidTest/java/app/opendocument/droid/test/CoreTest.kt index 31ed0a71299f..7c5739120214 100644 --- a/app/src/androidTest/java/app/opendocument/droid/test/CoreTest.kt +++ b/app/src/androidTest/java/app/opendocument/droid/test/CoreTest.kt @@ -181,6 +181,28 @@ class CoreTest { Assert.assertFalse("the decrypted document should produce a view", views.isEmpty()) } + /** + * A document only held decrypted is read only, so no Edit button appears over it. The same odt + * without a password is editable - see [testEditableFormats] - and saving this one would have + * written the content back out without the protection its author asked for. + */ + @Test + fun testDecryptedDocumentIsNotEditable() { + coreLoader.host( + prefix = "password-test-editable", + inputPath = passwordTestFile.absolutePath, + cachePath = File(cacheDir(), "password_editable").path, + password = "passwort", + editable = true, + keepDocument = true, + ) + + Assert.assertFalse( + "a decrypted document should not be editable", + coreLoader.isDocumentEditable, + ) + } + /** * An encrypted `.doc` says so rather than failing as a parse error, and odrcore has no way into * it, so [CoreLoader.host] refuses it instead of raising a prompt no password can close. diff --git a/app/src/main/java/app/opendocument/droid/background/CoreLoader.kt b/app/src/main/java/app/opendocument/droid/background/CoreLoader.kt index 5dbedcc37cd1..f025d4734c9b 100644 --- a/app/src/main/java/app/opendocument/droid/background/CoreLoader.kt +++ b/app/src/main/java/app/opendocument/droid/background/CoreLoader.kt @@ -211,12 +211,15 @@ class CoreLoader(private val context: Context) { /** * What the document is *called*. Not [IdentifiedFile.mimeType]: `FileIdentifier` takes that * from `Odr.mimetype` wherever it answered, so it would be the same reading again. + * + * Only a name the core has a decoder for: html is named by the table and not opened by it, so + * calling a file `.html` answers nothing [openAs] could act on. */ private fun declaredType(file: IdentifiedFile): FileType? { val extension = MimeTypeResolver.parseExtension(file.filename)?.lowercase() ?: return null val type = Odr.fileTypeByFileExtension(extension) ?: return null - return type.takeIf { it != FileType.UNKNOWN } + return type.takeIf { it != FileType.UNKNOWN && Odr.capabilitiesByFileType(it).open } } /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 658b6b3870a3..c94eedab7b79 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ googleJavaFormat = "1.35.0" ktfmt = "0.64" # odrcore's JNI bindings, java and native in one AAR, published from OpenDocument.core -odrCore = "6.11.0" +odrCore = "6.13.0" androidxAnnotation = "1.10.0" androidxAppcompat = "1.8.0" diff --git a/tools/render-sweep/render-sweep.sh b/tools/render-sweep/render-sweep.sh index f36967bd588f..52c4a57f601e 100755 --- a/tools/render-sweep/render-sweep.sh +++ b/tools/render-sweep/render-sweep.sh @@ -34,7 +34,7 @@ INSTALL=0 # because the tables live in libodr_jni and reading them needs a device - the # same reason SupportedDocumentTypesTest is an instrumented test. A format added # upstream and missing here just means this sweep skips it. -CLAIMED='csv|doc|docm|docx|dot|dotm|dotx|fodg|fodp|fods|fodt|key|numbers|odg|odm|odp|ods|odt|otg|otm|otp|ots|ott|pages|pdf|pot|potm|potx|pps|ppsm|ppsx|ppt|pptm|pptx|rtf|text|txt|xlm|xls|xlsm|xlsx|xlt|xltm|xltx|zip' +CLAIMED='csv|doc|docm|docx|dot|dotm|dotx|fodg|fodp|fods|fodt|key|markdown|md|numbers|odg|odm|odp|ods|odt|otg|otm|otp|ots|ott|pages|pdf|pot|potm|potx|pps|ppsm|ppsx|ppt|pptm|pptx|rtf|text|txt|xlm|xls|xlsm|xlsx|xlt|xltm|xltx|zip' usage() { cat <<'EOF'