Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ interface DebugMenuRepository {
*/
fun resetCoachMarkTourStatuses()

/**
* Resets the value for displaying the accessibility disclaimer.
*/
fun resetAccessibilityDisclaimer()

/**
* Manipulates the state to force showing the onboarding carousel.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class DebugMenuRepositoryImpl(
settingsDiskSource.storeShouldShowAddLoginCoachMark(shouldShow = null)
}

override fun resetAccessibilityDisclaimer() {
settingsDiskSource.hasShownAccessibilityDisclaimer = null
}

override fun modifyStateToShowOnboardingCarousel(
userStateUpdateTrigger: () -> Unit,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ fun AccessibilityDisclosureScreen(
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top),
) {
AccessibilityDisclosureContent(
onAcceptClick = {
viewModel.trySendAction(AccessibilityDisclosureAction.AcceptClicked)
iUnderstandClick = {
viewModel.trySendAction(AccessibilityDisclosureAction.IUnderstandClick)
},
onCloseAppClick = {
viewModel.trySendAction(AccessibilityDisclosureAction.CloseAppClick)
Expand All @@ -74,9 +74,10 @@ fun AccessibilityDisclosureScreen(
}
}

@Suppress("LongMethod")
@Composable
private fun AccessibilityDisclosureContent(
onAcceptClick: () -> Unit,
iUnderstandClick: () -> Unit,
onCloseAppClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand Down Expand Up @@ -111,8 +112,32 @@ private fun AccessibilityDisclosureContent(
Spacer(modifier = Modifier.height(height = 12.dp))

Text(
text = stringResource(id = BitwardenString.accessibility_disclosure_start_up_text),
text = stringResource(id = BitwardenString.accessibility_disclosure_start_up_text_1),
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)

Spacer(modifier = Modifier.height(height = 12.dp))

Text(
text = stringResource(id = BitwardenString.accessibility_disclosure_start_up_text_2),
style = BitwardenTheme.typography.bodySmall,
color = BitwardenTheme.colorScheme.text.primary,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)

Spacer(modifier = Modifier.height(height = 12.dp))

Text(
text = stringResource(id = BitwardenString.accessibility_disclosure_start_up_text_3),
style = BitwardenTheme.typography.bodySmall,
color = BitwardenTheme.colorScheme.text.primary,
textAlign = TextAlign.Center,
modifier = Modifier
Expand All @@ -123,8 +148,8 @@ private fun AccessibilityDisclosureContent(
Spacer(modifier = Modifier.height(height = 24.dp))

BitwardenFilledButton(
label = stringResource(id = BitwardenString.accept),
onClick = onAcceptClick,
label = stringResource(id = BitwardenString.i_understand),
onClick = iUnderstandClick,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
Expand All @@ -150,7 +175,7 @@ private fun AccessibilityDisclosureContent(
private fun AccessibilityDisclosureContent_preview() {
BitwardenTheme {
AccessibilityDisclosureContent(
onAcceptClick = {},
iUnderstandClick = {},
onCloseAppClick = {},
modifier = Modifier.fillMaxSize(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ class AccessibilityDisclosureViewModel @Inject constructor(
) {
override fun handleAction(action: AccessibilityDisclosureAction) {
when (action) {
AccessibilityDisclosureAction.AcceptClicked -> handleAcceptClicked()
AccessibilityDisclosureAction.IUnderstandClick -> handleIUnderstandClick()
AccessibilityDisclosureAction.CloseAppClick -> handleCloseAppClick()
}
}

private fun handleAcceptClicked() {
private fun handleIUnderstandClick() {
settingsRepository.accessibilityDisclaimerHasBeenShown()
sendEvent(AccessibilityDisclosureEvent.Dismiss)
}
Expand Down Expand Up @@ -63,9 +63,9 @@ sealed class AccessibilityDisclosureEvent {
*/
sealed class AccessibilityDisclosureAction {
/**
* User clicked the accept button.
* User clicked the "I understand" button.
*/
data object AcceptClicked : AccessibilityDisclosureAction()
data object IUnderstandClick : AccessibilityDisclosureAction()

/**
* User clicked the close app button.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,15 @@ fun DebugMenuScreen(
viewModel.trySendAction(DebugMenuAction.RestartOnboardingCarousel)
},
)
Spacer(Modifier.height(16.dp))
Spacer(modifier = Modifier.height(height = 16.dp))
BitwardenFilledButton(
label = stringResource(id = BitwardenString.reset_accessibility_disclaimer),
onClick = { viewModel.trySendAction(DebugMenuAction.ResetAccessibilityDisclaimer) },
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(height = 8.dp))
BitwardenFilledButton(
label = stringResource(BitwardenString.reset_coach_mark_tour_status),
onClick = { viewModel.trySendAction(DebugMenuAction.ResetCoachMarkTourStatuses) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,14 @@ class DebugMenuViewModel @Inject constructor(
DebugMenuAction.ClearSsoCookies -> handleClearSsoCookies()
DebugMenuAction.ResetPremiumUpgradeBanner -> handleResetPremiumUpgradeBanner()
DebugMenuAction.ShowUpgradedToPremiumCard -> handleShowUpgradedToPremiumCard()
DebugMenuAction.ResetAccessibilityDisclaimer -> handleResetAccessibilityDisclaimer()
}
}

private fun handleResetAccessibilityDisclaimer() {
debugMenuRepository.resetAccessibilityDisclaimer()
}

private fun handleShowUpgradedToPremiumCard() {
debugMenuRepository.showUpgradedToPremiumCard()
}
Expand Down Expand Up @@ -186,6 +191,11 @@ sealed class DebugMenuAction {
*/
data object RestartOnboarding : DebugMenuAction()

/**
* The user has clicked the reset accessibility disclaimer button.
*/
data object ResetAccessibilityDisclaimer : DebugMenuAction()

/**
* The user has clicked the restart onboarding button for the onboarding section.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ class DebugMenuRepositoryTest {
assertTrue(lambdaHasBeenCalled)
}

@Test
fun `resetAccessibilityDisclaimer calls settings disk source setting value back to null`() {
every { mockSettingsDiskSource.hasShownAccessibilityDisclaimer = null } just runs

debugMenuRepository.resetAccessibilityDisclaimer()

verify(exactly = 1) {
mockSettingsDiskSource.hasShownAccessibilityDisclaimer = null
}
}

@Test
fun `resetCoachMarkTourStatuses calls settings disk source setting values back to null`() {
every {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ class AccessibilityDisclosureScreenTest : BitwardenComposeTest() {
}

@Test
fun `accept button click should send AcceptClicked action`() {
fun `i understand button click should send IUnderstandClick action`() {
composeTestRule
.onNodeWithText(text = "Accept")
.onNodeWithText(text = "I understand")
.performScrollTo()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(AccessibilityDisclosureAction.AcceptClicked)
viewModel.trySendAction(AccessibilityDisclosureAction.IUnderstandClick)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ class AccessibilityDisclosureViewModelTest : BaseViewModelTest() {
}

@Test
fun `AcceptClicked should mark disclaimer as shown and emit Dismiss event`() = runTest {
fun `IUnderstandClick should mark disclaimer as shown and emit Dismiss event`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(AccessibilityDisclosureAction.AcceptClicked)
viewModel.trySendAction(AccessibilityDisclosureAction.IUnderstandClick)
assertEquals(AccessibilityDisclosureEvent.Dismiss, awaitItem())
}
verify(exactly = 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,18 @@ class DebugMenuScreenTest : BitwardenComposeTest() {
}
}

@Test
fun `reset accessibility disclaimer should send ResetAccessibilityDisclaimer action`() {
composeTestRule
.onNodeWithText("Reset accessibility disclaimer")
.performScrollTo()
.performClick()

verify(exactly = 1) {
viewModel.trySendAction(DebugMenuAction.ResetAccessibilityDisclaimer)
}
}

@Test
fun `reset all coach mark tours should send ResetCoachMarkTourStatuses action`() {
composeTestRule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class DebugMenuViewModelTest : BaseViewModelTest() {
coEvery { resetFeatureFlagOverrides() } just runs
every { updateFeatureFlag<Boolean>(any(), any()) } just runs
every { resetOnboardingStatusForCurrentUser() } just runs
every { resetAccessibilityDisclaimer() } just runs
every {
modifyStateToShowOnboardingCarousel(userStateUpdateTrigger = any())
} answers {
Expand Down Expand Up @@ -134,6 +135,15 @@ class DebugMenuViewModelTest : BaseViewModelTest() {
}
}

@Test
fun `ResetAccessibilityDisclaimer should call repository to reset values`() {
val viewModel = createViewModel()
viewModel.trySendAction(DebugMenuAction.ResetAccessibilityDisclaimer)
verify(exactly = 1) {
mockDebugMenuRepository.resetAccessibilityDisclaimer()
}
}

@Test
fun `handleResetCoachMarkTourStatuses should call repository to reset values`() {
val viewModel = createViewModel()
Expand Down
5 changes: 4 additions & 1 deletion ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,10 @@ select Add TOTP to store the key safely</string>
<string name="forwarded_email_description">Generate an email alias with an external forwarding service.</string>
<string name="accessibility_service_disclosure">Accessibility Service Disclosure</string>
<string name="accessibility_disclosure_text">Bitwarden uses the Accessibility Service to search for login fields in apps and websites, then establish the appropriate field IDs for entering a username &amp; password when a match for the app or site is found. We do not store any of the information presented to us by the service, nor do we make any attempt to control any on-screen elements beyond text entry of credentials.</string>
<string name="accessibility_disclosure_start_up_text">Bitwarden offers an optional autofill method that uses Android’s Accessibility Service to detect login fields in apps and websites. If you choose to enable it, Bitwarden will identify the appropriate fields and enter your credentials when a match is found. We do not store any information observed by the service, and we do not control any on-screen elements beyond credential entry.</string>
<string name="accessibility_disclosure_start_up_text_1">This notice is required before Bitwarden can offer accessibility-based autofill.</string>
<string name="accessibility_disclosure_start_up_text_2">Bitwarden offers an optional autofill method that uses Android’s Accessibility Service to detect login fields. If you enable it, Bitwarden will identify the appropriate fields and fill in your credentials when a match is found.</string>
<string name="accessibility_disclosure_start_up_text_3">We don’t store any information about what’s onscreen while you use the Accessibility Service, and we don’t control any onscreen elements beyond credential entry.</string>
<string name="i_understand">I understand</string>
<string name="accept">Accept</string>
<string name="decline">Decline</string>
<string name="login_request_has_already_expired">Login request has already expired.</string>
Expand Down
1 change: 1 addition & 0 deletions ui/src/main/res/values/strings_non_localized.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<string name="restart_onboarding_carousel">Show Onboarding Carousel</string>
<string name="restart_onboarding_carousel_details">This will force the change to app state which will cause the first time carousel to show. The carousel will continue to show for any \"new\" account until a login is completed. May need to exit debug menu manually.</string>
<string name="reset_coach_mark_tour_status">Reset all coach mark tours</string>
<string name="reset_accessibility_disclaimer">Reset accessibility disclaimer</string>
<string name="generate_crash">Generate crash</string>
<string name="generate_error_report">Generate error report</string>
<string name="error_reports">Error reports</string>
Expand Down
Loading