Skip to content

Commit ab481d2

Browse files
Merge branch 'main' into QA-1126b/adding-native-sanity-test
2 parents b74d3b1 + 517198b commit ab481d2

570 files changed

Lines changed: 74780 additions & 6028 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ android {
5959
minSdk = libs.versions.minSdk.get().toInt()
6060
targetSdk = libs.versions.targetSdk.get().toInt()
6161
versionCode = 1
62-
versionName = "2025.4.0"
62+
versionName = "2025.7.0"
6363

6464
setProperty("archivesBaseName", "com.x8bit.bitwarden")
6565

app/src/debug/res/xml/provider.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<credential-provider>
3+
<capabilities>
4+
<capability name="android.credentials.TYPE_PASSWORD_CREDENTIAL" />
5+
<capability name="androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL" />
6+
</capabilities>
7+
</credential-provider>

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
<intent-filter>
8787
<action android:name="com.x8bit.bitwarden.credentials.ACTION_CREATE_PASSKEY" />
8888
<action android:name="com.x8bit.bitwarden.credentials.ACTION_GET_PASSKEY" />
89+
<action android:name="com.x8bit.bitwarden.credentials.ACTION_GET_PASSWORD" />
8990
<action android:name="com.x8bit.bitwarden.credentials.ACTION_UNLOCK_ACCOUNT" />
9091

9192
<category android:name="android.intent.category.DEFAULT" />

app/src/main/kotlin/com/x8bit/bitwarden/MainViewModel.kt

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.lifecycle.SavedStateHandle
66
import androidx.lifecycle.viewModelScope
77
import com.bitwarden.ui.platform.base.BaseViewModel
88
import com.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
9+
import com.bitwarden.ui.platform.resource.BitwardenString
910
import com.bitwarden.ui.util.Text
1011
import com.bitwarden.ui.util.asText
1112
import com.bitwarden.vault.CipherView
@@ -22,13 +23,12 @@ import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
2223
import com.x8bit.bitwarden.data.credentials.util.getCreateCredentialRequestOrNull
2324
import com.x8bit.bitwarden.data.credentials.util.getFido2AssertionRequestOrNull
2425
import com.x8bit.bitwarden.data.credentials.util.getGetCredentialsRequestOrNull
26+
import com.x8bit.bitwarden.data.credentials.util.getProviderGetPasswordRequestOrNull
2527
import com.x8bit.bitwarden.data.platform.manager.AppResumeManager
26-
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
2728
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
2829
import com.x8bit.bitwarden.data.platform.manager.garbage.GarbageCollectionManager
2930
import com.x8bit.bitwarden.data.platform.manager.model.AppResumeScreenData
3031
import com.x8bit.bitwarden.data.platform.manager.model.CompleteRegistrationData
31-
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
3232
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
3333
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
3434
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
@@ -68,7 +68,6 @@ private const val ANIMATION_REFRESH_DELAY = 500L
6868
class MainViewModel @Inject constructor(
6969
accessibilitySelectionManager: AccessibilitySelectionManager,
7070
autofillSelectionManager: AutofillSelectionManager,
71-
featureFlagManager: FeatureFlagManager,
7271
private val addTotpItemFromAuthenticatorManager: AddTotpItemFromAuthenticatorManager,
7372
private val specialCircumstanceManager: SpecialCircumstanceManager,
7473
private val garbageCollectionManager: GarbageCollectionManager,
@@ -85,9 +84,6 @@ class MainViewModel @Inject constructor(
8584
initialState = MainState(
8685
theme = settingsRepository.appTheme,
8786
isScreenCaptureAllowed = settingsRepository.isScreenCaptureAllowed,
88-
isErrorReportingDialogEnabled = featureFlagManager.getFeatureFlag(
89-
key = FlagKey.MobileErrorReporting,
90-
),
9187
isDynamicColorsEnabled = settingsRepository.isDynamicColorsEnabled,
9288
),
9389
) {
@@ -106,12 +102,6 @@ class MainViewModel @Inject constructor(
106102
.onEach { specialCircumstance = it }
107103
.launchIn(viewModelScope)
108104

109-
featureFlagManager
110-
.getFeatureFlagFlow(key = FlagKey.MobileErrorReporting)
111-
.map { MainAction.Internal.OnMobileErrorReportingReceive(it) }
112-
.onEach(::sendAction)
113-
.launchIn(viewModelScope)
114-
115105
accessibilitySelectionManager
116106
.accessibilitySelectionFlow
117107
.map { MainAction.Internal.AccessibilitySelectionReceive(it) }
@@ -217,17 +207,6 @@ class MainViewModel @Inject constructor(
217207
is MainAction.Internal.ThemeUpdate -> handleAppThemeUpdated(action)
218208
is MainAction.Internal.VaultUnlockStateChange -> handleVaultUnlockStateChange()
219209
is MainAction.Internal.DynamicColorsUpdate -> handleDynamicColorsUpdate(action)
220-
is MainAction.Internal.OnMobileErrorReportingReceive -> {
221-
handleOnMobileErrorReportingReceive(action)
222-
}
223-
}
224-
}
225-
226-
private fun handleOnMobileErrorReportingReceive(
227-
action: MainAction.Internal.OnMobileErrorReportingReceive,
228-
) {
229-
mutableStateFlow.update {
230-
it.copy(isErrorReportingDialogEnabled = action.isErrorReportingEnabled)
231210
}
232211
}
233212

@@ -325,6 +304,7 @@ class MainViewModel @Inject constructor(
325304
val createCredentialRequest = intent.getCreateCredentialRequestOrNull()
326305
val getCredentialsRequest = intent.getGetCredentialsRequestOrNull()
327306
val fido2AssertCredentialRequest = intent.getFido2AssertionRequestOrNull()
307+
val providerGetPasswordRequest = intent.getProviderGetPasswordRequestOrNull()
328308
when {
329309
passwordlessRequestData != null -> {
330310
authRepository.activeUserId?.let {
@@ -415,6 +395,19 @@ class MainViewModel @Inject constructor(
415395
)
416396
}
417397

398+
providerGetPasswordRequest != null -> {
399+
// Set the user's verification status when a new GetPassword request is
400+
// received to force explicit verification if the user's vault is
401+
// unlocked when the request is received.
402+
bitwardenCredentialManager.isUserVerified =
403+
providerGetPasswordRequest.isUserPreVerified
404+
405+
specialCircumstanceManager.specialCircumstance =
406+
SpecialCircumstance.ProviderGetPasswordRequest(
407+
passwordGetRequest = providerGetPasswordRequest,
408+
)
409+
}
410+
418411
getCredentialsRequest != null -> {
419412
specialCircumstanceManager.specialCircumstance =
420413
SpecialCircumstance.ProviderGetCredentials(
@@ -460,7 +453,8 @@ class MainViewModel @Inject constructor(
460453
message = emailTokenResult
461454
.message
462455
?.asText()
463-
?: R.string.there_was_an_issue_validating_the_registration_token
456+
?: BitwardenString
457+
.there_was_an_issue_validating_the_registration_token
464458
.asText(),
465459
),
466460
)
@@ -495,15 +489,12 @@ data class MainState(
495489
val theme: AppTheme,
496490
val isScreenCaptureAllowed: Boolean,
497491
val isDynamicColorsEnabled: Boolean,
498-
private val isErrorReportingDialogEnabled: Boolean,
499492
) : Parcelable {
500493
/**
501494
* Contains all feature flags that are available to the UI.
502495
*/
503496
val featureFlagsState: FeatureFlagsState
504-
get() = FeatureFlagsState(
505-
isErrorReportingDialogEnabled = isErrorReportingDialogEnabled,
506-
)
497+
get() = FeatureFlagsState
507498
}
508499

509500
/**
@@ -548,13 +539,6 @@ sealed class MainAction {
548539
val cipherView: CipherView,
549540
) : Internal()
550541

551-
/**
552-
* Indicates the Mobile Error Reporting feature flag has been updated.
553-
*/
554-
data class OnMobileErrorReportingReceive(
555-
val isErrorReportingEnabled: Boolean,
556-
) : Internal()
557-
558542
/**
559543
* Indicates the user has manually selected the given [cipherView] for autofill.
560544
*/

app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/AuthRequestNotificationManagerImpl.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import androidx.core.app.NotificationManagerCompat
1010
import com.bitwarden.annotation.OmitFromCoverage
1111
import com.bitwarden.data.manager.DispatcherManager
1212
import com.bitwarden.ui.platform.resource.BitwardenDrawable
13-
import com.x8bit.bitwarden.R
13+
import com.bitwarden.ui.platform.resource.BitwardenString
1414
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
1515
import com.x8bit.bitwarden.data.auth.util.createPasswordlessRequestDataIntent
1616
import com.x8bit.bitwarden.data.autofill.util.toPendingIntentMutabilityFlag
@@ -49,23 +49,23 @@ class AuthRequestNotificationManagerImpl(
4949
NOTIFICATION_CHANNEL_ID,
5050
NotificationManagerCompat.IMPORTANCE_DEFAULT,
5151
)
52-
.setName(context.getString(R.string.pending_log_in_requests))
52+
.setName(context.getString(BitwardenString.pending_log_in_requests))
5353
.build(),
5454
)
5555
if (!notificationManager.areNotificationsEnabled(NOTIFICATION_CHANNEL_ID)) return
5656
// Create the notification
5757
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
5858
.setContentIntent(createContentIntent(data))
59-
.setContentTitle(context.getString(R.string.log_in_requested))
59+
.setContentTitle(context.getString(BitwardenString.log_in_requested))
6060
.setContentText(
6161
authDiskSource
6262
.userState
6363
?.accounts
6464
?.get(data.userId)
6565
?.profile
6666
?.email
67-
?.let { context.getString(R.string.confim_log_in_attemp_for_x, it) }
68-
?: context.getString(R.string.confirm_log_in),
67+
?.let { context.getString(BitwardenString.confim_log_in_attemp_for_x, it) }
68+
?: context.getString(BitwardenString.confirm_log_in),
6969
)
7070
.setSmallIcon(BitwardenDrawable.ic_notification)
7171
.setColor(Color.White.value.toInt())

app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/UserLogoutManagerImpl.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import androidx.annotation.StringRes
44
import com.bitwarden.core.data.manager.toast.ToastManager
55
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
66
import com.bitwarden.data.manager.DispatcherManager
7-
import com.x8bit.bitwarden.R
7+
import com.bitwarden.ui.platform.resource.BitwardenString
88
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
99
import com.x8bit.bitwarden.data.auth.manager.model.LogoutEvent
1010
import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason
@@ -48,7 +48,7 @@ class UserLogoutManagerImpl(
4848
Timber.d("logout reason=$reason")
4949
val isExpired = reason == LogoutReason.SecurityStamp
5050
if (isExpired) {
51-
showToast(message = R.string.login_expired)
51+
showToast(message = BitwardenString.login_expired)
5252
}
5353

5454
val ableToSwitchToNewAccount = switchUserIfAvailable(
@@ -70,7 +70,7 @@ class UserLogoutManagerImpl(
7070
Timber.d("softLogout reason=$reason")
7171
val isExpired = reason == LogoutReason.SecurityStamp
7272
if (isExpired) {
73-
showToast(message = R.string.login_expired)
73+
showToast(message = BitwardenString.login_expired)
7474
}
7575
authDiskSource.storeAccountTokens(
7676
userId = userId,
@@ -140,7 +140,7 @@ class UserLogoutManagerImpl(
140140
// Check if there is a new active user
141141
return if (updatedAccounts.isNotEmpty()) {
142142
if (currentUserId == currentUserState.activeUserId && !isExpired) {
143-
showToast(message = R.string.account_switched_automatically)
143+
showToast(message = BitwardenString.account_switched_automatically)
144144
}
145145

146146
// If we logged out a non-active user, we want to leave the active user unchanged.

app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/accessibility/processor/BitwardenAccessibilityProcessorImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import android.view.accessibility.AccessibilityEvent
66
import android.view.accessibility.AccessibilityNodeInfo
77
import android.widget.Toast
88
import com.bitwarden.core.data.manager.toast.ToastManager
9-
import com.x8bit.bitwarden.R
9+
import com.bitwarden.ui.platform.resource.BitwardenString
1010
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilityAutofillManager
1111
import com.x8bit.bitwarden.data.autofill.accessibility.manager.LauncherPackageNameManager
1212
import com.x8bit.bitwarden.data.autofill.accessibility.model.AccessibilityAction
@@ -113,7 +113,7 @@ class BitwardenAccessibilityProcessorImpl(
113113
}
114114
?: run {
115115
toastManager.show(
116-
messageId = R.string.autofill_tile_uri_not_found,
116+
messageId = BitwardenString.autofill_tile_uri_not_found,
117117
duration = Toast.LENGTH_LONG,
118118
)
119119
}

app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/di/AutofillModule.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import com.x8bit.bitwarden.data.autofill.processor.AutofillProcessor
2424
import com.x8bit.bitwarden.data.autofill.processor.AutofillProcessorImpl
2525
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider
2626
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProviderImpl
27-
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
2827
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
2928
import com.x8bit.bitwarden.data.platform.manager.ciphermatching.CipherMatchingManager
3029
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
@@ -59,12 +58,8 @@ object AutofillModule {
5958

6059
@Singleton
6160
@Provides
62-
fun providesBrowserAutofillEnabledManager(
63-
featureFlagManager: FeatureFlagManager,
64-
): BrowserThirdPartyAutofillEnabledManager =
65-
BrowserThirdPartyAutofillEnabledManagerImpl(
66-
featureFlagManager = featureFlagManager,
67-
)
61+
fun providesBrowserAutofillEnabledManager(): BrowserThirdPartyAutofillEnabledManager =
62+
BrowserThirdPartyAutofillEnabledManagerImpl()
6863

6964
@Singleton
7065
@Provides

app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/manager/AutofillTotpManagerImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.x8bit.bitwarden.data.autofill.manager
22

3+
import com.bitwarden.ui.platform.resource.BitwardenString
34
import com.bitwarden.ui.util.asText
45
import com.bitwarden.vault.CipherView
5-
import com.x8bit.bitwarden.R
66
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
77
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
88
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
@@ -34,7 +34,7 @@ class AutofillTotpManagerImpl(
3434
if (totpResult is GenerateTotpResult.Success) {
3535
clipboardManager.setText(
3636
text = totpResult.code,
37-
toastDescriptorOverride = R.string.verification_code_totp.asText(),
37+
toastDescriptorOverride = BitwardenString.verification_code_totp.asText(),
3838
)
3939
}
4040
}

app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/manager/browser/BrowserThirdPartyAutofillEnabledManagerImpl.kt

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@ package com.x8bit.bitwarden.data.autofill.manager.browser
22

33
import com.x8bit.bitwarden.data.autofill.model.browser.BrowserThirdPartyAutoFillData
44
import com.x8bit.bitwarden.data.autofill.model.browser.BrowserThirdPartyAutofillStatus
5-
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
6-
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
75
import kotlinx.coroutines.flow.Flow
86
import kotlinx.coroutines.flow.MutableStateFlow
9-
import kotlinx.coroutines.flow.combine
107
import kotlinx.coroutines.flow.update
118

129
/**
1310
* Default implementation of [BrowserThirdPartyAutofillEnabledManager].
1411
*/
15-
class BrowserThirdPartyAutofillEnabledManagerImpl(
16-
private val featureFlagManager: FeatureFlagManager,
17-
) : BrowserThirdPartyAutofillEnabledManager {
12+
class BrowserThirdPartyAutofillEnabledManagerImpl : BrowserThirdPartyAutofillEnabledManager {
1813
override var browserThirdPartyAutofillStatus: BrowserThirdPartyAutofillStatus = DEFAULT_STATUS
1914
set(value) {
2015
field = value
@@ -29,15 +24,6 @@ class BrowserThirdPartyAutofillEnabledManagerImpl(
2924

3025
override val browserThirdPartyAutofillStatusFlow: Flow<BrowserThirdPartyAutofillStatus>
3126
get() = mutableBrowserThirdPartyAutofillStatusStateFlow
32-
.combine(
33-
featureFlagManager.getFeatureFlagFlow(FlagKey.ChromeAutofill),
34-
) { data, enabled ->
35-
if (enabled) {
36-
data
37-
} else {
38-
DEFAULT_STATUS
39-
}
40-
}
4127
}
4228

4329
private val DEFAULT_STATUS = BrowserThirdPartyAutofillStatus(

0 commit comments

Comments
 (0)