Closes #1170: Allow user to add a new site exception to site permissions
This commit is contained in:
parent
36e9939d9e
commit
22eba72f8f
|
@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- #1238 - Added the ability to edit bookmark folders
|
- #1238 - Added the ability to edit bookmark folders
|
||||||
- #1239 - Added the ability to move bookmark folders
|
- #1239 - Added the ability to move bookmark folders
|
||||||
- #1068 - Adds the ability to quickly copy the URL by long clicking the URLBar
|
- #1068 - Adds the ability to quickly copy the URL by long clicking the URLBar
|
||||||
|
- #1170: Allow user to add a new site exception to site permissions
|
||||||
### Changed
|
### Changed
|
||||||
- #1429 - Updated site permissions ui for MVP
|
- #1429 - Updated site permissions ui for MVP
|
||||||
### Removed
|
### Removed
|
|
@ -25,8 +25,10 @@ import kotlinx.android.synthetic.main.component_search.*
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
||||||
import kotlinx.android.synthetic.main.fragment_search.*
|
import kotlinx.android.synthetic.main.fragment_search.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
|
@ -39,12 +41,14 @@ import mozilla.components.feature.session.FullScreenFeature
|
||||||
import mozilla.components.feature.session.SessionFeature
|
import mozilla.components.feature.session.SessionFeature
|
||||||
import mozilla.components.feature.session.SessionUseCases
|
import mozilla.components.feature.session.SessionUseCases
|
||||||
import mozilla.components.feature.session.ThumbnailsFeature
|
import mozilla.components.feature.session.ThumbnailsFeature
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsFeature
|
import mozilla.components.feature.sitepermissions.SitePermissionsFeature
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||||
import mozilla.components.support.base.feature.BackHandler
|
import mozilla.components.support.base.feature.BackHandler
|
||||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||||
import mozilla.components.support.ktx.android.view.enterToImmersiveMode
|
import mozilla.components.support.ktx.android.view.enterToImmersiveMode
|
||||||
import mozilla.components.support.ktx.android.view.exitImmersiveModeIfNeeded
|
import mozilla.components.support.ktx.android.view.exitImmersiveModeIfNeeded
|
||||||
|
import mozilla.components.support.ktx.kotlin.toUri
|
||||||
import org.mozilla.fenix.BrowsingModeManager
|
import org.mozilla.fenix.BrowsingModeManager
|
||||||
import org.mozilla.fenix.DefaultThemeManager
|
import org.mozilla.fenix.DefaultThemeManager
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
@ -73,9 +77,10 @@ import org.mozilla.fenix.quickactionsheet.QuickActionComponent
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
||||||
class BrowserFragment : Fragment(), BackHandler {
|
class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
|
||||||
private lateinit var toolbarComponent: ToolbarComponent
|
private lateinit var toolbarComponent: ToolbarComponent
|
||||||
|
|
||||||
private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
|
private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
|
||||||
|
@ -88,9 +93,17 @@ class BrowserFragment : Fragment(), BackHandler {
|
||||||
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
|
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
|
||||||
private val thumbnailsFeature = ViewBoundFeatureWrapper<ThumbnailsFeature>()
|
private val thumbnailsFeature = ViewBoundFeatureWrapper<ThumbnailsFeature>()
|
||||||
private val customTabsIntegration = ViewBoundFeatureWrapper<CustomTabsIntegration>()
|
private val customTabsIntegration = ViewBoundFeatureWrapper<CustomTabsIntegration>()
|
||||||
|
private lateinit var job: Job
|
||||||
|
|
||||||
var sessionId: String? = null
|
var sessionId: String? = null
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
job = Job()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
@ -263,13 +276,7 @@ class BrowserFragment : Fragment(), BackHandler {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
toolbarComponent.getView().setOnSiteSecurityClickedListener {
|
toolbarComponent.getView().setOnSiteSecurityClickedListener {
|
||||||
val session = getSessionByIdOrUseSelectedSession()
|
showQuickSettingsDialog()
|
||||||
val quickSettingsSheet = QuickSettingsSheetDialogFragment.newInstance(
|
|
||||||
url = session.url,
|
|
||||||
isSecured = session.securityInfo.secure,
|
|
||||||
isSiteInExceptionList = false
|
|
||||||
)
|
|
||||||
quickSettingsSheet.show(requireFragmentManager(), QuickSettingsSheetDialogFragment.FRAGMENT_TAG)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +395,11 @@ class BrowserFragment : Fragment(), BackHandler {
|
||||||
promptsFeature.withFeature { it.onActivityResult(requestCode, resultCode, data) }
|
promptsFeature.withFeature { it.onActivityResult(requestCode, resultCode, data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
// This method triggers the complexity warning. However it's actually not that hard to understand.
|
// This method triggers the complexity warning. However it's actually not that hard to understand.
|
||||||
@SuppressWarnings("ComplexMethod")
|
@SuppressWarnings("ComplexMethod")
|
||||||
private fun trackToolbarItemInteraction(action: SearchAction.ToolbarMenuItemTapped) {
|
private fun trackToolbarItemInteraction(action: SearchAction.ToolbarMenuItemTapped) {
|
||||||
|
@ -472,6 +484,26 @@ class BrowserFragment : Fragment(), BackHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showQuickSettingsDialog() {
|
||||||
|
val session = getSessionByIdOrUseSelectedSession()
|
||||||
|
val host = requireNotNull(session.url.toUri().host)
|
||||||
|
|
||||||
|
launch {
|
||||||
|
val storage = requireContext().components.storage
|
||||||
|
val sitePermissions: SitePermissions? = storage.findSitePermissionsBy(host)
|
||||||
|
|
||||||
|
launch(Main) {
|
||||||
|
val quickSettingsSheet = QuickSettingsSheetDialogFragment.newInstance(
|
||||||
|
url = session.url,
|
||||||
|
isSecured = session.securityInfo.secure,
|
||||||
|
sitePermissions = sitePermissions
|
||||||
|
)
|
||||||
|
quickSettingsSheet.sitePermissions = sitePermissions
|
||||||
|
quickSettingsSheet.show(requireFragmentManager(), QuickSettingsSheetDialogFragment.FRAGMENT_TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getSessionByIdOrUseSelectedSession(): Session {
|
private fun getSessionByIdOrUseSelectedSession(): Session {
|
||||||
return if (sessionId != null) {
|
return if (sessionId != null) {
|
||||||
requireNotNull(requireContext().components.core.sessionManager.findSessionById(requireNotNull(sessionId)))
|
requireNotNull(requireContext().components.core.sessionManager.findSessionById(requireNotNull(sessionId)))
|
||||||
|
|
|
@ -17,4 +17,5 @@ class Components(private val context: Context) {
|
||||||
val useCases by lazy { UseCases(context, core.sessionManager, search.searchEngineManager) }
|
val useCases by lazy { UseCases(context, core.sessionManager, search.searchEngineManager) }
|
||||||
val utils by lazy { Utilities(context, core.sessionManager, useCases.sessionUseCases, useCases.searchUseCases) }
|
val utils by lazy { Utilities(context, core.sessionManager, useCases.sessionUseCases, useCases.searchUseCases) }
|
||||||
val analytics by lazy { Analytics(context) }
|
val analytics by lazy { Analytics(context) }
|
||||||
|
val storage by lazy { Storage(context) }
|
||||||
}
|
}
|
||||||
|
|
44
app/src/main/java/org/mozilla/fenix/components/Storage.kt
Normal file
44
app/src/main/java/org/mozilla/fenix/components/Storage.kt
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions.Status
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissionsStorage
|
||||||
|
|
||||||
|
class Storage(private val context: Context) {
|
||||||
|
|
||||||
|
private val permissionsStorage by lazy {
|
||||||
|
SitePermissionsStorage(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addSitePermissionException(
|
||||||
|
origin: String,
|
||||||
|
location: Status,
|
||||||
|
notification: Status,
|
||||||
|
microphone: Status,
|
||||||
|
camera: Status
|
||||||
|
): SitePermissions {
|
||||||
|
val sitePermissions = SitePermissions(
|
||||||
|
origin = origin,
|
||||||
|
location = location,
|
||||||
|
camera = camera,
|
||||||
|
microphone = microphone,
|
||||||
|
notification = notification,
|
||||||
|
savedAt = System.currentTimeMillis()
|
||||||
|
)
|
||||||
|
permissionsStorage.save(sitePermissions)
|
||||||
|
return sitePermissions
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findSitePermissionsBy(origin: String): SitePermissions? {
|
||||||
|
return permissionsStorage.findSitePermissionsBy(origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateSitePermissions(sitePermissions: SitePermissions) {
|
||||||
|
permissionsStorage.update(sitePermissions)
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ internal fun SitePermissionsRules.Action.toString(context: Context): String {
|
||||||
context.getString(R.string.preference_option_phone_feature_ask_to_allow)
|
context.getString(R.string.preference_option_phone_feature_ask_to_allow)
|
||||||
}
|
}
|
||||||
SitePermissionsRules.Action.BLOCKED -> {
|
SitePermissionsRules.Action.BLOCKED -> {
|
||||||
context.getString(R.string.preference_option_phone_feature_block)
|
context.getString(R.string.preference_option_phone_feature_blocked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,53 @@ internal fun SitePermissionsRules.Action.toString(context: Context): String {
|
||||||
internal fun SitePermissions.Status.toString(context: Context): String {
|
internal fun SitePermissions.Status.toString(context: Context): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
SitePermissions.Status.BLOCKED -> {
|
SitePermissions.Status.BLOCKED -> {
|
||||||
context.getString(R.string.preference_option_phone_feature_block)
|
context.getString(R.string.preference_option_phone_feature_blocked)
|
||||||
}
|
}
|
||||||
SitePermissions.Status.NO_DECISION -> {
|
SitePermissions.Status.NO_DECISION -> {
|
||||||
context.getString(R.string.preference_option_phone_feature_ask_to_allow)
|
context.getString(R.string.preference_option_phone_feature_ask_to_allow)
|
||||||
}
|
}
|
||||||
SitePermissions.Status.ALLOWED -> {
|
SitePermissions.Status.ALLOWED -> {
|
||||||
context.getString(R.string.phone_feature_no_decision)
|
context.getString(R.string.preference_option_phone_feature_allowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SitePermissionsRules.Action.toStatus(): SitePermissions.Status {
|
||||||
|
return when (this) {
|
||||||
|
SitePermissionsRules.Action.BLOCKED -> SitePermissions.Status.BLOCKED
|
||||||
|
SitePermissionsRules.Action.ASK_TO_ALLOW -> SitePermissions.Status.NO_DECISION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SitePermissions.Status.toggle(): SitePermissions.Status {
|
||||||
|
return when (this) {
|
||||||
|
SitePermissions.Status.BLOCKED -> SitePermissions.Status.ALLOWED
|
||||||
|
SitePermissions.Status.NO_DECISION -> SitePermissions.Status.ALLOWED
|
||||||
|
SitePermissions.Status.ALLOWED -> SitePermissions.Status.BLOCKED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SitePermissions.toggle(featurePhone: PhoneFeature): SitePermissions {
|
||||||
|
return when (featurePhone) {
|
||||||
|
PhoneFeature.CAMERA -> {
|
||||||
|
copy(
|
||||||
|
camera = camera.toggle()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PhoneFeature.LOCATION -> {
|
||||||
|
copy(
|
||||||
|
location = location.toggle()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PhoneFeature.MICROPHONE -> {
|
||||||
|
copy(
|
||||||
|
microphone = microphone.toggle()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PhoneFeature.NOTIFICATION -> {
|
||||||
|
copy(
|
||||||
|
notification = notification.toggle()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,31 @@ enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getStatus(sitePermissions: SitePermissions? = null, settings: Settings): SitePermissions.Status {
|
||||||
|
return when (this) {
|
||||||
|
CAMERA -> {
|
||||||
|
sitePermissions?.camera ?: settings
|
||||||
|
.getSitePermissionsPhoneFeatureCameraAction()
|
||||||
|
.toStatus()
|
||||||
|
}
|
||||||
|
LOCATION -> {
|
||||||
|
sitePermissions?.location ?: settings
|
||||||
|
.getSitePermissionsPhoneFeatureLocation()
|
||||||
|
.toStatus()
|
||||||
|
}
|
||||||
|
MICROPHONE -> {
|
||||||
|
sitePermissions?.microphone ?: settings
|
||||||
|
.getSitePermissionsPhoneFeatureMicrophoneAction()
|
||||||
|
.toStatus()
|
||||||
|
}
|
||||||
|
NOTIFICATION -> {
|
||||||
|
sitePermissions?.notification ?: settings
|
||||||
|
.getSitePermissionsPhoneFeatureNotificationAction()
|
||||||
|
.toStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun findFeatureBy(permissions: Array<out String>): PhoneFeature? {
|
fun findFeatureBy(permissions: Array<out String>): PhoneFeature? {
|
||||||
return PhoneFeature.values().find { feature ->
|
return PhoneFeature.values().find { feature ->
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.settings.quicksettings
|
package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
|
import mozilla.components.support.ktx.kotlin.toUri
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.mvi.Action
|
import org.mozilla.fenix.mvi.Action
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
import org.mozilla.fenix.mvi.Change
|
import org.mozilla.fenix.mvi.Change
|
||||||
|
@ -12,6 +16,9 @@ import org.mozilla.fenix.mvi.UIComponent
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
import org.mozilla.fenix.mvi.ViewState
|
import org.mozilla.fenix.mvi.ViewState
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
import org.mozilla.fenix.settings.toStatus
|
||||||
|
import org.mozilla.fenix.settings.toggle
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
class QuickSettingsComponent(
|
class QuickSettingsComponent(
|
||||||
private val container: ViewGroup,
|
private val container: ViewGroup,
|
||||||
|
@ -28,18 +35,23 @@ class QuickSettingsComponent(
|
||||||
mode = QuickSettingsState.Mode.Normal(
|
mode = QuickSettingsState.Mode.Normal(
|
||||||
change.url,
|
change.url,
|
||||||
change.isSecured,
|
change.isSecured,
|
||||||
change.isSiteInExceptionList
|
change.sitePermissions
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is QuickSettingsChange.PermissionGranted -> {
|
is QuickSettingsChange.PermissionGranted -> {
|
||||||
state.copy(
|
state.copy(
|
||||||
mode = QuickSettingsState.Mode.ActionLabelUpdated(change.phoneFeature)
|
mode = QuickSettingsState.Mode.ActionLabelUpdated(change.phoneFeature, change.sitePermissions)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
QuickSettingsChange.PromptRestarted -> {
|
is QuickSettingsChange.PromptRestarted -> {
|
||||||
state.copy(
|
state.copy(
|
||||||
mode = QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid
|
mode = QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid(change.sitePermissions)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is QuickSettingsChange.Stored -> {
|
||||||
|
state.copy(
|
||||||
|
mode = QuickSettingsState.Mode.ActionLabelUpdated(change.phoneFeature, change.sitePermissions)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,28 +64,62 @@ class QuickSettingsComponent(
|
||||||
init {
|
init {
|
||||||
render(reducer)
|
render(reducer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleSitePermission(
|
||||||
|
context: Context,
|
||||||
|
featurePhone: PhoneFeature,
|
||||||
|
url: String,
|
||||||
|
sitePermissions: SitePermissions?
|
||||||
|
): SitePermissions {
|
||||||
|
|
||||||
|
return if (sitePermissions == null) {
|
||||||
|
val settings = Settings.getInstance(context)
|
||||||
|
val origin = requireNotNull(url.toUri().host)
|
||||||
|
var location = settings.getSitePermissionsPhoneFeatureLocation().toStatus()
|
||||||
|
var camera = settings.getSitePermissionsPhoneFeatureCameraAction().toStatus()
|
||||||
|
var microphone = settings.getSitePermissionsPhoneFeatureMicrophoneAction().toStatus()
|
||||||
|
var notification = settings.getSitePermissionsPhoneFeatureNotificationAction().toStatus()
|
||||||
|
|
||||||
|
when (featurePhone) {
|
||||||
|
PhoneFeature.CAMERA -> camera = camera.toggle()
|
||||||
|
PhoneFeature.LOCATION -> location = location.toggle()
|
||||||
|
PhoneFeature.MICROPHONE -> microphone = microphone.toggle()
|
||||||
|
PhoneFeature.NOTIFICATION -> notification = notification.toggle()
|
||||||
|
}
|
||||||
|
context.components.storage.addSitePermissionException(origin, location, camera, microphone, notification)
|
||||||
|
} else {
|
||||||
|
val updatedSitePermissions = sitePermissions.toggle(featurePhone)
|
||||||
|
context.components.storage.updateSitePermissions(updatedSitePermissions)
|
||||||
|
updatedSitePermissions
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class QuickSettingsState(val mode: Mode) : ViewState {
|
data class QuickSettingsState(val mode: Mode) : ViewState {
|
||||||
sealed class Mode {
|
sealed class Mode {
|
||||||
data class Normal(val url: String, val isSecured: Boolean, val isSiteInExceptionList: Boolean) : Mode()
|
data class Normal(val url: String, val isSecured: Boolean, val sitePermissions: SitePermissions?) : Mode()
|
||||||
data class ActionLabelUpdated(val phoneFeature: PhoneFeature) : Mode()
|
data class ActionLabelUpdated(val phoneFeature: PhoneFeature, val sitePermissions: SitePermissions?) :
|
||||||
object CheckPendingFeatureBlockedByAndroid : Mode()
|
Mode()
|
||||||
|
|
||||||
|
data class CheckPendingFeatureBlockedByAndroid(val sitePermissions: SitePermissions?) : Mode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class QuickSettingsAction : Action {
|
sealed class QuickSettingsAction : Action {
|
||||||
data class SelectBlockedByAndroid(val permissions: Array<String>) : QuickSettingsAction()
|
data class SelectBlockedByAndroid(val permissions: Array<String>) : QuickSettingsAction()
|
||||||
object DismissDialog : QuickSettingsAction()
|
data class TogglePermission(val featurePhone: PhoneFeature) : QuickSettingsAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class QuickSettingsChange : Change {
|
sealed class QuickSettingsChange : Change {
|
||||||
data class Change(
|
data class Change(
|
||||||
val url: String,
|
val url: String,
|
||||||
val isSecured: Boolean,
|
val isSecured: Boolean,
|
||||||
val isSiteInExceptionList: Boolean
|
val sitePermissions: SitePermissions?
|
||||||
) : QuickSettingsChange()
|
) : QuickSettingsChange()
|
||||||
|
|
||||||
data class PermissionGranted(val phoneFeature: PhoneFeature) : QuickSettingsChange()
|
data class PermissionGranted(val phoneFeature: PhoneFeature, val sitePermissions: SitePermissions?) :
|
||||||
object PromptRestarted : QuickSettingsChange()
|
QuickSettingsChange()
|
||||||
|
|
||||||
|
data class PromptRestarted(val sitePermissions: SitePermissions?) : QuickSettingsChange()
|
||||||
|
data class Stored(val phoneFeature: PhoneFeature, val sitePermissions: SitePermissions?) : QuickSettingsChange()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,24 +11,44 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
||||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
private const val KEY_URL = "KEY_URL"
|
private const val KEY_URL = "KEY_URL"
|
||||||
private const val KEY_IS_SECURED = "KEY_IS_SECURED"
|
private const val KEY_IS_SECURED = "KEY_IS_SECURED"
|
||||||
private const val KEY_IS_SITE_IN_EXCEPTION_LIST = "KEY_IS_SITE_IN_EXCEPTION_LIST"
|
private const val KEY_SITE_PERMISSIONS = "KEY_SITE_PERMISSIONS"
|
||||||
private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4
|
private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions")
|
@SuppressWarnings("TooManyFunctions")
|
||||||
class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() {
|
class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment(), CoroutineScope {
|
||||||
private val safeArguments get() = requireNotNull(arguments)
|
private val safeArguments get() = requireNotNull(arguments)
|
||||||
private val url: String by lazy { safeArguments.getString(KEY_URL) }
|
private val url: String by lazy { safeArguments.getString(KEY_URL) }
|
||||||
private val isSecured: Boolean by lazy { safeArguments.getBoolean(KEY_IS_SECURED) }
|
private val isSecured: Boolean by lazy { safeArguments.getBoolean(KEY_IS_SECURED) }
|
||||||
private val isSiteInExceptionList: Boolean by lazy { safeArguments.getBoolean(KEY_IS_SITE_IN_EXCEPTION_LIST) }
|
|
||||||
private lateinit var quickSettingsComponent: QuickSettingsComponent
|
private lateinit var quickSettingsComponent: QuickSettingsComponent
|
||||||
|
private lateinit var job: Job
|
||||||
|
|
||||||
|
var sitePermissions: SitePermissions?
|
||||||
|
get() = safeArguments.getParcelable(KEY_SITE_PERMISSIONS)
|
||||||
|
set(value) {
|
||||||
|
safeArguments.putParcelable(KEY_SITE_PERMISSIONS, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
job = Job()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_quick_settings_dialog_sheet, container, false)
|
return inflater.inflate(R.layout.fragment_quick_settings_dialog_sheet, container, false)
|
||||||
|
@ -39,7 +59,7 @@ class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() {
|
||||||
quickSettingsComponent = QuickSettingsComponent(
|
quickSettingsComponent = QuickSettingsComponent(
|
||||||
rootView as ConstraintLayout, ActionBusFactory.get(this),
|
rootView as ConstraintLayout, ActionBusFactory.get(this),
|
||||||
QuickSettingsState(
|
QuickSettingsState(
|
||||||
QuickSettingsState.Mode.Normal(url, isSecured, isSiteInExceptionList)
|
QuickSettingsState.Mode.Normal(url, isSecured, sitePermissions)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -50,7 +70,7 @@ class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() {
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
url: String,
|
url: String,
|
||||||
isSecured: Boolean,
|
isSecured: Boolean,
|
||||||
isSiteInExceptionList: Boolean
|
sitePermissions: SitePermissions?
|
||||||
): QuickSettingsSheetDialogFragment {
|
): QuickSettingsSheetDialogFragment {
|
||||||
|
|
||||||
val fragment = QuickSettingsSheetDialogFragment()
|
val fragment = QuickSettingsSheetDialogFragment()
|
||||||
|
@ -59,7 +79,7 @@ class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() {
|
||||||
with(arguments) {
|
with(arguments) {
|
||||||
putString(KEY_URL, url)
|
putString(KEY_URL, url)
|
||||||
putBoolean(KEY_IS_SECURED, isSecured)
|
putBoolean(KEY_IS_SECURED, isSecured)
|
||||||
putBoolean(KEY_IS_SITE_IN_EXCEPTION_LIST, isSiteInExceptionList)
|
putParcelable(KEY_SITE_PERMISSIONS, sitePermissions)
|
||||||
}
|
}
|
||||||
fragment.arguments = arguments
|
fragment.arguments = arguments
|
||||||
return fragment
|
return fragment
|
||||||
|
@ -70,10 +90,15 @@ class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() {
|
||||||
if (arePermissionsGranted(requestCode, grantResults)) {
|
if (arePermissionsGranted(requestCode, grantResults)) {
|
||||||
val feature = requireNotNull(PhoneFeature.findFeatureBy(permissions))
|
val feature = requireNotNull(PhoneFeature.findFeatureBy(permissions))
|
||||||
getManagedEmitter<QuickSettingsChange>()
|
getManagedEmitter<QuickSettingsChange>()
|
||||||
.onNext(QuickSettingsChange.PermissionGranted(feature))
|
.onNext(QuickSettingsChange.PermissionGranted(feature, sitePermissions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
private fun arePermissionsGranted(requestCode: Int, grantResults: IntArray) =
|
private fun arePermissionsGranted(requestCode: Int, grantResults: IntArray) =
|
||||||
requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED }
|
requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED }
|
||||||
|
|
||||||
|
@ -85,13 +110,30 @@ class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() {
|
||||||
is QuickSettingsAction.SelectBlockedByAndroid -> {
|
is QuickSettingsAction.SelectBlockedByAndroid -> {
|
||||||
requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
|
requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
|
||||||
}
|
}
|
||||||
is QuickSettingsAction.DismissDialog -> dismiss()
|
is QuickSettingsAction.TogglePermission -> {
|
||||||
|
|
||||||
|
launch {
|
||||||
|
sitePermissions = quickSettingsComponent.toggleSitePermission(
|
||||||
|
context = requireContext(),
|
||||||
|
featurePhone = it.featurePhone,
|
||||||
|
url = url,
|
||||||
|
sitePermissions = sitePermissions
|
||||||
|
)
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
getManagedEmitter<QuickSettingsChange>()
|
||||||
|
.onNext(QuickSettingsChange.Stored(it.featurePhone, sitePermissions))
|
||||||
|
|
||||||
|
requireContext().components.useCases.sessionUseCases.reload.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
getManagedEmitter<QuickSettingsChange>()
|
getManagedEmitter<QuickSettingsChange>()
|
||||||
.onNext(QuickSettingsChange.PromptRestarted)
|
.onNext(QuickSettingsChange.PromptRestarted(sitePermissions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.settings.quicksettings
|
package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
import android.util.TypedValue
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
|
@ -14,9 +15,10 @@ import androidx.core.content.ContextCompat
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions.Status.NO_DECISION
|
||||||
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
||||||
import mozilla.components.support.ktx.kotlin.toUri
|
import mozilla.components.support.ktx.kotlin.toUri
|
||||||
import org.jetbrains.anko.textColorResource
|
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
@ -24,7 +26,6 @@ import org.mozilla.fenix.settings.PhoneFeature.CAMERA
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.LOCATION
|
import org.mozilla.fenix.settings.PhoneFeature.LOCATION
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE
|
import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION
|
import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
class QuickSettingsUIView(
|
class QuickSettingsUIView(
|
||||||
|
@ -38,26 +39,28 @@ class QuickSettingsUIView(
|
||||||
private val securityInfoLabel: TextView
|
private val securityInfoLabel: TextView
|
||||||
private val urlLabel: TextView
|
private val urlLabel: TextView
|
||||||
private val cameraActionLabel: TextView
|
private val cameraActionLabel: TextView
|
||||||
|
private val cameraLabel: TextView
|
||||||
private val microphoneActionLabel: TextView
|
private val microphoneActionLabel: TextView
|
||||||
|
private val microphoneLabel: TextView
|
||||||
private val locationActionLabel: TextView
|
private val locationActionLabel: TextView
|
||||||
|
private val locationLabel: TextView
|
||||||
private val notificationActionLabel: TextView
|
private val notificationActionLabel: TextView
|
||||||
|
private val notificationLabel: TextView
|
||||||
private val blockedByAndroidPhoneFeatures = mutableListOf<PhoneFeature>()
|
private val blockedByAndroidPhoneFeatures = mutableListOf<PhoneFeature>()
|
||||||
private val context get() = view.context
|
private val context get() = view.context
|
||||||
private val settings: Settings = Settings.getInstance(context)
|
private val settings: Settings = Settings.getInstance(context)
|
||||||
|
|
||||||
private val toolbarTextColorId by lazy {
|
|
||||||
val typedValue = TypedValue()
|
|
||||||
context.theme.resolveAttribute(R.attr.toolbarTextColor, typedValue, true)
|
|
||||||
typedValue.resourceId
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
urlLabel = view.findViewById<AppCompatTextView>(R.id.url)
|
urlLabel = view.findViewById<AppCompatTextView>(R.id.url)
|
||||||
securityInfoLabel = view.findViewById<AppCompatTextView>(R.id.security_info)
|
securityInfoLabel = view.findViewById<AppCompatTextView>(R.id.security_info)
|
||||||
cameraActionLabel = view.findViewById<AppCompatTextView>(R.id.camera_action_label)
|
cameraActionLabel = view.findViewById<AppCompatTextView>(R.id.camera_action_label)
|
||||||
|
cameraLabel = view.findViewById<AppCompatTextView>(R.id.camera_icon)
|
||||||
microphoneActionLabel = view.findViewById<AppCompatTextView>(R.id.microphone_action_label)
|
microphoneActionLabel = view.findViewById<AppCompatTextView>(R.id.microphone_action_label)
|
||||||
|
microphoneLabel = view.findViewById<AppCompatTextView>(R.id.microphone_icon)
|
||||||
|
locationLabel = view.findViewById<AppCompatTextView>(R.id.location_icon)
|
||||||
locationActionLabel = view.findViewById<AppCompatTextView>(R.id.location_action_label)
|
locationActionLabel = view.findViewById<AppCompatTextView>(R.id.location_action_label)
|
||||||
notificationActionLabel = view.findViewById<AppCompatTextView>(R.id.notification_action_label)
|
notificationActionLabel = view.findViewById<AppCompatTextView>(R.id.notification_action_label)
|
||||||
|
notificationLabel = view.findViewById<AppCompatTextView>(R.id.notification_icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateView() = Consumer<QuickSettingsState> { state ->
|
override fun updateView() = Consumer<QuickSettingsState> { state ->
|
||||||
|
@ -65,20 +68,20 @@ class QuickSettingsUIView(
|
||||||
is QuickSettingsState.Mode.Normal -> {
|
is QuickSettingsState.Mode.Normal -> {
|
||||||
bindUrl(state.mode.url)
|
bindUrl(state.mode.url)
|
||||||
bindSecurityInfo(state.mode.isSecured)
|
bindSecurityInfo(state.mode.isSecured)
|
||||||
bindPhoneFeatureItem(cameraActionLabel, CAMERA)
|
bindPhoneFeatureItem(cameraActionLabel, CAMERA, state.mode.sitePermissions)
|
||||||
bindPhoneFeatureItem(microphoneActionLabel, MICROPHONE)
|
bindPhoneFeatureItem(microphoneActionLabel, MICROPHONE, state.mode.sitePermissions)
|
||||||
bindPhoneFeatureItem(notificationActionLabel, NOTIFICATION)
|
bindPhoneFeatureItem(notificationActionLabel, NOTIFICATION, state.mode.sitePermissions)
|
||||||
bindPhoneFeatureItem(locationActionLabel, LOCATION)
|
bindPhoneFeatureItem(locationActionLabel, LOCATION, state.mode.sitePermissions)
|
||||||
bindManagePermissionsButton()
|
|
||||||
}
|
}
|
||||||
is QuickSettingsState.Mode.ActionLabelUpdated -> {
|
is QuickSettingsState.Mode.ActionLabelUpdated -> {
|
||||||
bindPhoneFeatureItem(
|
bindPhoneFeatureItem(
|
||||||
state.mode.phoneFeature.actionLabel,
|
state.mode.phoneFeature.labelAndAction.second,
|
||||||
state.mode.phoneFeature
|
state.mode.phoneFeature,
|
||||||
|
state.mode.sitePermissions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid -> {
|
is QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid -> {
|
||||||
checkFeaturesBlockedByAndroid()
|
checkFeaturesBlockedByAndroid(state.mode.sitePermissions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,17 +111,41 @@ class QuickSettingsUIView(
|
||||||
securityInfoLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null)
|
securityInfoLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPhoneFeatureItem(actionLabel: TextView, phoneFeature: PhoneFeature) {
|
private fun bindPhoneFeatureItem(
|
||||||
|
actionLabel: TextView,
|
||||||
|
phoneFeature: PhoneFeature,
|
||||||
|
sitePermissions: SitePermissions? = null
|
||||||
|
) {
|
||||||
|
if (phoneFeature.shouldBeHidden(sitePermissions)) {
|
||||||
|
hide(phoneFeature)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
show(phoneFeature)
|
||||||
if (!phoneFeature.isAndroidPermissionGranted(context)) {
|
if (!phoneFeature.isAndroidPermissionGranted(context)) {
|
||||||
handleBlockedByAndroidAction(actionLabel, phoneFeature)
|
handleBlockedByAndroidAction(actionLabel, phoneFeature)
|
||||||
} else {
|
} else {
|
||||||
bindPhoneAction(actionLabel, phoneFeature)
|
bindPhoneAction(actionLabel, phoneFeature, sitePermissions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun show(phoneFeature: PhoneFeature) {
|
||||||
|
val (label, action) = phoneFeature.labelAndAction
|
||||||
|
label.visibility = VISIBLE
|
||||||
|
action.visibility = VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hide(phoneFeature: PhoneFeature) {
|
||||||
|
val (label, action) = phoneFeature.labelAndAction
|
||||||
|
label.visibility = GONE
|
||||||
|
action.visibility = GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PhoneFeature.shouldBeHidden(sitePermissions: SitePermissions?): Boolean {
|
||||||
|
return getStatus(sitePermissions, settings) == NO_DECISION
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleBlockedByAndroidAction(actionLabel: TextView, phoneFeature: PhoneFeature) {
|
private fun handleBlockedByAndroidAction(actionLabel: TextView, phoneFeature: PhoneFeature) {
|
||||||
actionLabel.setText(R.string.phone_feature_blocked_by_android)
|
actionLabel.setText(R.string.phone_feature_blocked_by_android)
|
||||||
actionLabel.setTextColor(ContextCompat.getColor(context, R.color.photonBlue50))
|
|
||||||
actionLabel.tag = phoneFeature
|
actionLabel.tag = phoneFeature
|
||||||
actionLabel.setOnClickListener {
|
actionLabel.setOnClickListener {
|
||||||
val feature = it.tag as PhoneFeature
|
val feature = it.tag as PhoneFeature
|
||||||
|
@ -131,38 +158,44 @@ class QuickSettingsUIView(
|
||||||
blockedByAndroidPhoneFeatures.add(phoneFeature)
|
blockedByAndroidPhoneFeatures.add(phoneFeature)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPhoneAction(actionLabel: TextView, phoneFeature: PhoneFeature) {
|
private fun bindPhoneAction(
|
||||||
actionLabel.text = phoneFeature.getActionLabel(context = context, settings = settings)
|
actionLabel: TextView,
|
||||||
actionLabel.textColorResource = toolbarTextColorId
|
phoneFeature: PhoneFeature,
|
||||||
actionLabel.isEnabled = false
|
sitePermissions: SitePermissions? = null
|
||||||
|
) {
|
||||||
|
actionLabel.text = phoneFeature.getActionLabel(
|
||||||
|
context = context,
|
||||||
|
sitePermissions = sitePermissions,
|
||||||
|
settings = settings
|
||||||
|
)
|
||||||
|
|
||||||
|
actionLabel.tag = phoneFeature
|
||||||
|
actionLabel.setOnClickListener {
|
||||||
|
val feature = it.tag as PhoneFeature
|
||||||
|
actionEmitter.onNext(
|
||||||
|
QuickSettingsAction.TogglePermission(feature)
|
||||||
|
)
|
||||||
|
}
|
||||||
blockedByAndroidPhoneFeatures.remove(phoneFeature)
|
blockedByAndroidPhoneFeatures.remove(phoneFeature)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindManagePermissionsButton() {
|
private fun checkFeaturesBlockedByAndroid(sitePermissions: SitePermissions?) {
|
||||||
val urlLabel = view.findViewById<TextView>(R.id.manage_site_permissions)
|
|
||||||
urlLabel.setOnClickListener {
|
|
||||||
actionEmitter.onNext(QuickSettingsAction.DismissDialog)
|
|
||||||
ItsNotBrokenSnack(context).showSnackbar(issueNumber = "1170")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkFeaturesBlockedByAndroid() {
|
|
||||||
val clonedList = blockedByAndroidPhoneFeatures.toTypedArray()
|
val clonedList = blockedByAndroidPhoneFeatures.toTypedArray()
|
||||||
clonedList.forEach { phoneFeature ->
|
clonedList.forEach { phoneFeature ->
|
||||||
if (phoneFeature.isAndroidPermissionGranted(context)) {
|
if (phoneFeature.isAndroidPermissionGranted(context)) {
|
||||||
val actionLabel = phoneFeature.actionLabel
|
val actionLabel = phoneFeature.labelAndAction.second
|
||||||
bindPhoneAction(actionLabel, phoneFeature)
|
bindPhoneAction(actionLabel, phoneFeature, sitePermissions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val PhoneFeature.actionLabel
|
private val PhoneFeature.labelAndAction
|
||||||
get(): TextView {
|
get(): Pair<TextView, TextView> {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
CAMERA -> cameraActionLabel
|
CAMERA -> cameraLabel to cameraActionLabel
|
||||||
LOCATION -> locationActionLabel
|
LOCATION -> locationLabel to locationActionLabel
|
||||||
MICROPHONE -> microphoneActionLabel
|
MICROPHONE -> microphoneLabel to microphoneActionLabel
|
||||||
NOTIFICATION -> notificationActionLabel
|
NOTIFICATION -> notificationLabel to notificationActionLabel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
android:id="@+id/block_radio"
|
android:id="@+id/block_radio"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/radio_button_preference_height"
|
android:layout_height="@dimen/radio_button_preference_height"
|
||||||
android:text="@string/preference_option_phone_feature_block"
|
android:text="@string/preference_option_phone_feature_blocked"
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
|
|
|
@ -121,16 +121,5 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/notification_action_label"/>
|
app:layout_constraintTop_toBottomOf="@id/notification_action_label"/>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manage_site_permissions"
|
|
||||||
style="@style/QuickSettingsText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="@dimen/quicksettings_item_height"
|
|
||||||
android:textColor="@color/photonBlue50"
|
|
||||||
android:background="?android:attr/selectableItemBackground"
|
|
||||||
android:text="@string/quick_settings_sheet_manage_site_permissions"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/location_icon"/>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,10 @@
|
||||||
<!-- Label that indicates that a permission must be asked always -->
|
<!-- Label that indicates that a permission must be asked always -->
|
||||||
<string name="preference_option_phone_feature_ask_to_allow">Ask to allow</string>
|
<string name="preference_option_phone_feature_ask_to_allow">Ask to allow</string>
|
||||||
<!-- Label that indicates that a permission must be blocked -->
|
<!-- Label that indicates that a permission must be blocked -->
|
||||||
<string name="preference_option_phone_feature_block">Block</string>
|
<string name="preference_option_phone_feature_blocked">Blocked</string>
|
||||||
|
<!-- Label that indicates that a permission must be allowed -->
|
||||||
|
<string name="preference_option_phone_feature_allowed">Allowed</string>
|
||||||
|
|
||||||
<!--Label that indicates a permission is by the Android OS-->
|
<!--Label that indicates a permission is by the Android OS-->
|
||||||
<string name="phone_feature_blocked_by_android">Blocked by Android</string>
|
<string name="phone_feature_blocked_by_android">Blocked by Android</string>
|
||||||
<!--Label that indicates that a user hasn't select a value for a site permission-->
|
<!--Label that indicates that a user hasn't select a value for a site permission-->
|
||||||
|
|
|
@ -252,5 +252,6 @@
|
||||||
<item name="android:paddingEnd">24dp</item>
|
<item name="android:paddingEnd">24dp</item>
|
||||||
<item name="android:gravity">end|center_vertical</item>
|
<item name="android:gravity">end|center_vertical</item>
|
||||||
<item name="android:background">?android:attr/selectableItemBackground</item>
|
<item name="android:background">?android:attr/selectableItemBackground</item>
|
||||||
|
<item name="android:textColor">@color/photonBlue50</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user