Skip to content

chore: merge develop into develop-v2 - #1790

Open
PratimMallick wants to merge 92 commits into
develop-v2from
chore/merge-develop-into-develop-v2
Open

chore: merge develop into develop-v2#1790
PratimMallick wants to merge 92 commits into
develop-v2from
chore/merge-develop-into-develop-v2

Conversation

@PratimMallick

@PratimMallick PratimMallick commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Goal

resolves AND-1464

Bring develop up to date on develop-v2 so v2 keeps the latest product, analytics, and CI work from the v1 line without abandoning the v2 architecture (Kotlin 2.2, StreamClient, Call decomposition, WebRTC 137).

This is a follow-up to the previous develop→develop-v2 merge (#1761).

Implementation

Testing

  • :stream-video-android-core:compileDebugKotlin, :stream-video-android-ui-compose:compileDebugKotlin, :stream-video-android-previewdata:compileDebugKotlin — succeeded after conflict resolution
  • :stream-video-android-core:apiDump / :stream-video-android-ui-compose:apiDump — regenerated
  • ./gradlew spotlessApply — required for the pre-push hook
  • Pre-push spotlessCheck + apiCheck — succeeded
  • ./gradlew test / ./gradlew check — not run on the full suite after the merge; CI should cover this
  • Manual call / lobby / ringing UI — not exercised on device; VideoComponentFactory rewires Compose slots, worth a smoke pass on lobby, incoming/outgoing, and screen-share
Conflict-resolution notes for reviewers
Keep v2 StreamClient / StreamConnectionState paths in StreamVideoClient, ClientState,
CoordinatorConnectionModule, CoordinatorAnalytics.

Keep DegradationPreferenceMapper DISABLED mapping (WebRTC 137).

Take develop noise-cancellation policy + CallMediaManager factory lifecycle + Call.kt
SFU signaling, with io.getstream.webrtc imports instead of org.webrtc.

☑️Contributor Checklist

General

  • I have signed the Stream CLA (required)
  • Assigned a person / code owner group (required)
  • Thread with the PR link started in a respective Slack channel (required internally)
  • PR targets the develop branch
  • PR is linked to the GitHub issue it resolves

This PR targets develop-v2, not develop.

Code & documentation

  • New code is covered by unit tests
  • Comparison screenshots added for visual changes
  • Affected documentation updated (KDocs, docusaurus, tutorial)
  • Tutorial starter kit updated
  • Examples/guides starter kits updated (stream-video-examples)

Develop already shipped tests for NC signaling, VideoComponentFactory, and analytics; those land on v2 via this merge. Changelog file was removed on develop (#1779).

☑️Reviewer Checklist

  • XML sample runs & works
  • Compose sample runs & works
  • Tutorial starter kit
  • Example starter kits work
  • UI Changes correct (before & after images)
  • Bugs validated (bugfixes)
  • New feature tested and works
  • Release notes and docs clearly describe changes
  • All code we touched has new or updated KDocs
  • Check the SDK Size Comparison table in the CI logs

Please smoke lobby / ringing / screen-share Compose paths because of VideoComponentFactory.

🎉 GIF

Skipped — merge/sync PR, no new user-facing animation.

Made with Cursor

PratimMallick and others added 30 commits May 26, 2026 16:18
* upgrade to m145 webrtc and noise-cancellation

* Update to webrtc m145 and corresponding noiseCancellation lib

* Remove the snapshot repo resolution
…ng (#1699)

* feat(core): pick up SFU DegradationPreference and add WebRTC mapper

Regenerate SFU protos to pick up the new DegradationPreference enum and
its degradation_preference fields on PublishOption and VideoSender (plus
TrackInfo.self_sub_audio_video), and refresh the public API dump.

Add toRtcDegradationPreference() converting the SFU enum to
org.webrtc.RtpParameters.DegradationPreference, returning null for
UNSPECIFIED so callers can keep the current value. Includes unit tests
covering every enum variant.

Co-authored-by: Cursor <cursoragent@cursor.com>

* publisher changes for applying degradation preferences

* Remove duplicate handling of ChangePublishQualityEvent from callState. This event directly gets handled by RtcSession handleEvent method

* Added test for the two call sites where degradation Preference is getting set to test for the case where sfu sends the same degrdation preference which is already set in the transcevier sender param

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
* demo: Add logic to add custom user

* chore(demo-app): gate add user dialog to development flavor

Hide the new add-user button and popup outside the development flavor
so the production demo app doesn't expose internal user injection.

---------

Co-authored-by: Aleksandar Apostolov <apostolov.alexandar@gmail.com>
When toggling a single track (e.g. muting the mic while the camera stays
on, or turning the camera off while the mic stays on), RtcSession sent the
full declarative mute-state map for all track types. Re-asserting an
unchanged track as un-muted made the SFU re-emit a redundant
TrackPublishedEvent for that track. That event carries a potentially stale
published_tracks snapshot which re-enabled the just-disabled track, freezing
the local self-view on the last frame / showing the avatar while no frames
arrive.

Send only the mute state of the track that actually changed, matching the
web SDK. On SFU (re)connect/migration each enabled track is re-signalled
individually via listenToMediaChanges, so the full state is still restored.

Co-authored-by: Cursor <cursoragent@cursor.com>
…1705)

deleteDevice previously only purged the cached Device on API success. When
DELETE /devices returned 404 or the network failed, the stale token sat in
deviceTokenStorage. The next createDevice for a different user short-circuited
on token equality (when autoRegisterPushDevice=true) and returned Success
without calling POST /devices, silently leaving the new user without a device
row server-side and breaking incoming-call push.

Local cleanup now runs unconditionally and is guarded so a storage failure
doesn't mask the API outcome. CancellationException is re-thrown to preserve
structured concurrency.

Three regression tests added.

AND-1214
… device registration (#1703)

Guest user setup runs asynchronously: StreamVideoBuilder.build returns immediately
while setupGuestUser kicks off a background createGuest call to fetch the JWT.
Any authenticated request that fires in that window goes out with stream-auth-type
"anonymous" and no Authorization header, so the backend silently registers it
against the wrong identity. The customer-visible effect is push device
registration succeeding under !anon and incoming-call pushes never reaching
the guest user.

apiCall now awaits guestUserJob before invoking the request block, with a
self-job guard so createGuestUser — which also goes through apiCall — does not
await its own enclosing job and deadlock.

Adds two regression tests: one for the wait, one for the deadlock guard.

AND-1202

Co-authored-by: Rahul Kumar Lohra <tgunix@gmail.com>
* fix(core): adopt response.user from createGuest to keep guest identity in sync

The createGuest endpoint returns the server-resolved user (which may differ
from what was passed in — e.g. normalized id). The SDK previously kept only
the access token and left its in-memory user as the builder's input, so the
WS auth payload and the JWT user_id claim could disagree.

setupGuestUser now also updates client.user from response.user (matching the
JS SDK's connectUser(response.user, response.access_token) semantics).
userId becomes a computed property so every existing reader of client.userId
picks up the new identity automatically. CoordinatorSocketConnection.user
turns into a var so its onCreated() auth payload reads the latest user.

Adds three regression tests: userId reactivity, the var update inside the
socket connection's connect path, and a full setupGuestUser flow with the
api mocked to return a different user id than the input.

AND-1202

* fix(core): mirror adopted guest user into ClientState.user

ClientState._user was snapshotted from the integrator-supplied user at
construction, so observers of state.user kept the old id after
setupGuestUser adopted the server-issued one. Propagate the adopted
user via a new internal ClientState.setUser.
* refactor(core): introduce UserRepository as single source of truth for SDK user

Replaces the parallel `var user` fields in `StreamVideoClient` and
`CoordinatorSocketConnection` (and the `_user` mirror in `ClientState`) with
a single `UserRepository`:

- `UserRepository` — public, read-only access via `user` / `userFlow`.
- `WritableUserRepository` — internal sub-interface with `setUser`. Only
  `StreamVideoClient` holds a write reference, so identity updates go through
  one path.
- `StreamUserRepositoryImpl` — in-memory impl backed by a `MutableStateFlow`.

`StreamVideoBuilder` constructs one instance and shares it between the client
(writer) and the coordinator socket / `ClientState` (readers). `setupGuestUser`
writes the adopted user to the repo once; readers pick it up automatically
without any local copy to keep in sync. `connect()`/`reconnect()` no longer
mutate a snapshot of the user on the socket — they only forward the call to
`internalSocket`, and `onCreated()` reads from the repository when building
the WS auth payload.

* test(core): add direct unit tests for StreamUserRepositoryImpl

Covers seed-from-constructor, user/userFlow reads, setUser write, emission
to active StateFlow collectors, and replacement semantics. Lifts coverage
on the new repository from indirect-only (via StreamVideoClient tests) to
full coverage of the impl.

* Auto-connect and register push device for guest users (#1707)

* feat(core): auto-connect and register push device for guest users

StreamVideoBuilder previously only ran the auto-register-push and
auto-connect block for UserType.Authenticated. Guest users fell through,
forcing every Guest integrator to write the same boilerplate (manual
registerPushDevice + connect after build) — boilerplate the iOS and JS
SDKs don't require.

Widen the gate to include UserType.Guest. registerPushDevice() and
connectAsync() inside StreamVideoClient already await guestUserJob, so
both are safe to fire from the builder block before /video/guest
completes. Anonymous users still don't have an identity to register a
device against, so they remain excluded.

AND-1202

* fix(core): wait for guestUserJob before registering push device

StreamNotificationManager.createDevice() goes straight to api.createDevice()
without the apiCall {} wrapper, so the guestUserJob await guard added in #1703
doesn't cover it. registerPushDevice() now waits for guest setup itself before
delegating, so the push generator can't fire createDevice() before the
coordinator's auth headers flip from anonymous to JWT.
* fix: include internal audio switch to fix concurrency issue

* fix: include aar
The KDoc claimed `logOut` clears internal user state, removes push
notification devices, and clears call state. The actual implementation
only writes null to the local DeviceTokenStorage — no `DELETE /devices`,
no socket disconnect, no in-memory clear.

The name and the historical doc invite a customer to ship broken
user-switching: anyone reading the API surface would reasonably assume a
clean slate. Surfaced while diagnosing a customer integration where push
delivery silently failed across user transitions.

Annotate the interface declaration and the StreamVideoClient override
with `@Deprecated`. Update the KDoc to describe current behavior
accurately. Point `ReplaceWith` at `StreamVideo.removeClient()`, which
triggers a real `cleanup()` and uninstalls the singleton. Customers who
need to remove the server-side device row should call `deleteDevice()`
before `removeClient()`.

No binary signature change — `@Deprecated` is annotation-only, so the
public `.api` file is unchanged.

AND-1217

Co-authored-by: Rahul Kumar Lohra <tgunix@gmail.com>
…ce (#1711)

Assign the DataStore.updateData() result to a local in
DeviceTokenStorage.updateUserDevice so the suspend function is compiled
as a state machine that returns Unit. Without it the compiler
tail-call-optimizes the call and propagates the DevicePreferences result
up the updateDevice suspend chain, which can surface as
"DevicePreferences cannot be cast to kotlin.Unit" at the caller once R8
inlines the chain.

Co-authored-by: Cursor <cursoragent@cursor.com>
…unt (#1712)

Post-join, the SFU healthcheck delivers the authoritative participant count.
Coordinator session events (participant_joined/left, counts_updated, anything
carrying a CallSessionResponse) carry a smaller, stale snapshot that disagrees
at scale. The previous guard checked only !is RealtimeConnection.Joined — a
transient state immediately replaced by Connected — so every coordinator
session event re-wrote the count, producing wild swings during livestreams
(e.g. 25k -> 32k -> 42k -> 28k in seconds).

Broaden the guard to cover the entire in-call lifetime (Joined, Connected,
Reconnecting, Migrating). Pre-join, the session-derived path now uses
max(byRoleCount, participants.size) for monotonicity during fast joins,
matching the stream-video-js SDK.

AND-926
)

* fix(core): prevent "MediaSource has been disposed" crash on leave

Guards the lazy audio/video source and track creation/disposal in
MediaManagerImpl with a single reentrant lock, and adds a terminal
`released` flag so the mic/camera mute paths no-op after cleanup instead
of lazily resurrecting native objects.

The crash occurred when a call was left while the first AudioSwitch setup
was still in flight: cleanup() disposed the audio source on one thread
while the deferred mic-disable callback recreated the audio track from
that disposed source on stream-audio-thread.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(core): stub runOnAudioTrackIfAvailable in MicrophoneManager tests

enable()/disable() now route the track toggle through
mediaManager.runOnAudioTrackIfAvailable instead of the audioTrack getter,
so the test helper stubs the new helper to invoke its block with the mock
track. Fixes the 5 failing MicrophoneManagerTest verifications.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…elease of 1.26.0 (#1719)

* Revert " Include internal audio switch to fix concurrency issue (#1710)"

This reverts commit 9a8da36.

* chore(release): reset version to 1.25.0 to allow re-release of 1.26.0

The 1.26.0 Maven publish failed due to the local AAR introduced in #1710.
Resetting gradle.properties to 1.25.0 so the release workflow can re-tag
and publish 1.26.0 cleanly from the reverted develop state.
The "setting up call" foreground-service notification was built without a
small icon for any non-incoming trigger (outgoing/ongoing/livestream). The
non-deprecated getSettingUpCallNotification(trigger, callId) delegated its
else branch to the deprecated no-arg overload, which never called
setSmallIcon. A small icon is mandatory for foreground-service
notifications, so Android 13+ rejected it with
CannotPostForegroundServiceNotificationException ("Bad notification for
startForeground") when the call foreground service started.

Extract a non-deprecated buildSettingUpCallNotification() helper that always
sets setSmallIcon(R.drawable.stream_video_ic_call), and have both the
non-deprecated else branch and the deprecated overload delegate to it. Add a
regression test covering the non-incoming (outgoing) trigger path.

Co-authored-by: Cursor <cursoragent@cursor.com>
* update open api generated models

* update code gen script
* update open api generated models

* update code gen script

* fix: self cancelling coroutine code

* fix: fix self cancelling coroutine code
…e call (3/4) (#1715)

* update open api generated models

* update code gen script

* fix: self cancelling coroutine code

* internal: add call leave reason

* internal: update Call Leave Reason LLC

* fix: fix unit tests

* 📝 CodeRabbit Chat: Implement requested code changes

* Update stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallLeaveReason.kt

* chore: send correct leave reason from StreamCallActivity.kt

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Aleksandar Apostolov <apostolov.alexandar@gmail.com>
github-actions Bot and others added 14 commits August 21, 2026 10:53
…1773)

* fix(core): enforce noise-cancellation capability and call settings

Core checked neither OwnCapability.EnableNoiseCancellation nor the call type's
noise_cancellation mode, so noise cancellation ran regardless of what the server
granted. Android enforced neither check, and shipped the mode helpers in core
while only the demo app consumed them.

Add NoiseCancellationPolicy owning both checks, and reconcile against it from
Call. Enabling is refused when either is withheld and withdrawn if either is
taken away mid-call; disabling is always allowed so a withdrawal can never be
blocked. The reconciler waits for settings to resolve rather than reading
"not told yet" as a refusal, which would flap noise cancellation during join.

The call type's auto-on default moves out of the demo app's lobby view model
into core, so every app gets it rather than whoever remembered to wire it.

Applying a wanted state no longer forces the peer-connection factory into
existence: CallMediaManager remembers it and a factory created later picks it
up. A factory built before join captures the pre-join audio bitrate profile and
defeats ensureFactoryMatchesAudioProfile.

Expose CallState.audioProcessingEnabled so consumers can observe SDK-driven
changes; the demo app collects it instead of snapshotting, and now reads
settings only to decide whether to show the menu item.

* fix(core): close the noise-cancellation lifecycle gaps

Three gaps between the policy gate and the deferred factory, all of which let
state and enforcement drift apart.

Withdrawal only acted when something was already processing. A state wanted
before the factory existed is remembered and would be applied the moment one was
built, after the server had withheld it. Withdrawal now clears the wanted state
whether or not anything is running yet.

The gate read the audio-processing state through the lazily-creating factory
accessor, so opening the toggle before joining built a factory pinned to the
pre-join audio bitrate profile. It now reads without creating one.

The wanted state also outlived the call, so a reused Call would re-apply it to
the factory built for the next session. Cleanup forgets it.

Publishing and signalling now both follow the applied state rather than the
request, matching the toggle path.
CHANGELOG.md is not used anymore. Release notes are generated from the
PRs themselves, using the pr: labels and the categories configured in
.github/release.yaml.

Deletes the file, its ownership line in .github/CODEOWNERS, and the
"Changelog is updated with client-facing changes" item in the PR
template checklist.

The remaining "changelog" matches in the repo are unrelated to this
file and stay: the changelog: key in .github/release.yaml is GitHub's
own release notes config, FASTLANE_HIDE_CHANGELOG in fastlane/.env is a
fastlane internal flag, and the README link points to the roadmap page
on GitHub Discussions.

AND-1442
* Write analytics docs

* Write analytics docs
* [AND-1445] Stabilize the flaky E2E emulator tests

The nightly E2E cron was red on 11 of the last 13 runs. Most failures
came from retry attempts that were not independent: the instrumentation
runs inside the app process, so a failed attempt could leave the
internet connection disabled or a call still active, and the remaining
attempts inherited that state and failed the same way.

- RetryRule now restores the connection and leaves any leftover call
  between attempts, and all post-failure steps are best-effort so an
  attachment error cannot replace the real failure or skip retries.
- The UiAutomator wait helpers are replaced with the polling, stale-safe
  versions from stream-chat-android. Timeouts now throw a clear error
  naming the selector instead of an NPE.
- All UserRobot clicks go through the new stale-safe waitToAppearAndClick.
- Longer windows for joining a call and for the outgoing ringing screen,
  and the recording label assertion polls through the reconnect banner.
- run_e2e_test accepts a test_class option, and the PR workflow exposes
  api_level and test_class dispatch inputs to sample one flaky test.
- Failure artifacts include allure-results, and the E2E concurrency
  groups are scoped by workflow name.

* [AND-1445] Address review findings and widen the view menu wait

- Pass test_class to fastlane through the step environment with a quoted
  expansion, so the dispatch input cannot inject shell commands into the
  emulator action script.
- Drop '$' from the allowed test_class characters: the local and device
  shells would expand it. All E2E test classes are top-level anyway.
- Give the view menu items in setView a 15s window. In the failed batch 0
  run, the Spotlight item was present in the hierarchy dump seconds after
  the 5s timeout: with many live video tiles the popup lands in the
  accessibility tree late on the emulator.

* [AND-1445] Widen the connecting screen window to match the join window

The connecting progress bar covers the same call join round-trip as
waitForCallToStart, which can exceed 10s on a loaded CI emulator. This
is the assertConnectingView failure seen on PR #1781.
* [AND-1446] Fix the flaky MockK Context setup in PictureInPictureTest

* [AND-1446] Assert the built PictureInPictureParams values on TIRAMISU

* [AND-1446] Strengthen the PiP params assertions per review
* Snapshot test baseline for the Compose Video SDK (AND-1417)

Adopt the chat SDK Paparazzi conventions: a PaparazziComposeTest
interface with snapshot, snapshotWithDarkMode, and snapshotWithDarkModeRow
helpers plus shared hdpi device configs, replacing BaseComposeTest.

Fix the flakiness behind the 10 ignored tests and enable them. The
preview data now uses deterministic session ids, pins previewCall's
own session id, populates all six participants once at init, and no
longer clears shared state on every access.

Extend coverage from 74 to 116 goldens: individual control actions,
dialogs, spotlight renderers, livestream backstage, 7-participant
grids, lobby states, and dark variants for the main screens. New
coverage uses shared internal preview composables in src/debug called
by both the @Preview wrapper and the test; those tests live in
src/testDebug so the release unit test variant still compiles.

Raise the Paparazzi test worker heap to 4g like the chat repo.

* Apply chat snapshot conventions to names, dark coverage, and rendering

Rename all snapshot test methods to the chat SDK style (lowercase
phrases, dark variants suffixed with 'in dark mode') so golden file
names follow the same convention as the chat repo.

Cover light and dark for every surface: components use the combined
snapshotWithDarkMode golden, full screens get an explicit dark mode
sibling test, and screen sharing tests gain the light variant they
were missing. Remove tests that duplicated the same composition.

Use RenderingMode.SHRINK everywhere except the dialog tests (window
level Dialog and Popup overlays) so component goldens crop to content.

Give the grid renderer tests a dedicated call per participant count
(previewGridCall). The renderers read remote participants from call
state for the small layouts, so the shared six-participant previewCall
could not represent one, two, or three participant calls. This also
makes the 'N participants' goldens true to their names.

* Fix snapshot verification failures found by Linux CI

Record the case-only renames of the BaseComponentsTest goldens
explicitly. The macOS filesystem is case insensitive, so git kept the
old capitalized file names and the Linux runner could not find the
lowercase ones the tests expect.

Snapshot the participant actions menu content directly. The production
wrapper renders through a window level Popup, which neither Paparazzi
nor Android Studio previews capture, so the goldens were empty. The
Popup content is extracted into ParticipantActionsDialogContent
(internal, no API change) and the stale kick preview, which duplicated
the default preview, is removed.

Build the grid test call before the snapshot and wait for the sorted
participants state to settle. The state propagates asynchronously on
the call scope and the grid renderers return early while it is empty,
so capturing the first frame raced with machine timing (CI diffed 51
to 59 percent on two grids).

Set maxPercentDifference to 0.5. CI measured 0.10 to 0.30 percent
antialiasing drift between macOS recorded goldens and Linux
verification on Paparazzi 1.3.4 (the newest version usable with Kotlin
1.9). Revisit with the Kotlin 2 / Paparazzi 1.3.5 upgrade, where the
chat repo runs the default threshold.

* Fix clipped and oversized snapshot goldens

Stack the wide component snapshots vertically instead of side by side.
The dark and light Row halves cap each side at half the device width,
which clipped the base component button rows and the call control
actions.

Split the portrait and landscape grid renderer tests into their own
classes (PortraitVideoRendererTest, LandscapeVideoRendererTest) kept on
full device rendering, and enable RenderingMode.SHRINK on the remaining
participant component tests so their goldens crop to content instead of
capturing a full screen.

* Split tall base component snapshots into light and dark files

The stacked dark and light halves cap each theme at half the device
height, which clipped the input fields and regular buttons goldens at
the bottom. These two tests now record a separate golden per theme,
like the full screen tests.

* Share preview composables between @Preview wrappers and snapshot tests

Every snapshot test now renders a shared internal preview composable
that the matching @Preview wrapper in src/debug also renders, so IDE
previews and goldens cannot drift apart. The test content is the source
of truth: the shared functions contain exactly what the tests composed,
and all golden files stay byte identical (verified by re-recording).

The test classes move to src/testDebug, keeping their packages, class
names, and method names, because tests that call src/debug internals
must compile only against the debug variant. previewGridCall moves to
src/debug so the grid previews can use it too. The microphone indicator
preview is renamed to resolve a pre-existing name clash with the sound
indicator preview.

* Address CodeRabbit review findings

Share a remote participant's screen in the 'for other participant'
screen sharing previews. Both fixtures shared the local user's screen,
so the two snapshots rendered the same state; the goldens now show the
'<name> is Presenting' variant.

Use the AutoMirrored icon variants in the button previews instead of
the deprecated ones. Rendering is identical in LTR, so no golden
changed.
…1778)

Add VideoComponentFactory, a public interface with default implementations
for the components behind the existing lambda slots on CallContent,
ParticipantVideo, ControlActions, CallLobby, CallAppBar and the ringing
screens. Each method takes a single params holder class, following the
ChatComponentFactory convention from the chat SDK.

The factory is provided through VideoTheme(componentFactory) and exposed
via VideoTheme.componentFactory. CompoundComponentFactory allows layering
overrides per subtree, and StreamCallActivityComposeDelegate exposes an
overridable componentFactory used by the screens it renders. All existing
lambda slots keep their signatures and now delegate to the factory by
default, so the change is source compatible and the snapshot suite is
unchanged. The new VideoTheme parameter does change its JVM signature, so
consumers need a recompile against this version.

The demo app shows a sample override: DemoComponentFactory replaces the
inline reaction and participant-action lambdas in CallScreen and is also
installed on the activity delegate.
…ry (#1785)

* [AND-1441] Route the remaining internal render paths through VideoComponentFactory

* [AND-1441] Extract the shared screen sharing fallback default
Bring develop into develop-v2: VideoComponentFactory, noise-cancellation SFU signaling, join analytics, and conventions 0.14.0, while keeping the v2 Kotlin 2.2 / StreamClient / WebRTC 137 stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@PratimMallick
PratimMallick requested a review from a team as a code owner August 31, 2026 06:38
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 12.29 MB 12.43 MB 0.14 MB 🟢
stream-video-android-ui-xml 5.70 MB 5.75 MB 0.05 MB 🟢
stream-video-android-ui-compose 6.23 MB 5.81 MB -0.43 MB 🚀

…teNative

The develop merge took the m145 `-libwebrtc` Maven coordinate and createNative(any()) while keeping NC 2.0.0 / WebRTC 137, which broke CI resolve and unit-test compilation.

Co-authored-by: Cursor <cursoragent@cursor.com>
andremion and others added 4 commits August 31, 2026 15:14
* Null-check the stop intent before stopService in cleanup

* Cover both stop-intent branches of cleanup with Robolectric tests
Bring in the NC signal test hardening, join-after-relogin wait, and stopService null-check from develop, keeping the v2 StreamClient cleanup tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

jobs:
pr-clean-stale:
uses: GetStream/stream-build-conventions-android/.github/workflows/pr-clean-stale.yaml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/pr-clean-stale.yaml@v0.14.0
jobs:
pr-checklist:
uses: GetStream/stream-build-conventions-android/.github/workflows/pr-quality.yml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/pr-quality.yml@v0.14.0
permissions:
contents: write
uses: GetStream/stream-build-conventions-android/.github/workflows/release.yml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/release.yml@v0.14.0
jobs:
compare-sdk-sizes:
uses: GetStream/stream-build-conventions-android/.github/workflows/sdk-size-checks.yml@v0.13.1
uses: GetStream/stream-build-conventions-android/.github/workflows/sdk-size-checks.yml@v0.14.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:internal Internal or infra-only changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants