Repository: wireapp/wire-android
Pull request #4003: fix: move mls jobs to start from te UI [WPB-17367]
Author: login: MohamadJaara
Labels: name: size/XS
Created: 2025-04-24T16:01:57Z | Merged: 2025-04-25T13:45:33Z

<!--do not remove this marker, its needed to replace info when ticket title is updated -->
<!--jira-description-action-hidden-marker-start-->

<table>
<td>
  <a href="https://wearezeta.atlassian.net/browse/WPB-17367" title="WPB-17367" target="_blank"><img alt="Bug" src="https://wearezeta.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10803?size=medium" />WPB-17367</a>  [Android] unlimited MLS jobs when sync goes live
  </td></table>
  <br />
 

<!--jira-description-action-hidden-marker-end-->
----
#### PR Submission Checklist for internal contributors

- The **PR Title**
    - [ ] conforms to the style of semantic commits messages¹ supported in Wire's Github Workflow²
    - [ ] contains a reference JIRA issue number like `SQPIT-764`
    - [ ] answers the question: _If merged, this PR will: ..._ ³

- The **PR Description**
    - [ ] is free of optional paragraphs and you have filled the relevant parts to the best of your ability
----

# What's new in this PR?

### Issues

move MLS jobs to kick start only from the foreground

Needs releases with:

- [ ] GitHub link to other pull request

### Testing

#### Test Coverage (Optional)

- [ ] I have added automated test to this contribution

#### How to Test

_Briefly describe how this change was tested and if applicable the exact steps taken to verify that it works as expected._

### Notes (Optional)

_Specify here any other facts that you think are important for this issue._

### Attachments (Optional)

_Attachments like images, videos, etc. (drag and drop in the text box)_ 
<!-- Uncomment the brackets and place your screenshots on the table below. -->
<!--
| Before | After |
| ----------- | ------------ |
|   |   |
-->

----
#### PR Post Submission Checklist for internal contributors (Optional)

- [ ] Wire's Github Workflow has automatically linked the PR to a JIRA issue
----
#### PR Post Merge Checklist for internal contributors

- [ ] If any soft of configuration variable was introduced by this PR, it has been added to the relevant documents and the CI jobs have been updated.
----
##### References
1. https://sparkbox.com/foundry/semantic_commit_messages
1. https://github.com/wireapp/.github#usage
1. E.g. `feat(conversation-list): Sort conversations by most emojis in the title #SQPIT-764`.



Diff:
diff --git a/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt b/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt
index 117c1a6fe55..adb00a9d3f5 100644
--- a/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt
+++ b/app/src/main/kotlin/com/wire/android/di/CoreLogicModule.kt
@@ -33,12 +33,15 @@ import com.wire.kalium.logic.feature.analytics.GetCurrentAnalyticsTrackingIdenti
 import com.wire.kalium.logic.feature.auth.AddAuthenticatedUserUseCase
 import com.wire.kalium.logic.feature.auth.LogoutUseCase
 import com.wire.kalium.logic.feature.auth.sso.ValidateSSOCodeUseCase
+import com.wire.kalium.logic.feature.client.MLSClientManager
 import com.wire.kalium.logic.feature.connection.BlockUserUseCase
 import com.wire.kalium.logic.feature.connection.UnblockUserUseCase
 import com.wire.kalium.logic.feature.conversation.ObserveOtherUserSecurityClassificationLabelUseCase
 import com.wire.kalium.logic.feature.conversation.ObserveSecurityClassificationLabelUseCase
+import com.wire.kalium.logic.feature.conversation.keyingmaterials.KeyingMaterialsManager
 import com.wire.kalium.logic.feature.e2ei.usecase.FetchConversationMLSVerificationStatusUseCase
 import com.wire.kalium.logic.feature.featureConfig.ObserveIsAppLockEditableUseCase
+import com.wire.kalium.logic.feature.mlsmigration.MLSMigrationManager
 import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveSelfDeletionTimerSettingsForConversationUseCase
 import com.wire.kalium.logic.feature.selfDeletingMessages.ObserveTeamSettingsSelfDeletingStatusUseCase
 import com.wire.kalium.logic.feature.selfDeletingMessages.PersistNewSelfDeletionTimerUseCase
