PM-9659: Do not show push notification permissions on FDroid (#3528)

This commit is contained in:
David Perez 2024-07-18 11:17:23 -05:00 committed by GitHub
parent 96324f01d7
commit 775a73fe54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 31 additions and 4 deletions

View file

@ -1,7 +1,7 @@
package com.x8bit.bitwarden.ui.vault.feature.vault package com.x8bit.bitwarden.ui.vault.feature.vault
import android.Manifest import android.Manifest
import android.os.Build import android.annotation.SuppressLint
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleIn
@ -125,7 +125,10 @@ fun VaultScreen(
} }
} }
val vaultHandlers = remember(viewModel) { VaultHandlers.create(viewModel) } val vaultHandlers = remember(viewModel) { VaultHandlers.create(viewModel) }
VaultScreenPushNotifications(permissionsManager = permissionsManager) VaultScreenPushNotifications(
hideNotificationsDialog = state.hideNotificationsDialog,
permissionsManager = permissionsManager,
)
VaultScreenScaffold( VaultScreenScaffold(
state = state, state = state,
pullToRefreshState = pullToRefreshState, pullToRefreshState = pullToRefreshState,
@ -139,14 +142,17 @@ fun VaultScreen(
*/ */
@Composable @Composable
private fun VaultScreenPushNotifications( private fun VaultScreenPushNotifications(
hideNotificationsDialog: Boolean,
permissionsManager: PermissionsManager, permissionsManager: PermissionsManager,
) { ) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return if (hideNotificationsDialog) return
val launcher = permissionsManager.getLauncher { val launcher = permissionsManager.getLauncher {
// We do not actually care what the response is, we just need // We do not actually care what the response is, we just need
// to give the user a chance to give us the permission. // to give the user a chance to give us the permission.
} }
LaunchedEffect(key1 = Unit) { LaunchedEffect(key1 = Unit) {
@SuppressLint("InlinedApi")
// We check the version code as part of the 'hideNotificationsDialog' property.
if (!permissionsManager.checkPermission(Manifest.permission.POST_NOTIFICATIONS)) { if (!permissionsManager.checkPermission(Manifest.permission.POST_NOTIFICATIONS)) {
launcher.launch(Manifest.permission.POST_NOTIFICATIONS) launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
} }

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.ui.vault.feature.vault package com.x8bit.bitwarden.ui.vault.feature.vault
import android.os.Build
import android.os.Parcelable import android.os.Parcelable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@ -15,6 +16,8 @@ import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.data.platform.repository.model.DataState import com.x8bit.bitwarden.data.platform.repository.model.DataState
import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
import com.x8bit.bitwarden.data.platform.util.isFdroid
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
import com.x8bit.bitwarden.data.vault.repository.VaultRepository import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult
@ -87,6 +90,7 @@ class VaultViewModel @Inject constructor(
isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value, isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value,
baseIconUrl = userState.activeAccount.environment.environmentUrlData.baseIconUrl, baseIconUrl = userState.activeAccount.environment.environmentUrlData.baseIconUrl,
hasMasterPassword = userState.activeAccount.hasMasterPassword, hasMasterPassword = userState.activeAccount.hasMasterPassword,
hideNotificationsDialog = isBuildVersionBelow(Build.VERSION_CODES.TIRAMISU) || isFdroid,
) )
}, },
) { ) {
@ -628,6 +632,7 @@ data class VaultState(
private val isPullToRefreshSettingEnabled: Boolean, private val isPullToRefreshSettingEnabled: Boolean,
val baseIconUrl: String, val baseIconUrl: String,
val isIconLoadingDisabled: Boolean, val isIconLoadingDisabled: Boolean,
val hideNotificationsDialog: Boolean,
) : Parcelable { ) : Parcelable {
/** /**

View file

@ -26,14 +26,20 @@ class FakePermissionManager : PermissionsManager {
var getMultiplePermissionsResult: Map<String, Boolean> = emptyMap() var getMultiplePermissionsResult: Map<String, Boolean> = emptyMap()
/** /**
* * The value for whether a rationale should be shown to the user. * The value for whether a rationale should be shown to the user.
*/ */
var shouldShowRequestRationale: Boolean = false var shouldShowRequestRationale: Boolean = false
/**
* Indicates that the [getLauncher] function has been called.
*/
var hasGetLauncherBeenCalled: Boolean = false
@Composable @Composable
override fun getLauncher( override fun getLauncher(
onResult: (Boolean) -> Unit, onResult: (Boolean) -> Unit,
): ManagedActivityResultLauncher<String, Boolean> { ): ManagedActivityResultLauncher<String, Boolean> {
hasGetLauncherBeenCalled = true
return mockk { return mockk {
every { launch(any()) } answers { onResult.invoke(getPermissionsResult) } every { launch(any()) } answers { onResult.invoke(getPermissionsResult) }
} }

View file

@ -1129,6 +1129,14 @@ class VaultScreenTest : BaseComposeTest() {
viewModel.trySendAction(VaultAction.TrashClick) viewModel.trySendAction(VaultAction.TrashClick)
} }
} }
@Test
fun `permissionManager is invoked for notifications based on state`() {
assertFalse(permissionsManager.hasGetLauncherBeenCalled)
mutableStateFlow.update { it.copy(hideNotificationsDialog = false) }
composeTestRule.waitForIdle()
assertTrue(permissionsManager.hasGetLauncherBeenCalled)
}
} }
private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary( private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
@ -1181,6 +1189,7 @@ private val DEFAULT_STATE: VaultState = VaultState(
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
isIconLoadingDisabled = false, isIconLoadingDisabled = false,
hasMasterPassword = true, hasMasterPassword = true,
hideNotificationsDialog = true,
) )
private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content( private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content(

View file

@ -1572,4 +1572,5 @@ private fun createMockVaultState(
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
isIconLoadingDisabled = false, isIconLoadingDisabled = false,
hasMasterPassword = true, hasMasterPassword = true,
hideNotificationsDialog = true,
) )