Commit Graph

5814 Commits

Author SHA1 Message Date
Benoit Marty 45d9339bfa Merge pull request #7495 from element-hq/refactor/add-client-enterprise-hooks
Add `ClientEnterpriseHook` and `ClientBuilderEnterpriseHook`
2026-08-22 08:10:50 +02:00
Benoit Marty 277dd4a2fd Fix test compilation 2026-08-21 18:53:43 +02:00
Benoit Marty e271a6b4a8 Revert change on dependencies 2026-08-21 18:13:44 +02:00
Jorge Martín c56bb66307 Fix ClientBuilderEnterpriseHook not returning an updated ClientBuilder 2026-08-21 17:32:45 +02:00
Benoit Marty eeaf0166f5 Merge pull request #7443 from hayaksi1/fix/4519-hide-verification-fallback
Do not render in-chat key verification requests in the timeline
2026-08-21 16:52:58 +02:00
Benoit Marty 1300112edc Merge pull request #7453 from hayaksi1/fix/4639-system-theme
Apply the system theme when switching back to it from a forced light or dark theme
2026-08-21 12:18:52 +02:00
Jorge Martin Espinosa 614619e306 Make PIP react to camera orientation changes in the other participant's device (#6951)
* Make PIP react to camera orientation changes in the other participant's device

Adds a `controls.onPipMediaOrientationUpdate` callback for the WebView that will trigger a new `pipParamsBuilder.setAspectRatioFromOrientation(orientation)` method

* Fix warning about `PictureInPictureParams.Builder.setAspectRatio` only being available on API 26+
2026-08-21 09:47:49 +00:00
Benoit Marty 2b3aeee1c6 Merge pull request #7494 from element-hq/feature/bma/loginWording
Move strings to the login module
2026-08-21 10:06:21 +02:00
Jorge Martín 4b32816b32 Add ClientEnterpriseHook and ClientBuilderEnterpriseHook
These allow us to not expose the enterprise internal when setting up custom configs for both `ClientBuilder` and `Client`
2026-08-21 10:05:00 +02:00
Benoit Marty be124610f0 Reuse the existing FakeOAuthActionFlow in RootFlowNodeTest
RootFlowNodeTest was declaring its own no-op fake, while the oauth test
module already provides one. Use it, and move it out of the customtab
package, since it is not specific to the custom tabs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 15:28:22 +02:00
Benoit Marty f0e575e25e Move the fake entry points of RootFlowNodeTest to the test modules
The fakes were declared in RootFlowNodeTest, so other tests could not use
them. Move each of them next to the API it fakes, following the existing
convention of a createNodeResult lambda defaulting to lambdaError():

- FakeLoginEntryPoint in features/login/test
- FakeBugReportEntryPoint in features/rageshake/test
- FakeSignedOutEntryPoint in features/signedout/test (new module)
- FakeAccountSelectEntryPoint in libraries/accountselect/test (new module)