@@ -202,6 +205,30 @@ class UseCaseModule {
     fun provideValidateSSOCodeUseCase(@KaliumCoreLogic coreLogic: CoreLogic): ValidateSSOCodeUseCase =
         coreLogic.getGlobalScope().validateSSOCodeUseCase
 
+    @ViewModelScoped
+    @Provides
+    fun provideMLSMigrationManager(
+        @KaliumCoreLogic coreLogic: CoreLogic,
+        @CurrentAccount currentAccount: UserId
+    ): MLSMigrationManager =
+        coreLogic.getSessionScope(currentAccount).mlsMigrationManager
+
+    @ViewModelScoped
+    @Provides
+    fun provideMLSClientManager(
+        @KaliumCoreLogic coreLogic: CoreLogic,
+        @CurrentAccount currentAccount: UserId
+    ): MLSClientManager =
+        coreLogic.getSessionScope(currentAccount).mlsClientManager
+
+    @ViewModelScoped
+    @Provides
+    fun provideKeyingMaterialsManager(
+        @KaliumCoreLogic coreLogic: CoreLogic,
+        @CurrentAccount currentAccount: UserId
+    ): KeyingMaterialsManager =
+        coreLogic.getSessionScope(currentAccount).keyingMaterialsManager
+
     @ViewModelScoped
     @Provides
     fun provideValidatePasswordUseCase(@KaliumCoreLogic coreLogic: CoreLogic) =
diff --git a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
index cf9839278b4..857285c47f8 100644
--- a/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
+++ b/app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
@@ -20,9 +20,12 @@ package com.wire.android.ui.home
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import com.wire.android.appLogger
+import com.wire.kalium.logic.feature.client.MLSClientManager
+import com.wire.kalium.logic.feature.conversation.keyingmaterials.KeyingMaterialsManager
 import com.wire.kalium.logic.feature.e2ei.SyncCertificateRevocationListUseCase
 import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase
 import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker
+import com.wire.kalium.logic.feature.mlsmigration.MLSMigrationManager
 import com.wire.kalium.logic.feature.server.UpdateApiVersionsUseCase
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Job
@@ -39,8 +42,11 @@ class AppSyncViewModel @Inject constructor(
     private val syncCertificateRevocationListUseCase: SyncCertificateRevocationListUseCase,
     private val observeCertificateRevocationForSelfClient: ObserveCertificateRevocationForSelfClientUseCase,
     private val featureFlagsSyncWorker: FeatureFlagsSyncWorker,
-    private val updateApiVersions: UpdateApiVersionsUseCase
-) : ViewModel() {
+    private val updateApiVersions: UpdateApiVersionsUseCase,
+    private val mLSMigrationManager: MLSMigrationManager,
+    private val keyingMaterialsManager: KeyingMaterialsManager,
+    private val mLSClientManager: MLSClientManager,
+    ) : ViewModel() {
 
     private val minIntervalBetweenPulls: Duration = MIN_INTERVAL_BETWEEN_PULLS
 
@@ -77,6 +83,9 @@ class AppSyncViewModel @Inject constructor(
                 viewModelScope.launch { featureFlagsSyncWorker.execute() },
                 viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() },
                 viewModelScope.launch { updateApiVersions() },
+                viewModelScope.launch { mLSClientManager() },
+                viewModelScope.launch { mLSMigrationManager() },
+                viewModelScope.launch { keyingMaterialsManager() },
             ).joinAll()
         } catch (e: Exception) {
             appLogger.e("Error while syncing app config", e)
diff --git a/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt
index 531731fc301..14364a3839c 100644
--- a/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt
+++ b/app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt
@@ -18,15 +18,17 @@
 package com.wire.android.ui.home
 
 import com.wire.android.config.CoroutineTestExtension
+import com.wire.kalium.logic.feature.client.MLSClientManager
+import com.wire.kalium.logic.feature.conversation.keyingmaterials.KeyingMaterialsManager
 import com.wire.kalium.logic.feature.e2ei.SyncCertificateRevocationListUseCase
 import com.wire.kalium.logic.feature.e2ei.usecase.ObserveCertificateRevocationForSelfClientUseCase
 import com.wire.kalium.logic.feature.featureConfig.FeatureFlagsSyncWorker
+import com.wire.kalium.logic.feature.mlsmigration.MLSMigrationManager
 import com.wire.kalium.logic.feature.server.UpdateApiVersionsUseCase
 import io.mockk.MockKAnnotations
 import io.mockk.coEvery
 import io.mockk.coVerify
 import io.mockk.impl.annotations.MockK
-import kotlinx.coroutines.InternalCoroutinesApi
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.test.advanceUntilIdle
 import kotlinx.coroutines.test.runTest
@@ -42,6 +44,9 @@ class AppSyncViewModelTest {
             withFeatureFlagsSyncWorker()
             withSyncCertificateRevocationListUseCase()
             withUpdateApiVersions()
+            withMlsClientManager()
+            withMlsMigrationManager()
+            withKeyingMaterialsManager()
         }
 
         viewModel.startSyncingAppConfig()
@@ -51,6 +56,9 @@ class AppSyncViewModelTest {
         coVerify { arrangement.syncCertificateRevocationListUseCase.invoke() }
         coVerify { arrangement.featureFlagsSyncWorker.execute() }
         coVerify { arrangement.updateApiVersions() }
+        coVerify { arrangement.mlsClientManager() }
+        coVerify { arrangement.mlsMigrationManager() }
+        coVerify { arrangement.keyingMaterialsManager() }
     }
 
     @Test
@@ -60,6 +68,9 @@ class AppSyncViewModelTest {
             withFeatureFlagsSyncWorker(1000)
             withSyncCertificateRevocationListUseCase(1000)
             withUpdateApiVersions(1000)
+            withMlsClientManager(1000)
+            withMlsMigrationManager(1000)
+            withKeyingMaterialsManager(1000)
         }
 
         viewModel.startSyncingAppConfig()
@@ -71,6 +82,9 @@ class AppSyncViewModelTest {
         coVerify(exactly = 1) { arrangement.syncCertificateRevocationListUseCase.invoke() }
         coVerify(exactly = 1) { arrangement.featureFlagsSyncWorker.execute() }
         coVerify(exactly = 1) { arrangement.updateApiVersions() }
+        coVerify(exactly = 1) { arrangement.mlsClientManager() }
+        coVerify(exactly = 1) { arrangement.mlsMigrationManager() }
+        coVerify(exactly = 1) { arrangement.keyingMaterialsManager() }
     }
 
     private class Arrangement {
@@ -87,6 +101,15 @@ class AppSyncViewModelTest {
         @MockK
         lateinit var updateApiVersions: UpdateApiVersionsUseCase
 
+        @MockK
+        lateinit var mlsClientManager: MLSClientManager
+
+        @MockK
+        lateinit var mlsMigrationManager: MLSMigrationManager
+
+        @MockK
+        lateinit var keyingMaterialsManager: KeyingMaterialsManager
+
         init {
             MockKAnnotations.init(this)
         }
@@ -95,10 +118,12 @@ class AppSyncViewModelTest {
             syncCertificateRevocationListUseCase,
             observeCertificateRevocationForSelfClient,
             featureFlagsSyncWorker,
-            updateApiVersions
+            updateApiVersions,
+            mLSClientManager = mlsClientManager,
+            mLSMigrationManager = mlsMigrationManager,
+            keyingMaterialsManager = keyingMaterialsManager
         )
 
-        @OptIn(InternalCoroutinesApi::class)
         fun withObserveCertificateRevocationForSelfClient(delayMs: Long = 0) {
             coEvery { observeCertificateRevocationForSelfClient.invoke() } coAnswers {
                 delay(delayMs)
@@ -123,6 +148,24 @@ class AppSyncViewModelTest {
             }
         }
 
+        fun withMlsClientManager(delayMs: Long = 0) {
+            coEvery { mlsClientManager() } coAnswers {
+                delay(delayMs)
+            }
+        }
+
+        fun withMlsMigrationManager(delayMs: Long = 0) {
+            coEvery { mlsMigrationManager() } coAnswers {
+                delay(delayMs)
+            }
+        }
+
+        fun withKeyingMaterialsManager(delayMs: Long = 0) {
+            coEvery { keyingMaterialsManager() } coAnswers {
+                delay(delayMs)
+            }
+        }
+
         fun arrange(block: Arrangement.() -> Unit) = apply(block).let {
             this to viewModel
         }
diff --git a/kalium b/kalium
index a80946f8bba..cd054fa4afe 160000
--- a/kalium
+++ b/kalium
@@ -1 +1 @@
-Subproject commit a80946f8bba2333f65378632497a918d657b3f0e
+Subproject commit cd054fa4afe873a2ab82245e7262d38b1ef0906b


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR updates the foreground MLS job initiation by adding new manager invocations and updating dependency injections.  
- Introduces new manager dependencies (MLSMigrationManager, KeyingMaterialsManager, and MLSClientManager) in AppSyncViewModel  
- Removes the lowerKeyingMaterialsUpdateThreshold configuration in KaliumConfigsModule

### Reviewed Changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

| File | Description |
| ---- | ----------- |
| app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt | Added new MLS job managers and invoked them within viewModelScope |
| app/src/main/kotlin/com/wire/android/di/KaliumConfigsModule.kt | Removed lowerKeyingMaterialsUpdateThreshold configuration |

<details>
<summary>Files not reviewed (1)</summary>

* **kalium**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt:47**
* [nitpick] The parameter name 'mLSMigrationManager' appears to violate common camelCase conventions. Consider renaming it to 'mlsMigrationManager' (and similarly update 'mLSClientManager') for consistency.
```
private val mLSMigrationManager: MLSMigrationManager,
```
**app/src/main/kotlin/com/wire/android/di/KaliumConfigsModule.kt:51**
* The removal of 'lowerKeyingMaterialsUpdateThreshold' may have side effects on parts of the system relying on this configuration. Please confirm that this change is intentional and that no dependent functionality is affected.
```
lowerKeyingMaterialsUpdateThreshold = BuildConfig.PRIVATE_BUILD,
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T16:02:24Z
user: login: vitorhugods
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T10:09:08Z
user: login: MohamadJaara
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T10:14:13Z
user: login: MohamadJaara
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T10:15:28Z
user: login: vitorhugods
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T10:16:01Z
user: login: vitorhugods
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T10:16:06Z
user: login: Garzas
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T10:36:10Z

Review comments:
diff_hunk: @@ -77,6 +84,9 @@ class AppSyncViewModel @Inject constructor(
                 viewModelScope.launch { featureFlagsSyncWorker.execute() },
                 viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() },
                 viewModelScope.launch { updateApiVersions() },
+                viewModelScope.launch { mLSClientManager() },
+                viewModelScope.launch { mLSMigrationManager() },
+                viewModelScope.launch { keyingMaterialsManager() },
path: app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
user: login: vitorhugods
body: Instead of having the app explicitly knowing about MLS and how it works, can't we just mutate a `hasForegroundPriorityState` thing, and let the business logic handle itself in a single place within `Kalium`? 

Every time we add a new guy, we need to remember to do it here too. Also, other tools like TestService or whatever might be completely broken with these changes.

It would be similar to `NotifyConversationisOpenUseCase`, instead of having the ViewModels calling multiple UseCases, we centralise operations in a single point (clean up ephemeral, resolve 1:1, etc).
created_at: 2025-04-25T10:09:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -77,6 +84,9 @@ class AppSyncViewModel @Inject constructor(
                 viewModelScope.launch { featureFlagsSyncWorker.execute() },
                 viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() },
                 viewModelScope.launch { updateApiVersions() },
+                viewModelScope.launch { mLSClientManager() },
+                viewModelScope.launch { mLSMigrationManager() },
+                viewModelScope.launch { keyingMaterialsManager() },
path: app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
user: login: MohamadJaara
body: that will be a nice solution for a bigger refactor, there are quite a lot of those worker that runs on kalium init that i would like to make em all cleaner, but this will take quite some time that we do not have, for now what do you think about this approach that we can revisit later?
created_at: 2025-04-25T10:14:13Z
author_association: MEMBER
diff_hunk: @@ -77,6 +84,9 @@ class AppSyncViewModel @Inject constructor(
                 viewModelScope.launch { featureFlagsSyncWorker.execute() },
                 viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() },
                 viewModelScope.launch { updateApiVersions() },
+                viewModelScope.launch { mLSClientManager() },
+                viewModelScope.launch { mLSMigrationManager() },
+                viewModelScope.launch { keyingMaterialsManager() },
path: app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
user: login: MohamadJaara
body: for me the most important part is to not run all of this on every sync live update 
created_at: 2025-04-25T10:15:28Z
author_association: MEMBER
diff_hunk: @@ -77,6 +84,9 @@ class AppSyncViewModel @Inject constructor(
                 viewModelScope.launch { featureFlagsSyncWorker.execute() },
                 viewModelScope.launch { observeCertificateRevocationForSelfClient.invoke() },
                 viewModelScope.launch { updateApiVersions() },
+                viewModelScope.launch { mLSClientManager() },
+                viewModelScope.launch { mLSMigrationManager() },
+                viewModelScope.launch { keyingMaterialsManager() },
path: app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt
user: login: vitorhugods
body: Just... other than increasing debt, it might still break TestService (not sure), so QA might not be the happiest about this "temporary change".
created_at: 2025-04-25T10:16:01Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-04-25T10:44:22Z
body: ## [Codecov](https://app.codecov.io/gh/wireapp/wire-android/pull/4003?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 46.02%. Comparing base [(`a4275ef`)](https://app.codecov.io/gh/wireapp/wire-android/commit/a4275ef3ca7effce3b9e2d9283f0e3ac1d9e4a35?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp) to head [(`a07820d`)](https://app.codecov.io/gh/wireapp/wire-android/commit/a07820d4cacd9130cc9274b978b7708f8b382228?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp).
> Report is 1 commits behind head on develop.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop    #4003      +/-   ##
===========================================
+ Coverage    46.00%   46.02%   +0.01%     
===========================================
  Files          518      518              
  Lines        18051    18057       +6     
  Branches      3031     3031              
===========================================
+ Hits          8304     8310       +6     
  Misses        8889     8889              
  Partials       858      858              
```

| [Files with missing lines](https://app.codecov.io/gh/wireapp/wire-android/pull/4003?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp) | Coverage Δ | |
|---|---|---|
| [...otlin/com/wire/android/ui/home/AppSyncViewModel.kt](https://app.codecov.io/gh/wireapp/wire-android/pull/4003?src=pr&el=tree&filepath=app%2Fsrc%2Fmain%2Fkotlin%2Fcom%2Fwire%2Fandroid%2Fui%2Fhome%2FAppSyncViewModel.kt&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp#diff-YXBwL3NyYy9tYWluL2tvdGxpbi9jb20vd2lyZS9hbmRyb2lkL3VpL2hvbWUvQXBwU3luY1ZpZXdNb2RlbC5rdA==) | `81.25% <100.00%> (+4.32%)` | :arrow_up: |

------

[Continue to review full report in Codecov by Sentry](https://app.codecov.io/gh/wireapp/wire-android/pull/4003?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://app.codecov.io/gh/wireapp/wire-android/pull/4003?dropdown=coverage&src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp). Last update [a4275ef...a07820d](https://app.codecov.io/gh/wireapp/wire-android/pull/4003?dropdown=coverage&src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wireapp).

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-25T13:45:53Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=wireapp_wire-android&pullRequest=4003) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=wireapp_wire-android&pullRequest=4003&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=wireapp_wire-android&pullRequest=4003&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=wireapp_wire-android&pullRequest=4003&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=wireapp_wire-android&pullRequest=4003&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=wireapp_wire-android&pullRequest=4003&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=wireapp_wire-android&pullRequest=4003)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-25T14:24:46Z
body: Built [wire-android-staging-compat-pr-4003.apk]() is available for download
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-25T14:24:59Z
body: Built [wire-android-dev-debug-pr-4003.apk]() is available for download
author_association: CONTRIBUTOR