sessionPaths keeps pointing at the directories of the account which has
just been logged in, and it was never reset. Adding another account
calls setHomeserver(), whose rotateSessionPath() starts by deleting the
directories of the previous sessionPaths, so the file and cache
directories of the first account were wiped.
finalizeClientCreation() now forgets the session paths once the login
succeeded. It is done there rather than in clear() on purpose: after a
failed attempt the directories are orphaned and must still be deleted by
the rotateSessionPath() of the next attempt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Since the login flows stopped handing their client over to
RustMatrixClientFactory and let finalizeClientCreation() build a fresh
one from the SessionData, two problems appeared.
The client built by loginWithQrCode() was never owned by anyone: it is
not assigned to currentClient, so clear() had nothing to close and the
Rust Client stayed open for the whole app lifetime, holding the session
stores of the freshly logged in account. It is now tracked in
currentClient, and also disposed of when the QR login fails, which is
safe because that flow always builds its own client.
The client of the session was also built while the login client was
still open. Both use the same session paths, so their state and crypto
SQLite stores, and the search index when message search is enabled, were
opened twice at the same time with no cross process lock to protect
them. clear() now runs before the final client is created.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Update dependency org.matrix.rustcomponents:sdk-android to v26.09.08
* Fix API breaks:
- There's no `SyncServiceBuilder.withProfilesExtension()` method anymore. This is now enabled unconditionally in the SDK.
- Timeline filters no longer use the `org.matrix.rustcomponents.sdk.TimelineEventFilter` FFI wrapper, but the `uniffi.matrix_sdk_ui.TimelineEventFilter` type directly. This also changes the underlying types used for inclusion/exclusion.
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jorge Martín <jorgem@element.io>
Fix API breaks:
- A new `Mentions` room list filter is available.
- `RoomListService.subscribeToRooms` is now `RoomListService.setRoomSubscriptions`.
- `enableAutomaticBackPagination` moved from `Client` to `ClientBuilder`.
The -dontwarn is still required: firebase-messaging ships no consumer rules and
we exclude firebase-analytics from its dependencies. Only rename the file to
consumer-rules.keep and reword the comment, which embedded a local path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rule only kept the class, but ShowkaseBrowserActivity instantiates it with
Class.forName(...).getDeclaredConstructor().newInstance(), so R8 was free to
strip the constructor. Also drop the AGP template comments and rename the file
to .keep, for consistency with app/proguard.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The three rules came from a 2022 comment on Retrofit issue #3751. Retrofit
3.0.0 now ships META-INF/proguard/retrofit2.pro, which contains two of them
verbatim and covers retrofit2.Call through its conditional return-type rule.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Keep the push foreground service alive while notifications are fetched
* Release the push foreground service as soon as results are handed over
---------
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
* Make sure `enforce_element_pro` is taken into account in FOSS
* Make sure we crate `RustTemporaryMatrixClient` instances with a proper `serverName` value
Ask the SDK to track receipts on message-like events only, for the live
timeline and for the focused and threaded ones, so all three agree. The
disabled case for the media and pinned-event timelines is unchanged.
This matches the behaviour on Element X iOS.
The SDK attaches the receipt to the preceding event rather than the next
one, which is the placement its API offers.
Introduce io.element.android.libraries.mediaviewer.api.FileViewerEntryPoint, a
reusable screen which renders content that is not a Matrix media the same way the
media viewer renders a file, with Share and Download actions.
The caller provides a filename, a mime type and the whole content as a String.
The node writes it to a temporary file in the cache directory, then reuses
LocalMediaView (so text content goes through TextFileViewer) and LocalMediaActions
for sharing and saving on disk. The node is contributed to AppScope so that the
screen can be used from any graph, since MediaViewerNode itself is bound to
RoomScope and depends on the timeline data sources.
Also route MimeTypes.Json to TextFileView in LocalMediaView, so that a json file
is rendered as text instead of falling back to the generic file card.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sharing from another app listed Element X once, with no way to pick a
conversation: the Direct Share row never showed any.
The app already publishes a long-lived, conversation-categorised shortcut per
room, which is most of what the sharing shortcuts API needs. The part that was
missing is the declaration that ties those shortcuts to the share intent: the
launcher activity had no `android.app.shortcuts` meta-data, so there was no
`<share-target>` for the system to match them against.
It now ships one, matching the activity that already receives ACTION_SEND, and
the shortcuts carry the category it names.
The system offers these from Android 10 onwards, where sharing shortcuts are
handled natively. Reaching further back would additionally need the
androidx.sharetarget library, which is not added here.
Part of #3835
Upgrading over an older install crashed before the login screen with
`SQLiteException: no such column: SessionData.position`. The session, cache
and push databases were opened at their new schema version but their tables
were never migrated.
`SqlCipherDriverFactory` overrides `AndroidSqliteDriver.Callback.onUpgrade` so
the database key can be replaced, and never called through to the base
implementation - which is the only thing that runs `schema.migrate`. Every
SQLDelight migration in the app was skipped as a result.
The override now calls `super.onUpgrade` after the re-key, so a database that
crosses the re-key version is still re-encrypted before its tables are
migrated. It moved out of an anonymous object into a named `MigrationCallback`
so the behaviour can be tested.
Part of #7509
The room list preview prefixes the sender's name unless the room is a
direct message. A room that was created as a group and later converted to
a direct message is not marked as one by the server, so its preview kept
naming the only other person in it on every message, while iOS did not.
The prefix now depends on how many people are actually in the room rather
than on the direct message flag, which is the behaviour asked for in the
issue: no name while only two people can be talking, the name back as
soon as a third joins.
Part of #1548
The HTML sanitiser in toHtmlDocument() drops every tag outside its safelist,
which does not include img. A formatted body whose only content is an image —
a custom emoji, or a bot posting an image inline — therefore cleans down to an
empty document, and because that document is not null the ?: body fallbacks in
the timeline item factory, the room list preview, the notification resolver and
plainText are all dead. The message renders as an empty bubble.
Return null from toHtmlDocument() when no text survives the sanitisation, so the
existing fallbacks take the plain text body, which for these messages carries the
alt text the sender provided.