The login and rageshake test modules did not have Appyx on their
classpath, so add the architecture module to their dependencies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 15:11:00 +02:00
hayyaksi 2525019ca1 Show the right image when opening one that has not finished sending (#7359)
* Show the right image when opening one that has not finished sending

* Reuse the timeline media gallery for events that have no event id
2026-08-20 11:16:13 +02:00
hayyaksi 918015b8bb Stop waiting for a room alias that the remote server never resolves (#7446)
Tapping a room alias whose server is down left the resolver screen on a
spinner for as long as the screen stayed open, with no way forward other
than going back.

Bound the resolution with the ten second timeout already used when
joining a room by address, so the retry dialog is shown instead. The fake
client's resolve lambda becomes suspending so a server that never answers
can be simulated.
2026-08-20 09:34:15 +02:00
hayyaksi c362bca527 Keep the send button when the composer is emptied while editing a message (#7456)
* Keep the send button when the composer is emptied while editing

rememberEndButtonParams checked whether the composer had sendable text
before it checked whether the user was editing a message, so clearing
the text of a message being edited replaced the send button with the
voice recorder button. Starting a recording from there abandons the
edit.

Check the editing branch first, as the formatting composer already does,
and let it render a disabled send button when there is nothing to send.

* Update screenshots
2026-08-20 08:55:50 +02:00
hayyaksi 2432b0ccc6 Keep playing a voice message when another app plays a short sound (#7454)
* Request media audio focus when playing a voice message

Voice message playback asked for audio focus with
USAGE_VOICE_COMMUNICATION, the same bucket as Element Call and voice
message recording, while the player itself renders on the media stream.
Audio policy layers act on the declared usage, so a car head unit
switches to its call audio context and routes the playback away while
the player keeps running.

Declare USAGE_MEDIA (and STREAM_MUSIC on the legacy path) for playback,
which is what the player actually renders. Recording and Element Call
keep asking for voice communication focus.

* Keep playing a voice message through a short sound from another app

A notification, a navigation prompt or any other app taking focus for a
moment sends AUDIOFOCUS_LOSS_TRANSIENT or AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK,
and DefaultMediaPlayer pauses on it. The voice message stops part way
through and the user has to find it again and restart it.

Recording already ignores those two, because the capture path is not
affected by focus. Give voice message playback the same treatment, moving
the requester test into a named function rather than growing the inline
condition. A permanent AUDIOFOCUS_LOSS, a real phone call, still pauses,
and the media viewer is untouched.
2026-08-20 08:55:03 +02:00
Benoit Marty 42f9e15641 Move strings to the login module 2026-08-19 17:18:16 +02:00
Benoit Marty 1c94e89ee8 Merge pull request #7394 from element-hq/feature/account-provider-selection
Simplify choosing the account provider during sign in, with autocomplete of previously used ones
2026-08-19 17:06:47 +02:00
Benoit Marty 92595e1532 Merge pull request #7427 from element-hq/renovate/media3
Update media3 to v1.11.0
2026-08-19 16:26:29 +02:00
Benoit Marty 7adbd3941a Make the PUSHER_APP_ID configurable at build time. 2026-08-19 14:20:31 +02:00
hayyaksi 7341feeed8 Model the fake voice recorder on a cancellable recording job (#7466)
* Model the fake voice recorder on a cancellable recording job

FakeVoiceRecorder pushed a whole recording synchronously from a single
suspending call, which made it both weaker and stricter than
DefaultVoiceRecorder.

Every level emission carried the same elapsed time and the emissions were
coalesced by Molecule, so no intermediate recording state was observable and
the level-limit test had to skip half the emissions to compensate. Each level
now advances the test time source and suspends for its share of the recording
duration, so the states arrive one at a time and that magic number is gone.

Call verification moved to the constructor lambdas the rest of the repo uses,
in place of hand-rolled counters and assertCalls. The counters discarded the
argument, so nothing pinned that cancelling a recording stops it with
cancelled = true; that is now asserted. Truth is no longer needed by the
fixture module.

A second startRecord() no longer raises an error where production only warns
and returns, and stopping or deleting terminates an in-flight emission loop
the way cancelling the real recording job does, so a stale recording state can
no longer arrive after the recording has finished.

* Keep each recording's level loop to its own recording

The level loop checked a single isRecording flag, which cannot tell "this
recording was cancelled" from "a later recording has started". After a cancel
followed by a new start, the first loop resumed, saw the flag set again, and
advanced the shared test time source, so the new recording reported the elapsed
time of both. Each recording now carries an id and its loop stops as soon as
that id is no longer the active one.
2026-08-19 13:44:11 +02:00
ganfra cf2ce2bd65 Use Profiles sliding sync extension check for own profile subscription (#7403)
* Use Profiles sliding sync extension check for own profile subscription

---------

Co-authored-by: Jorge Martin Espinosa <jorgem@element.io>
2026-08-19 13:00:27 +02:00
Benoit Marty ff89302cf5 Normalize the applicationName used in user agent, as HTTP spec does not allow UTF-8 chars in headers. 2026-08-19 11:56:34 +02:00
Jorge Martin Espinosa a1e86ad499 Use the right base URL for the ESS config/well known endpoints (#7469)
* Rename `UrlContentFetcher` to `ClientUrlContentFetcher` and add missing base URL data (server name, homeserver URL)

* Avoid passing the `homeserverUrl/serverName` around.

Calculate the URL in `DefaultRemoteEnterpriseConfigRetriever` using the newly added `homserver` and `server` values as the possible base URLs, depending on the remote config source

* Make sure we don't perform blocking requests to fetch the remote config when restoring a session

Add a `needsRefresh` parameter to `RemoteEnterpriseConfigResult.NotFound` to handle this, and store a `no-config` value in the store to indicate an endpoint has been checked and no config was found

* Bump enterprise module
2026-08-19 09:24:22 +02:00
Jenna Vassar 891c077786 Merge remote-tracking branch 'origin/develop' into feature/account-provider-selection 2026-08-18 17:49:31 -07:00
Jenna Vassar 2e2bf71ad5 Make ensureProtocol case-insensitive 2026-08-18 17:03:40 -07:00
Jorge Martin Espinosa c31d7e6cce Don't restart the sync service if the client is shutting down (#7472)
* Don't restart the sync service if the client is shutting down

This was causing issues when clearing the cache:

1. The client would ask the SDK to clear the caches.
2. The SDK would stop the sync service, clear the caches and set the `pos` value of sliding sync to 0 so the HS returns all the required state the next time the client is used.
3. However, between the sync service being stopped with the `pos=0` change and the client being destroyed, there was enough time for the `SyncOrchestrator` to decide the sync service was stopped for no good reason since there is network connectivity and the app is on foreground, so it restarted the sync, with `pos=0`.
4. This value was persisted, and the next time the new client did an 'initial sync' it had a `pos != 0`, which the HS uses to avoid returning some required state it already fetched.
5. The room list now lacks state events for lots of rooms and room names, avatars, members, etc. are now missing.

---------

Co-authored-by: Benoit Marty <benoitm@element.io>
2026-08-18 16:50:57 +00:00
Benoit Marty 1fefbc9943 Firebase configuration location has changed. 2026-08-18 17:39:21 +02:00
Benoit Marty 07983221e6 Move google_app_id to resource files. 2026-08-18 16:25:57 +02:00
Benoit Marty ccebb55ca7 Improve documentation 2026-08-18 15:46:24 +02:00
Benoit Marty 378fbfa1d8 Merge pull request #7441 from hayaksi1/fix/5978-caption-markdown
Convert markdown to HTML when a caption is edited
2026-08-18 10:05:19 +02:00
Benoit Marty 25094cbd06 Merge pull request #7445 from hayaksi1/fix/2617-user-id-with-slash
Open the user profile of a user id that contains a slash
2026-08-18 10:04:27 +02:00
Benoit Marty 3ea36d54b4 Merge pull request #7451 from hayaksi1/fix/7059-relax-image-compression
Relax image compression so photos and screenshots keep more detail
2026-08-18 10:03:36 +02:00
hayyaksi 75607c73ec Keep transparency when an image is shared into the app with an imprecise mime type (#7452)
* Resolve the real image format before choosing the encoder

The upload pre-processor picks the encoder from the mime type it is
given. When an image is shared from another app that type is often
broader than the image really is, so a transparent PNG shared as a
wildcard image type is re-encoded as JPEG and its alpha channel is
flattened to black.

Read the format from the image header when the declared type is not
already a concrete PNG or JPEG, and use that to decide both whether the
image can be compressed at all and which encoder to use.

* Cover the mime type fallbacks the wildcard resolution introduced

resolveImageMimeType now decides whether an image is compressible, so two of
its outcomes had no test: a GIF shared with a wildcard type has to be
recognised and left uncompressed rather than recompressed into a still, and a
file the decoder cannot read at all has to fall back to the type it was shared
with.

The isMimeTypeImage() guard on the decoded type is dropped with them. The
BitmapFactory decoders only ever report an image type in outMimeType, so the
guard could not fire and there was no way to exercise it.
2026-08-17 21:08:48 +02:00
renovate[bot] e6e93c9bd0 Update dependency org.matrix.rustcomponents:sdk-android to v26.08.17 (#7460)
* Update dependency org.matrix.rustcomponents:sdk-android to v26.08.17

* Fix API breaks:

- `ClientBuildException.WellKnownLookupDisabled` should be handled now.
- `Client.sendReply` returns a `Result<SendHandle>` now. We can ignore it like we do for `Client.send`.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jorge Martín <jorgem@element.io>
2026-08-17 21:06:28 +02:00
Jenna Vassar 7c48e737c4 Merge remote-tracking branch 'origin/develop' into feature/account-provider-selection 2026-08-17 11:18:46 -07:00
Jenna Vassar bbd6ce134b Fix account provider dropped on first Continue and address review comments 2026-08-17 10:31:17 -07:00
Benoit Marty 1f7635f0e3 Fix API break 2026-08-17 15:56:59 +02:00
Jorge Martin Espinosa 8b2c207728 Move the :libraries:wellknown logic into enterprise modules (#7429)
* Extract `IsEnterpriseBuild` use case

Having it inside `EnterpriseService` made having DI cycles with the `BuildMeta` provider too easy

* Rename `EnterpriseService.defaultHomeserverList()` to `homeserverAllowList()`

This seems more aligned with the way this list works

* Move most of the logic from `:libraries:wellknown` to `:enterprise:feature:enterprise`, both `shared` and `impl` modules

Ideally I would have added everything into `impl`, but some of the classes needed to be shared between the different `:enterprise:features` modules, and those are in the `shared` module, lacking a better name/strategy

* Add `EnterpriseService.isElementProEnforced`

With this, we don't need to provide the `RemoteEnterpriseConfig` anymore to any consumers, everything goes through `EnterpriseService` or other providers

* Remove `EnterpriseService.overriddenElementWellKnown`

This leaks the remote enterprise config/element well known contents to the app in a public interface.

* Create `CustomMapTilerConfigProvider` to avoid leaking the `RemoteEnterpriseConfig` in public APIs

This commit also starts moving some of the well-known related values to the enterprise modules

* Add missing docs to `EnterpriseService` and `SessionEnterpriseService`

* Fix tests

* Fix lint issues

* Bump enterprise module
2026-08-17 13:21:47 +00:00
hayyaksi 12791406ca Explain a rate limiting push gateway in the notification troubleshooter (#7448)
* Explain a rate limiting push gateway in the notification troubleshooter

The push loop back test printed whatever HTTP status the gateway
answered, so a user throttled by the public ntfy.sh gateway was told
"Error: HTTP 507", which reads as a server fault rather than as a quota
they can wait out or move away from.

Map the two statuses that mean the notification was throttled onto a
typed failure and give the troubleshooter a message that says what to do.

* Import strings from localazy, remove `temporary.xml` in `:libraries:push:impl`

---------

Co-authored-by: Jorge Martín <jorgem@element.io>
2026-08-17 15:14:15 +02:00
Benoit Marty 054d592391 Sync again 2026-08-17 12:10:39 +02:00
Benoit Marty 5ac1fe2409 Remove temporary string. 2026-08-17 12:10:18 +02:00
Benoit Marty a740423343 Sync strings. 2026-08-17 11:34:52 +02:00
hayaksi1 932a4d013c Relax image compression so photos keep more detail
Images are downscaled against a 640px reference, which makes inSampleSize
halve the source one step further than the documented intent: the KDoc
says images should be sent at up to 1280x1280, but a 12000x3916 photo is
sent as 3006x979. Text in screenshots and detail in photos is lost at
that size.

Raise the reference to 1280. inSampleSize is a power of two, so this
moves each image one step up rather than to an exact size.
2026-08-17 11:33:41 +03:00
hayaksi1 ddd89f46df Resolve the System theme from the application configuration
Selecting a Light or Dark theme makes AppCompatDelegate rewrite the
activity configuration to the forced night mode. isSystemInDarkTheme
reads that same configuration, so switching back to System kept showing
the previously forced theme.

Read the night mode from the application configuration instead, which
AppCompat leaves untouched and itself uses to expand
MODE_NIGHT_FOLLOW_SYSTEM. The activity configuration is still used as
the recomposition key so a system-wide theme change is picked up.
2026-08-17 11:33:09 +03:00
hayaksi1 c5a878249b Open the user profile of a user id that contains a slash
A slash is valid in the local part of a user id, but in a permalink it
also separates the identifier from an event id, so the SDK could not tell
the two apart and the link fell back to opening matrix.to in a browser.

Only a user id can start with an @, so recover it before handing the URI
to the SDK, and only when the identifier really contains a slash so every
other permalink keeps taking the same path.
2026-08-17 03:48:44 +03:00
hayaksi1 39afaa1fe4 Do not render in-chat key verification requests in the timeline
A m.key.verification.request sent from a client that supports in-chat
verification carries a plain text body for clients that do not. Element X
has no msgtype of its own for it, so it fell through to OtherMessageType
and the timeline printed that body, telling the user their client does
not support in-chat key verification right after a verification they had
just completed.

Drop the event when building the timeline items, as Element X iOS does.
2026-08-17 03:44:53 +03:00
hayaksi1 537842bb40 Convert markdown to HTML when a caption is edited
Adding or editing a media caption from the plain composer sent the
caption as text only: the composer has no HTML to pass, and the media
caption edit was built by hand with a null formatted body, so the
markdown was never rendered. Sending a caption with the same markdown
does render it, because the SDK builds the formatted body there.

Build the edit with the SDK's createCaptionEdit, which runs the caption
through the same markdown conversion the send path uses.
2026-08-17 03:40:11 +03:00
Jenna Vassar 89e2abaeeb Merge develop into feature/account-provider-selection 2026-08-14 07:51:17 -07:00
Benoit Marty 9e32801d02 Merge pull request #7426 from element-hq/feature/bma/documentation
Add KDoc to all the interfaces of the api modules
2026-08-14 13:46:28 +02:00
Benoit Marty 1ab401482a Fix formatting issues 2026-08-14 12:20:49 +02:00