diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f8853bb84..4e00ab9a9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -33,6 +33,11 @@
android:launchMode="@integer/launchModeAPIlevel"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize">
+
+
+
diff --git a/app/src/main/java/com/x8bit/bitwarden/MainViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/MainViewModel.kt
index b3382fac7..726246697 100644
--- a/app/src/main/java/com/x8bit/bitwarden/MainViewModel.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/MainViewModel.kt
@@ -15,6 +15,8 @@ import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
+import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
+import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -116,6 +118,8 @@ class MainViewModel @Inject constructor(
val autofillSaveItem = intent.getAutofillSaveItemOrNull()
val autofillSelectionData = intent.getAutofillSelectionDataOrNull()
val shareData = intentManager.getShareDataFromIntent(intent)
+ val hasGeneratorShortcut = intent.isPasswordGeneratorShortcut
+ val hasVaultShortcut = intent.isMyVaultShortcut
when {
passwordlessRequestData != null -> {
specialCircumstanceManager.specialCircumstance =
@@ -153,6 +157,15 @@ class MainViewModel @Inject constructor(
shouldFinishWhenComplete = isFirstIntent,
)
}
+
+ hasGeneratorShortcut -> {
+ specialCircumstanceManager.specialCircumstance =
+ SpecialCircumstance.GeneratorShortcut
+ }
+
+ hasVaultShortcut -> {
+ specialCircumstanceManager.specialCircumstance = SpecialCircumstance.VaultShortcut
+ }
}
}
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/SpecialCircumstance.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/SpecialCircumstance.kt
index 239692e01..598adf39f 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/SpecialCircumstance.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/model/SpecialCircumstance.kt
@@ -46,4 +46,16 @@ sealed class SpecialCircumstance : Parcelable {
val passwordlessRequestData: PasswordlessRequestData,
val shouldFinishWhenComplete: Boolean,
) : SpecialCircumstance()
+
+ /**
+ * The app was launched via deeplink to the generator.
+ */
+ @Parcelize
+ data object GeneratorShortcut : SpecialCircumstance()
+
+ /**
+ * The app was launched via deeplink to the vault.
+ */
+ @Parcelize
+ data object VaultShortcut : SpecialCircumstance()
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensions.kt
index 9e3ae63ff..23d1c88ce 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensions.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensions.kt
@@ -13,6 +13,8 @@ fun SpecialCircumstance.toAutofillSaveItemOrNull(): AutofillSaveItem? =
is SpecialCircumstance.AutofillSelection -> null
is SpecialCircumstance.PasswordlessRequest -> null
is SpecialCircumstance.ShareNewSend -> null
+ SpecialCircumstance.GeneratorShortcut -> null
+ SpecialCircumstance.VaultShortcut -> null
}
/**
@@ -24,4 +26,6 @@ fun SpecialCircumstance.toAutofillSelectionDataOrNull(): AutofillSelectionData?
is SpecialCircumstance.AutofillSelection -> this.autofillSelectionData
is SpecialCircumstance.PasswordlessRequest -> null
is SpecialCircumstance.ShareNewSend -> null
+ SpecialCircumstance.GeneratorShortcut -> null
+ SpecialCircumstance.VaultShortcut -> null
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt
index 8375790cc..6d30425d2 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt
@@ -59,7 +59,6 @@ class RootNavViewModel @Inject constructor(
action: RootNavAction.Internal.UserStateUpdateReceive,
) {
val userState = action.userState
- val specialCircumstance = action.specialCircumstance
val updatedRootNavState = when {
userState?.activeAccount?.trustedDevice?.isDeviceTrusted == false &&
!userState.activeAccount.isVaultUnlocked -> RootNavState.TrustedDevice
@@ -73,7 +72,7 @@ class RootNavViewModel @Inject constructor(
userState.hasPendingAccountAddition -> RootNavState.Auth
userState.activeAccount.isVaultUnlocked -> {
- when (specialCircumstance) {
+ when (val specialCircumstance = action.specialCircumstance) {
is SpecialCircumstance.AutofillSave -> {
RootNavState.VaultUnlockedForAutofillSave(
autofillSaveItem = specialCircumstance.autofillSaveItem,
@@ -93,11 +92,10 @@ class RootNavViewModel @Inject constructor(
RootNavState.VaultUnlockedForAuthRequest
}
- null -> {
- RootNavState.VaultUnlocked(
- activeUserId = userState.activeAccount.userId,
- )
- }
+ SpecialCircumstance.GeneratorShortcut,
+ SpecialCircumstance.VaultShortcut,
+ null,
+ -> RootNavState.VaultUnlocked(activeUserId = userState.activeAccount.userId)
}
}
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModel.kt
index 30af28e34..b95b2f177 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModel.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModel.kt
@@ -1,6 +1,8 @@
package com.x8bit.bitwarden.ui.platform.feature.vaultunlockednavbar
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
+import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
+import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@@ -11,10 +13,25 @@ import javax.inject.Inject
@HiltViewModel
class VaultUnlockedNavBarViewModel @Inject constructor(
private val authRepository: AuthRepository,
-) :
- BaseViewModel(
- initialState = Unit,
- ) {
+ specialCircumstancesManager: SpecialCircumstanceManager,
+) : BaseViewModel(
+ initialState = Unit,
+) {
+ init {
+ when (specialCircumstancesManager.specialCircumstance) {
+ SpecialCircumstance.GeneratorShortcut -> {
+ sendEvent(VaultUnlockedNavBarEvent.NavigateToGeneratorScreen)
+ specialCircumstancesManager.specialCircumstance = null
+ }
+
+ SpecialCircumstance.VaultShortcut -> {
+ sendEvent(VaultUnlockedNavBarEvent.NavigateToVaultScreen)
+ specialCircumstancesManager.specialCircumstance = null
+ }
+
+ else -> Unit
+ }
+ }
override fun handleAction(action: VaultUnlockedNavBarAction) {
when (action) {
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/util/ShortcutUtils.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/util/ShortcutUtils.kt
new file mode 100644
index 000000000..d55f35379
--- /dev/null
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/util/ShortcutUtils.kt
@@ -0,0 +1,15 @@
+package com.x8bit.bitwarden.ui.platform.util
+
+import android.content.Intent
+
+/**
+ * Returns `true` if the [Intent] is a deeplink to the vault, `false` otherwise.
+ */
+val Intent.isMyVaultShortcut: Boolean
+ get() = dataString?.equals("bitwarden://my_vault") == true
+
+/**
+ * Returns `true` if the [Intent] is a deeplink to the password generator, `false` otherwise.
+ */
+val Intent.isPasswordGeneratorShortcut: Boolean
+ get() = dataString?.equals("bitwarden://password_generator") == true
diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml
new file mode 100644
index 000000000..ebca17b34
--- /dev/null
+++ b/app/src/main/res/xml/shortcuts.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/release/res/xml/shortcuts.xml b/app/src/release/res/xml/shortcuts.xml
new file mode 100644
index 000000000..ffd41be48
--- /dev/null
+++ b/app/src/release/res/xml/shortcuts.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/com/x8bit/bitwarden/MainViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/MainViewModelTest.kt
index 7e65c1f2c..3ac891285 100644
--- a/app/src/test/java/com/x8bit/bitwarden/MainViewModelTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/MainViewModelTest.kt
@@ -18,6 +18,8 @@ import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
+import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
+import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
@@ -54,6 +56,10 @@ class MainViewModelTest : BaseViewModelTest() {
Intent::getAutofillSaveItemOrNull,
Intent::getAutofillSelectionDataOrNull,
)
+ mockkStatic(
+ Intent::isMyVaultShortcut,
+ Intent::isPasswordGeneratorShortcut,
+ )
}
@AfterEach
@@ -63,6 +69,10 @@ class MainViewModelTest : BaseViewModelTest() {
Intent::getAutofillSaveItemOrNull,
Intent::getAutofillSelectionDataOrNull,
)
+ unmockkStatic(
+ Intent::isMyVaultShortcut,
+ Intent::isPasswordGeneratorShortcut,
+ )
}
@Suppress("MaxLineLength")
@@ -150,6 +160,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns null
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveFirstIntent(
@@ -175,6 +187,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns null
every { mockIntent.getAutofillSelectionDataOrNull() } returns autofillSelectionData
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveFirstIntent(
@@ -200,6 +214,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns autofillSaveItem
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveFirstIntent(
@@ -226,6 +242,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns null
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveFirstIntent(
@@ -251,6 +269,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns null
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveNewIntent(
@@ -276,6 +296,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns null
every { mockIntent.getAutofillSelectionDataOrNull() } returns autofillSelectionData
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveNewIntent(
@@ -301,6 +323,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns autofillSaveItem
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveNewIntent(
@@ -327,6 +351,8 @@ class MainViewModelTest : BaseViewModelTest() {
every { mockIntent.getAutofillSaveItemOrNull() } returns null
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+ every { mockIntent.isMyVaultShortcut } returns false
+ every { mockIntent.isPasswordGeneratorShortcut } returns false
viewModel.trySendAction(
MainAction.ReceiveNewIntent(
@@ -342,6 +368,54 @@ class MainViewModelTest : BaseViewModelTest() {
)
}
+ @Suppress("MaxLineLength")
+ @Test
+ fun `on ReceiveNewIntent with a Vault deeplink data should set the special circumstance to VaultShortcut`() {
+ val viewModel = createViewModel()
+ val mockIntent = mockk {
+ every { getPasswordlessRequestDataIntentOrNull() } returns null
+ every { getAutofillSaveItemOrNull() } returns null
+ every { getAutofillSelectionDataOrNull() } returns null
+ every { isMyVaultShortcut } returns true
+ every { isPasswordGeneratorShortcut } returns false
+ }
+ every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+
+ viewModel.trySendAction(
+ MainAction.ReceiveNewIntent(
+ intent = mockIntent,
+ ),
+ )
+ assertEquals(
+ SpecialCircumstance.VaultShortcut,
+ specialCircumstanceManager.specialCircumstance,
+ )
+ }
+
+ @Suppress("MaxLineLength")
+ @Test
+ fun `on ReceiveNewIntent with a password generator deeplink data should set the special circumstance to GeneratorShortcut`() {
+ val viewModel = createViewModel()
+ val mockIntent = mockk {
+ every { getPasswordlessRequestDataIntentOrNull() } returns null
+ every { getAutofillSaveItemOrNull() } returns null
+ every { getAutofillSelectionDataOrNull() } returns null
+ every { isMyVaultShortcut } returns false
+ every { isPasswordGeneratorShortcut } returns true
+ }
+ every { intentManager.getShareDataFromIntent(mockIntent) } returns null
+
+ viewModel.trySendAction(
+ MainAction.ReceiveNewIntent(
+ intent = mockIntent,
+ ),
+ )
+ assertEquals(
+ SpecialCircumstance.GeneratorShortcut,
+ specialCircumstanceManager.specialCircumstance,
+ )
+ }
+
@Suppress("MaxLineLength")
@Test
fun `changes in the allowed screen capture value should result in emissions of ScreenCaptureSettingChange `() =
diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensionsTest.kt
index 31128dc12..ea22194d2 100644
--- a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensionsTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/util/SpecialCircumstanceExtensionsTest.kt
@@ -34,6 +34,12 @@ class SpecialCircumstanceExtensionsTest {
data = mockk(),
shouldFinishWhenComplete = true,
),
+ SpecialCircumstance.PasswordlessRequest(
+ passwordlessRequestData = mockk(),
+ shouldFinishWhenComplete = true,
+ ),
+ SpecialCircumstance.GeneratorShortcut,
+ SpecialCircumstance.VaultShortcut,
)
.forEach { specialCircumstance ->
assertNull(specialCircumstance.toAutofillSaveItemOrNull())
@@ -67,6 +73,12 @@ class SpecialCircumstanceExtensionsTest {
data = mockk(),
shouldFinishWhenComplete = true,
),
+ SpecialCircumstance.PasswordlessRequest(
+ passwordlessRequestData = mockk(),
+ shouldFinishWhenComplete = true,
+ ),
+ SpecialCircumstance.GeneratorShortcut,
+ SpecialCircumstance.VaultShortcut,
)
.forEach { specialCircumstance ->
assertNull(specialCircumstance.toAutofillSelectionDataOrNull())
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModelTest.kt
index c6657b5d4..df9866b05 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModelTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarViewModelTest.kt
@@ -2,6 +2,8 @@ package com.x8bit.bitwarden.ui.platform.feature.vaultunlockednavbar
import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
+import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
+import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
import io.mockk.every
import io.mockk.just
@@ -16,6 +18,65 @@ class VaultUnlockedNavBarViewModelTest : BaseViewModelTest() {
private val authRepository: AuthRepository = mockk {
every { updateLastActiveTime() } just runs
}
+ private val specialCircumstancesManager: SpecialCircumstanceManager = mockk {
+ every { specialCircumstance = null } just runs
+ every { specialCircumstance } returns null
+ }
+
+ @Suppress("MaxLineLength")
+ @Test
+ fun `on init with GeneratorShortcut special circumstance should navigate to the generator screen`() =
+ runTest {
+ every {
+ specialCircumstancesManager.specialCircumstance
+ } returns SpecialCircumstance.GeneratorShortcut
+
+ val viewModel = createViewModel()
+
+ viewModel.eventFlow.test {
+ assertEquals(VaultUnlockedNavBarEvent.NavigateToGeneratorScreen, awaitItem())
+ }
+ verify(exactly = 1) {
+ specialCircumstancesManager.specialCircumstance
+ specialCircumstancesManager.specialCircumstance = null
+ }
+ }
+
+ @Suppress("MaxLineLength")
+ @Test
+ fun `on init with VaultShortcut special circumstance should navigate to the generator screen`() =
+ runTest {
+ every {
+ specialCircumstancesManager.specialCircumstance
+ } returns SpecialCircumstance.VaultShortcut
+
+ val viewModel = createViewModel()
+
+ viewModel.eventFlow.test {
+ assertEquals(VaultUnlockedNavBarEvent.NavigateToVaultScreen, awaitItem())
+ }
+ verify(exactly = 1) {
+ specialCircumstancesManager.specialCircumstance
+ specialCircumstancesManager.specialCircumstance = null
+ }
+ }
+
+ @Test
+ fun `on init with no shortcut special circumstance should do nothing`() = runTest {
+ every { specialCircumstancesManager.specialCircumstance } returns null
+
+ val viewModel = createViewModel()
+
+ viewModel.eventFlow.test {
+ expectNoEvents()
+ }
+ verify(exactly = 1) {
+ specialCircumstancesManager.specialCircumstance
+ }
+ verify(exactly = 0) {
+ specialCircumstancesManager.specialCircumstance = null
+ }
+ }
@Test
fun `VaultTabClick should navigate to the vault screen`() = runTest {
@@ -63,5 +124,6 @@ class VaultUnlockedNavBarViewModelTest : BaseViewModelTest() {
private fun createViewModel() =
VaultUnlockedNavBarViewModel(
authRepository = authRepository,
+ specialCircumstancesManager = specialCircumstancesManager,
)
}
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/util/ShortcutUtilsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/util/ShortcutUtilsTest.kt
new file mode 100644
index 000000000..df8c0c643
--- /dev/null
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/util/ShortcutUtilsTest.kt
@@ -0,0 +1,59 @@
+package com.x8bit.bitwarden.ui.platform.util
+
+import android.content.Intent
+import io.mockk.every
+import io.mockk.mockk
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+
+class ShortcutUtilsTest {
+ @Test
+ fun `isMyVaultShortcut should return true when dataString is my vault deeplink`() {
+ val mockIntent = mockk {
+ every { dataString } returns "bitwarden://my_vault"
+ }
+ assertTrue(mockIntent.isMyVaultShortcut)
+ }
+
+ @Test
+ fun `isMyVaultShortcut should return false when dataString is not my vault deeplink`() {
+ val mockIntent = mockk {
+ every { dataString } returns "bitwarden://some_other_vault"
+ }
+ assertFalse(mockIntent.isMyVaultShortcut)
+ }
+
+ @Test
+ fun `isMyVaultShortcut should return false when dataString is null`() {
+ val mockIntent = mockk {
+ every { dataString } returns null
+ }
+ assertFalse(mockIntent.isMyVaultShortcut)
+ }
+
+ @Test
+ fun `isPasswordGeneratorShortcut should return true when dataString is my vault deeplink`() {
+ val mockIntent = mockk {
+ every { dataString } returns "bitwarden://password_generator"
+ }
+ assertTrue(mockIntent.isPasswordGeneratorShortcut)
+ }
+
+ @Suppress("MaxLineLength")
+ @Test
+ fun `isPasswordGeneratorShortcut should return false when dataString is not my vault deeplink`() {
+ val mockIntent = mockk {
+ every { dataString } returns "bitwarden://some_other_generator"
+ }
+ assertFalse(mockIntent.isPasswordGeneratorShortcut)
+ }
+
+ @Test
+ fun `isPasswordGeneratorShortcut should return false when dataString is null`() {
+ val mockIntent = mockk {
+ every { dataString } returns null
+ }
+ assertFalse(mockIntent.isPasswordGeneratorShortcut)
+ }
+}