mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-02 03:40:16 +00:00
Closes #1079: Managing site permissions exceptions
This commit is contained in:
parent
5ffaa94150
commit
c3e31a15db
@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- #176 - Added a swipe to delete gesture on home screen
|
||||
- #1539 - Added bookmarks multi-select related features
|
||||
- #1603 - Remove deprecated success path for Firefox Accounts login
|
||||
- #1079 - Managing site permissions exceptions
|
||||
|
||||
### Changed
|
||||
- #1429 - Updated site permissions ui for MVP
|
||||
|
@ -5,6 +5,7 @@
|
||||
package org.mozilla.fenix.components
|
||||
|
||||
import android.content.Context
|
||||
import androidx.paging.DataSource
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsStorage
|
||||
@ -41,4 +42,16 @@ class Storage(private val context: Context) {
|
||||
fun updateSitePermissions(sitePermissions: SitePermissions) {
|
||||
permissionsStorage.update(sitePermissions)
|
||||
}
|
||||
|
||||
fun getSitePermissionsPaged(): DataSource.Factory<Int, SitePermissions> {
|
||||
return permissionsStorage.getSitePermissionsPaged()
|
||||
}
|
||||
|
||||
fun deleteSitePermissions(sitePermissions: SitePermissions) {
|
||||
permissionsStorage.remove(sitePermissions)
|
||||
}
|
||||
|
||||
fun deleteAllSitePermissions() {
|
||||
permissionsStorage.removeAll()
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,9 @@
|
||||
package org.mozilla.fenix.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.HtmlCompat
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||
import org.mozilla.fenix.R
|
||||
@ -73,3 +76,37 @@ fun SitePermissions.toggle(featurePhone: PhoneFeature): SitePermissions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PhoneFeature.getLabel(context: Context): String {
|
||||
return when (this) {
|
||||
PhoneFeature.CAMERA -> context.getString(R.string.preference_phone_feature_camera)
|
||||
PhoneFeature.LOCATION -> context.getString(R.string.preference_phone_feature_location)
|
||||
PhoneFeature.MICROPHONE -> context.getString(R.string.preference_phone_feature_microphone)
|
||||
PhoneFeature.NOTIFICATION -> context.getString(R.string.preference_phone_feature_notification)
|
||||
}
|
||||
}
|
||||
|
||||
fun PhoneFeature.getPreferenceKey(context: Context): String {
|
||||
return when (this) {
|
||||
PhoneFeature.CAMERA -> context.getString(R.string.pref_key_phone_feature_camera)
|
||||
PhoneFeature.LOCATION -> context.getString(R.string.pref_key_phone_feature_location)
|
||||
PhoneFeature.MICROPHONE -> context.getString(R.string.pref_key_phone_feature_microphone)
|
||||
PhoneFeature.NOTIFICATION -> context.getString(R.string.pref_key_phone_feature_notification)
|
||||
}
|
||||
}
|
||||
|
||||
fun initBlockedByAndroidView(phoneFeature: PhoneFeature, blockedByAndroidView: View) {
|
||||
val context = blockedByAndroidView.context
|
||||
if (!phoneFeature.isAndroidPermissionGranted(context)) {
|
||||
blockedByAndroidView.visibility = View.VISIBLE
|
||||
|
||||
val descriptionLabel = blockedByAndroidView.findViewById<TextView>(R.id.blocked_by_android_explanation_label)
|
||||
val text = context.getString(
|
||||
R.string.phone_feature_blocked_by_android_explanation,
|
||||
phoneFeature.getLabel(context)
|
||||
)
|
||||
descriptionLabel.text = HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_COMPACT)
|
||||
} else {
|
||||
blockedByAndroidView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package org.mozilla.fenix.settings
|
||||
|
||||
import android.Manifest
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||
import android.Manifest.permission.RECORD_AUDIO
|
||||
@ -13,16 +12,17 @@ import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.support.ktx.android.content.isPermissionGranted
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
const val ID_CAMERA_PERMISSION = 0
|
||||
const val ID_LOCATION_PERMISSION = 1
|
||||
const val ID_MICROPHONE_PERMISSION = 2
|
||||
const val ID_NOTIFICATION_PERMISSION = 3
|
||||
private const val CAMERA_PERMISSION = android.Manifest.permission.CAMERA
|
||||
|
||||
enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>) {
|
||||
CAMERA(SitePermissionsManagePhoneFeature.CAMERA_PERMISSION, arrayOf(Manifest.permission.CAMERA)),
|
||||
LOCATION(
|
||||
SitePermissionsManagePhoneFeature.LOCATION_PERMISSION, arrayOf(
|
||||
ACCESS_COARSE_LOCATION,
|
||||
ACCESS_FINE_LOCATION
|
||||
)
|
||||
),
|
||||
MICROPHONE(SitePermissionsManagePhoneFeature.MICROPHONE_PERMISSION, arrayOf(RECORD_AUDIO)),
|
||||
NOTIFICATION(SitePermissionsManagePhoneFeature.NOTIFICATION_PERMISSION, emptyArray());
|
||||
CAMERA(ID_CAMERA_PERMISSION, arrayOf(CAMERA_PERMISSION)),
|
||||
LOCATION(ID_LOCATION_PERMISSION, arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)),
|
||||
MICROPHONE(ID_MICROPHONE_PERMISSION, arrayOf(RECORD_AUDIO)),
|
||||
NOTIFICATION(ID_NOTIFICATION_PERMISSION, emptyArray());
|
||||
|
||||
@Suppress("SpreadOperator")
|
||||
fun isAndroidPermissionGranted(context: Context): Boolean {
|
||||
@ -33,54 +33,56 @@ enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>)
|
||||
return context.isPermissionGranted(*permissions)
|
||||
}
|
||||
|
||||
fun getActionLabel(context: Context, sitePermissions: SitePermissions? = null, settings: Settings): String {
|
||||
return when (this) {
|
||||
fun getActionLabel(context: Context, sitePermissions: SitePermissions? = null, settings: Settings? = null): String {
|
||||
val label = when (this) {
|
||||
CAMERA -> {
|
||||
sitePermissions?.camera?.toString(context) ?: settings
|
||||
.getSitePermissionsPhoneFeatureCameraAction()
|
||||
.toString(context)
|
||||
?.getSitePermissionsPhoneFeatureCameraAction()
|
||||
?.toString(context)
|
||||
}
|
||||
LOCATION -> {
|
||||
sitePermissions?.location?.toString(context) ?: settings
|
||||
.getSitePermissionsPhoneFeatureLocation()
|
||||
.toString(context)
|
||||
?.getSitePermissionsPhoneFeatureLocation()
|
||||
?.toString(context)
|
||||
}
|
||||
MICROPHONE -> {
|
||||
sitePermissions?.microphone?.toString(context) ?: settings
|
||||
.getSitePermissionsPhoneFeatureMicrophoneAction()
|
||||
.toString(context)
|
||||
?.getSitePermissionsPhoneFeatureMicrophoneAction()
|
||||
?.toString(context)
|
||||
}
|
||||
NOTIFICATION -> {
|
||||
sitePermissions?.notification?.toString(context) ?: settings
|
||||
.getSitePermissionsPhoneFeatureNotificationAction()
|
||||
.toString(context)
|
||||
?.getSitePermissionsPhoneFeatureNotificationAction()
|
||||
?.toString(context)
|
||||
}
|
||||
}
|
||||
return requireNotNull(label)
|
||||
}
|
||||
|
||||
fun getStatus(sitePermissions: SitePermissions? = null, settings: Settings): SitePermissions.Status {
|
||||
return when (this) {
|
||||
fun getStatus(sitePermissions: SitePermissions? = null, settings: Settings? = null): SitePermissions.Status {
|
||||
val status = when (this) {
|
||||
CAMERA -> {
|
||||
sitePermissions?.camera ?: settings
|
||||
.getSitePermissionsPhoneFeatureCameraAction()
|
||||
.toStatus()
|
||||
?.getSitePermissionsPhoneFeatureCameraAction()
|
||||
?.toStatus()
|
||||
}
|
||||
LOCATION -> {
|
||||
sitePermissions?.location ?: settings
|
||||
.getSitePermissionsPhoneFeatureLocation()
|
||||
.toStatus()
|
||||
?.getSitePermissionsPhoneFeatureLocation()
|
||||
?.toStatus()
|
||||
}
|
||||
MICROPHONE -> {
|
||||
sitePermissions?.microphone ?: settings
|
||||
.getSitePermissionsPhoneFeatureMicrophoneAction()
|
||||
.toStatus()
|
||||
?.getSitePermissionsPhoneFeatureMicrophoneAction()
|
||||
?.toStatus()
|
||||
}
|
||||
NOTIFICATION -> {
|
||||
sitePermissions?.notification ?: settings
|
||||
.getSitePermissionsPhoneFeatureNotificationAction()
|
||||
.toStatus()
|
||||
?.getSitePermissionsPhoneFeatureNotificationAction()
|
||||
?.toStatus()
|
||||
}
|
||||
}
|
||||
return requireNotNull(status)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -0,0 +1,130 @@
|
||||
/* 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.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import org.jetbrains.anko.alert
|
||||
import org.jetbrains.anko.noButton
|
||||
import org.jetbrains.anko.yesButton
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.settings.PhoneFeature.CAMERA
|
||||
import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE
|
||||
import org.mozilla.fenix.settings.PhoneFeature.LOCATION
|
||||
import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
class SitePermissionsDetailsExceptionsFragment : PreferenceFragmentCompat(), CoroutineScope {
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
|
||||
private lateinit var sitePermissions: SitePermissions
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
|
||||
sitePermissions = SitePermissionsDetailsExceptionsFragmentArgs
|
||||
.fromBundle(requireArguments())
|
||||
.sitePermissions
|
||||
|
||||
(activity as AppCompatActivity).title = sitePermissions.origin
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.site_permissions_details_exceptions_preferences, rootKey)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
launch(IO) {
|
||||
val context = requireContext()
|
||||
sitePermissions = requireNotNull(context.components.storage.findSitePermissionsBy(sitePermissions.origin))
|
||||
launch(Main) {
|
||||
bindCategoryPhoneFeatures()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun bindCategoryPhoneFeatures() {
|
||||
val context = requireContext()
|
||||
|
||||
val cameraAction = CAMERA.getActionLabel(context, sitePermissions)
|
||||
val locationAction = LOCATION.getActionLabel(context, sitePermissions)
|
||||
val microphoneAction = MICROPHONE.getActionLabel(context, sitePermissions)
|
||||
val notificationAction = NOTIFICATION.getActionLabel(context, sitePermissions)
|
||||
|
||||
initPhoneFeature(CAMERA, cameraAction)
|
||||
initPhoneFeature(LOCATION, locationAction)
|
||||
initPhoneFeature(MICROPHONE, microphoneAction)
|
||||
initPhoneFeature(NOTIFICATION, notificationAction)
|
||||
bindClearPermissionsButton()
|
||||
}
|
||||
|
||||
private fun initPhoneFeature(phoneFeature: PhoneFeature, summary: String) {
|
||||
val keyPreference = phoneFeature.getPreferenceKey(requireContext())
|
||||
val cameraPhoneFeatures: Preference = requireNotNull(findPreference(keyPreference))
|
||||
cameraPhoneFeatures.summary = summary
|
||||
|
||||
cameraPhoneFeatures.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
navigateToPhoneFeature(phoneFeature)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindClearPermissionsButton() {
|
||||
val keyPreference = getString(R.string.pref_key_exceptions_clear_site_permissions)
|
||||
val button: Preference = requireNotNull(findPreference(keyPreference))
|
||||
|
||||
button.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
requireContext().alert(
|
||||
R.string.confirm_clear_permissions_site,
|
||||
R.string.clear_permissions
|
||||
) {
|
||||
yesButton {
|
||||
clearSitePermissions()
|
||||
}
|
||||
noButton { }
|
||||
}.show()
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearSitePermissions() {
|
||||
launch(IO) {
|
||||
requireContext().components.storage.deleteSitePermissions(sitePermissions)
|
||||
launch(Main) {
|
||||
Navigation.findNavController(requireNotNull(view)).popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
||||
val directions =
|
||||
SitePermissionsDetailsExceptionsFragmentDirections.actionSitePermissionsToExceptionsToManagePhoneFeature(
|
||||
phoneFeatureId = phoneFeature.id,
|
||||
sitePermissions = sitePermissions
|
||||
)
|
||||
Navigation.findNavController(view!!).navigate(directions)
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/* 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.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.paging.LivePagedListBuilder
|
||||
import androidx.paging.PagedList
|
||||
import androidx.paging.PagedListAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.BrowserIcons
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import org.jetbrains.anko.alert
|
||||
import org.jetbrains.anko.noButton
|
||||
import org.jetbrains.anko.yesButton
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
|
||||
private const val MAX_ITEMS_PER_PAGE = 50
|
||||
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
class SitePermissionsExceptionsFragment : Fragment(), View.OnClickListener, CoroutineScope {
|
||||
private lateinit var emptyContainerMessage: View
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var clearButton: Button
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_site_permissions_exceptions, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(rootView: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(rootView, savedInstanceState)
|
||||
bindEmptyContainerMess(rootView)
|
||||
bindClearButton(rootView)
|
||||
bindRecyclerView(rootView)
|
||||
}
|
||||
|
||||
private fun bindRecyclerView(rootView: View) {
|
||||
recyclerView = rootView.findViewById(R.id.exceptions)
|
||||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
|
||||
val sitePermissionsPaged = requireContext().components.storage.getSitePermissionsPaged()
|
||||
|
||||
val adapter = ExceptionsAdapter(this)
|
||||
val liveData = LivePagedListBuilder(sitePermissionsPaged, MAX_ITEMS_PER_PAGE).build()
|
||||
|
||||
liveData.observe(this, Observer<PagedList<SitePermissions>> {
|
||||
if (it.isEmpty()) {
|
||||
showEmptyListMessage()
|
||||
} else {
|
||||
hideEmptyListMessage()
|
||||
adapter.submitList(it)
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun hideEmptyListMessage() {
|
||||
emptyContainerMessage.visibility = GONE
|
||||
recyclerView.visibility = VISIBLE
|
||||
clearButton.visibility = VISIBLE
|
||||
}
|
||||
|
||||
private fun showEmptyListMessage() {
|
||||
emptyContainerMessage.visibility = VISIBLE
|
||||
recyclerView.visibility = GONE
|
||||
clearButton.visibility = GONE
|
||||
}
|
||||
|
||||
private fun bindEmptyContainerMess(rootView: View) {
|
||||
emptyContainerMessage = rootView.findViewById<View>(R.id.empty_exception_container)
|
||||
}
|
||||
|
||||
private fun bindClearButton(rootView: View) {
|
||||
clearButton = rootView.findViewById(R.id.delete_all_site_permissions_button)
|
||||
clearButton.setOnClickListener {
|
||||
requireContext().alert(
|
||||
R.string.confirm_clear_permissions_on_all_sites,
|
||||
R.string.clear_permissions
|
||||
) {
|
||||
yesButton {
|
||||
deleteAllSitePermissions()
|
||||
}
|
||||
noButton { }
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun deleteAllSitePermissions() {
|
||||
launch(IO) {
|
||||
requireContext().components.storage.deleteAllSitePermissions()
|
||||
launch(Main) {
|
||||
showEmptyListMessage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(view: View?) {
|
||||
val sitePermissions = view?.tag as SitePermissions
|
||||
val directions = SitePermissionsExceptionsFragmentDirections
|
||||
.actionSitePermissionsToExceptionsToSitePermissionsDetails(sitePermissions)
|
||||
Navigation.findNavController(requireNotNull(view)).navigate(directions)
|
||||
}
|
||||
}
|
||||
|
||||
class SitePermissionsViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
|
||||
|
||||
class ExceptionsAdapter(private val clickListener: View.OnClickListener) :
|
||||
PagedListAdapter<SitePermissions, SitePermissionsViewHolder>(diffCallback), CoroutineScope {
|
||||
private lateinit var job: Job
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView)
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SitePermissionsViewHolder {
|
||||
val context = parent.context
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val textView = inflater.inflate(R.layout.fragment_site_permissions_exceptions_item, parent, false) as TextView
|
||||
return SitePermissionsViewHolder(textView)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SitePermissionsViewHolder, position: Int) {
|
||||
val sitePermissions = requireNotNull(getItem(position))
|
||||
val context = holder.textView.context
|
||||
val client = context.components.core.client
|
||||
|
||||
launch(IO) {
|
||||
val bitmap = BrowserIcons(context, client)
|
||||
.loadIcon(IconRequest(sitePermissions.origin)).await().bitmap
|
||||
launch(Main) {
|
||||
val drawable = BitmapDrawable(context.resources, bitmap)
|
||||
holder.textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||
}
|
||||
}
|
||||
holder.textView.text = sitePermissions.origin
|
||||
holder.textView.tag = sitePermissions
|
||||
holder.textView.setOnClickListener(clickListener)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val diffCallback = object :
|
||||
DiffUtil.ItemCallback<SitePermissions>() {
|
||||
override fun areItemsTheSame(old: SitePermissions, new: SitePermissions) = old.origin == new.origin
|
||||
override fun areContentsTheSame(old: SitePermissions, new: SitePermissions) = old == new
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,18 @@ class SitePermissionsFragment : PreferenceFragmentCompat() {
|
||||
private fun setupPreferences() {
|
||||
|
||||
bindCategoryPhoneFeatures()
|
||||
bindExceptions()
|
||||
}
|
||||
|
||||
private fun bindExceptions() {
|
||||
val keyExceptions = getString(R.string.pref_key_show_site_exceptions)
|
||||
val exceptionsCategory = requireNotNull<Preference>(findPreference(keyExceptions))
|
||||
|
||||
exceptionsCategory.onPreferenceClickListener = OnPreferenceClickListener {
|
||||
val directions = SitePermissionsFragmentDirections.actionSitePermissionsToExceptions()
|
||||
Navigation.findNavController(view!!).navigate(directions)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindCategoryPhoneFeatures() {
|
||||
@ -66,7 +78,7 @@ class SitePermissionsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
|
||||
private fun initPhoneFeature(phoneFeature: PhoneFeature, summary: String) {
|
||||
val keyPreference = getPreferenceKeyBy(phoneFeature)
|
||||
val keyPreference = phoneFeature.getPreferenceKey(requireContext())
|
||||
val cameraPhoneFeatures: Preference = requireNotNull(findPreference(keyPreference))
|
||||
cameraPhoneFeatures.summary = summary
|
||||
|
||||
@ -76,15 +88,6 @@ class SitePermissionsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPreferenceKeyBy(phoneFeature: PhoneFeature): String {
|
||||
return when (phoneFeature) {
|
||||
CAMERA -> getString(R.string.pref_key_phone_feature_camera)
|
||||
LOCATION -> getString(R.string.pref_key_phone_feature_location)
|
||||
MICROPHONE -> getString(R.string.pref_key_phone_feature_microphone)
|
||||
NOTIFICATION -> getString(R.string.pref_key_phone_feature_notification)
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
||||
val directions = SitePermissionsFragmentDirections.actionSitePermissionsToManagePhoneFeatures(phoneFeature.id)
|
||||
Navigation.findNavController(view!!).navigate(directions)
|
||||
|
@ -0,0 +1,177 @@
|
||||
/* 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.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.RadioButton
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status.ALLOWED
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status.BLOCKED
|
||||
import org.jetbrains.anko.alert
|
||||
import org.jetbrains.anko.noButton
|
||||
import org.jetbrains.anko.yesButton
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment(), CoroutineScope {
|
||||
private lateinit var phoneFeature: PhoneFeature
|
||||
private lateinit var sitePermissions: SitePermissions
|
||||
private lateinit var radioAllow: RadioButton
|
||||
private lateinit var radioBlock: RadioButton
|
||||
private lateinit var blockedByAndroidView: View
|
||||
private lateinit var job: Job
|
||||
val settings by lazy { Settings.getInstance(requireContext()) }
|
||||
|
||||
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
phoneFeature = SitePermissionsManageExceptionsPhoneFeatureFragmentArgs
|
||||
.fromBundle(requireArguments())
|
||||
.phoneFeatureId.toPhoneFeature()
|
||||
|
||||
sitePermissions = SitePermissionsManageExceptionsPhoneFeatureFragmentArgs
|
||||
.fromBundle(requireArguments())
|
||||
.sitePermissions
|
||||
|
||||
(activity as AppCompatActivity).title = phoneFeature.getLabel(requireContext())
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val rootView =
|
||||
inflater.inflate(R.layout.fragment_manage_site_permissions_exceptions_feature_phone, container, false)
|
||||
|
||||
initAskToAllowRadio(rootView)
|
||||
initBlockRadio(rootView)
|
||||
bindBlockedByAndroidContainer(rootView)
|
||||
initClearPermissionsButton(rootView)
|
||||
|
||||
return rootView
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
initBlockedByAndroidView(phoneFeature, blockedByAndroidView)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun initAskToAllowRadio(rootView: View) {
|
||||
radioAllow = rootView.findViewById(R.id.ask_to_allow_radio)
|
||||
val askToAllowText = getString(R.string.preference_option_phone_feature_allowed)
|
||||
|
||||
radioAllow.text = askToAllowText
|
||||
|
||||
radioAllow.setOnClickListener {
|
||||
updatedSitePermissions(ALLOWED)
|
||||
}
|
||||
radioAllow.restoreState(ALLOWED)
|
||||
}
|
||||
|
||||
private fun RadioButton.restoreState(status: SitePermissions.Status) {
|
||||
if (phoneFeature.getStatus(sitePermissions) == status) {
|
||||
this.isChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun initBlockRadio(rootView: View) {
|
||||
radioBlock = rootView.findViewById(R.id.block_radio)
|
||||
radioBlock.setOnClickListener {
|
||||
updatedSitePermissions(BLOCKED)
|
||||
}
|
||||
radioBlock.restoreState(BLOCKED)
|
||||
}
|
||||
|
||||
private fun initClearPermissionsButton(rootView: View) {
|
||||
val button = rootView.findViewById<Button>(R.id.reset_permission)
|
||||
button.setText(R.string.clear_permission)
|
||||
button.setOnClickListener {
|
||||
|
||||
requireContext().alert(
|
||||
R.string.confirm_clear_permission_site,
|
||||
R.string.clear_permission
|
||||
) {
|
||||
yesButton {
|
||||
val defaultStatus = phoneFeature.getStatus(settings = settings)
|
||||
updatedSitePermissions(defaultStatus)
|
||||
resetRadioButtonsStatus(defaultStatus)
|
||||
}
|
||||
noButton { }
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetRadioButtonsStatus(defaultStatus: SitePermissions.Status) {
|
||||
radioAllow.isChecked = false
|
||||
radioBlock.isChecked = false
|
||||
radioAllow.restoreState(defaultStatus)
|
||||
radioBlock.restoreState(defaultStatus)
|
||||
}
|
||||
|
||||
private fun bindBlockedByAndroidContainer(rootView: View) {
|
||||
blockedByAndroidView = rootView.findViewById<View>(R.id.permissions_blocked_container)
|
||||
initSettingsButton(blockedByAndroidView)
|
||||
}
|
||||
|
||||
private fun initSettingsButton(rootView: View) {
|
||||
val button = rootView.findViewById<Button>(R.id.settings_button)
|
||||
button.setOnClickListener {
|
||||
openSettings()
|
||||
}
|
||||
}
|
||||
|
||||
private fun openSettings() {
|
||||
val intent = Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
val uri = Uri.fromParts("package", requireContext().packageName, null)
|
||||
intent.data = uri
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun Int.toPhoneFeature(): PhoneFeature {
|
||||
return requireNotNull(PhoneFeature.values().find { feature ->
|
||||
this == feature.id
|
||||
}) {
|
||||
"$this is a invalid PhoneFeature"
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatedSitePermissions(status: SitePermissions.Status) {
|
||||
val updatedSitePermissions = when (phoneFeature) {
|
||||
PhoneFeature.CAMERA -> sitePermissions.copy(camera = status)
|
||||
PhoneFeature.LOCATION -> sitePermissions.copy(location = status)
|
||||
PhoneFeature.MICROPHONE -> sitePermissions.copy(microphone = status)
|
||||
PhoneFeature.NOTIFICATION -> sitePermissions.copy(notification = status)
|
||||
}
|
||||
launch(IO) {
|
||||
requireContext().components.storage.updateSitePermissions(updatedSitePermissions)
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE
|
||||
@ -17,50 +16,48 @@ import android.text.style.AbsoluteSizeSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.RadioButton
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||
import androidx.fragment.app.Fragment
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.BLOCKED
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.BLOCKED
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
class SitePermissionsManagePhoneFeature : Fragment() {
|
||||
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||
private lateinit var phoneFeature: PhoneFeature
|
||||
private lateinit var settings: Settings
|
||||
private lateinit var blockedByAndroidView: View
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
phoneFeature = SitePermissionsManagePhoneFeatureArgs
|
||||
phoneFeature = SitePermissionsManagePhoneFeatureFragmentArgs
|
||||
.fromBundle(requireArguments())
|
||||
.permission.toPhoneFeature()
|
||||
|
||||
(activity as AppCompatActivity).title = phoneFeature.label
|
||||
(activity as AppCompatActivity).title = phoneFeature.getLabel(requireContext())
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
settings = Settings.getInstance(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val rootView = inflater.inflate(R.layout.fragment_manage_site_permissions_feature_phone, container, false)
|
||||
|
||||
initAskToAllowRadio(rootView)
|
||||
initBlockRadio(rootView)
|
||||
initBockedByAndroidContainer(rootView)
|
||||
bindBlockedByAndroidContainer(rootView)
|
||||
|
||||
return rootView
|
||||
}
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
initBlockedByAndroidView(phoneFeature, blockedByAndroidView)
|
||||
}
|
||||
|
||||
private fun initAskToAllowRadio(rootView: View) {
|
||||
val radio = rootView.findViewById<RadioButton>(R.id.ask_to_allow_radio)
|
||||
@ -108,34 +105,11 @@ class SitePermissionsManagePhoneFeature : Fragment() {
|
||||
radio.restoreState(BLOCKED)
|
||||
}
|
||||
|
||||
private fun initBockedByAndroidContainer(rootView: View) {
|
||||
if (!phoneFeature.isAndroidPermissionGranted) {
|
||||
val containerView = rootView.findViewById<View>(R.id.permissions_blocked_container)
|
||||
containerView.visibility = VISIBLE
|
||||
|
||||
val descriptionLabel = rootView.findViewById<TextView>(R.id.blocked_by_android_explanation_label)
|
||||
val text = getString(R.string.phone_feature_blocked_by_android_explanation, phoneFeature.label)
|
||||
descriptionLabel.text = HtmlCompat.fromHtml(text, FROM_HTML_MODE_COMPACT)
|
||||
|
||||
initSettingsButton(rootView)
|
||||
}
|
||||
private fun bindBlockedByAndroidContainer(rootView: View) {
|
||||
blockedByAndroidView = rootView.findViewById<View>(R.id.permissions_blocked_container)
|
||||
initSettingsButton(blockedByAndroidView)
|
||||
}
|
||||
|
||||
private val PhoneFeature.label: String
|
||||
get() {
|
||||
return when (this) {
|
||||
PhoneFeature.CAMERA -> getString(R.string.preference_phone_feature_camera)
|
||||
PhoneFeature.LOCATION -> getString(R.string.preference_phone_feature_location)
|
||||
PhoneFeature.MICROPHONE -> getString(R.string.preference_phone_feature_microphone)
|
||||
PhoneFeature.NOTIFICATION -> getString(R.string.preference_phone_feature_notification)
|
||||
}
|
||||
}
|
||||
|
||||
private val PhoneFeature.isAndroidPermissionGranted: Boolean
|
||||
get() {
|
||||
return this.isAndroidPermissionGranted(requireContext())
|
||||
}
|
||||
|
||||
private fun Int.toPhoneFeature(): PhoneFeature {
|
||||
return requireNotNull(PhoneFeature.values().find { feature ->
|
||||
this == feature.id
|
||||
@ -176,11 +150,4 @@ class SitePermissionsManagePhoneFeature : Fragment() {
|
||||
PhoneFeature.NOTIFICATION -> settings.setSitePermissionsPhoneFeatureNotificationAction(action)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CAMERA_PERMISSION = 0
|
||||
const val LOCATION_PERMISSION = 1
|
||||
const val MICROPHONE_PERMISSION = 2
|
||||
const val NOTIFICATION_PERMISSION = 3
|
||||
}
|
||||
}
|
@ -86,7 +86,7 @@ class QuickSettingsComponent(
|
||||
PhoneFeature.MICROPHONE -> microphone = microphone.toggle()
|
||||
PhoneFeature.NOTIFICATION -> notification = notification.toggle()
|
||||
}
|
||||
context.components.storage.addSitePermissionException(origin, location, camera, microphone, notification)
|
||||
context.components.storage.addSitePermissionException(origin, location, notification, microphone, camera)
|
||||
} else {
|
||||
val updatedSitePermissions = sitePermissions.toggle(featurePhone)
|
||||
context.components.storage.updateSitePermissions(updatedSitePermissions)
|
||||
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="4dp"/>
|
||||
<solid android:color="@color/photonBlue80"/>
|
||||
</shape>
|
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/permissions_blocked_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="32dp"
|
||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:text="@string/phone_feature_blocked_by_android"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/blocked_by_android_explanation_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:text="@string/phone_feature_blocked_by_android_explanation"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/SitePermissionButton"
|
||||
android:text="@string/phone_feature_go_to_settings"
|
||||
android:layout_marginTop="24dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="@dimen/radio_button_preference_vertical">
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/ask_to_allow_radio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/preference_option_phone_feature_ask_to_allow"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:button="@null"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||
android:paddingBottom="@dimen/radio_button_preference_vertical"/>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/block_radio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/radio_button_preference_height"
|
||||
android:text="@string/preference_option_phone_feature_blocked"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:button="@null"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||
android:paddingBottom="@dimen/radio_button_preference_vertical"/>
|
||||
</RadioGroup>
|
||||
|
||||
<include layout="@layout/layout_clear_permission_button"/>
|
||||
<include layout="@layout/component_permissions_blocked_by_android"/>
|
||||
|
||||
</LinearLayout>
|
@ -5,7 +5,6 @@
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
@ -46,39 +45,7 @@
|
||||
android:paddingBottom="@dimen/radio_button_preference_vertical"/>
|
||||
</RadioGroup>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/permissions_blocked_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="32dp"
|
||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
<include layout="@layout/component_permissions_blocked_by_android"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:text="@string/phone_feature_blocked_by_android"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/blocked_by_android_explanation_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:text="@string/phone_feature_blocked_by_android_explanation"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/SitePermissionButton"
|
||||
android:text="@string/phone_feature_go_to_settings"
|
||||
android:layout_marginTop="24dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/container">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/exceptions"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/delete_all_site_permissions_button"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/clear_permissions_on_all_sites"
|
||||
app:layout_constraintTop_toBottomOf="@id/exceptions"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_margin="16dp"
|
||||
style="@style/SitePermissionButton"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_exception_container"
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/toolbarTextColor"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:text="@string/no_site_exceptions"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/exception_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/site_permissions_exceptions_item_height"
|
||||
android:textSize="@dimen/site_permissions_exceptions_item_text_size"
|
||||
android:drawablePadding="16dp"
|
||||
android:drawableStart="@drawable/ic_internet"
|
||||
android:textColor="?attr/toolbarTextColor"
|
||||
android:gravity="start|center_vertical"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:background="?android:attr/selectableItemBackground"/>
|
11
app/src/main/res/layout/layout_clear_permission_button.xml
Normal file
11
app/src/main/res/layout/layout_clear_permission_button.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!-- 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/. -->
|
||||
<Button
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/reset_permission"
|
||||
android:text="@string/clear_permissions"
|
||||
android:layout_margin="16dp"
|
||||
style="@style/SitePermissionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
@ -50,13 +50,47 @@
|
||||
|
||||
<fragment
|
||||
android:id="@+id/SitePermissionsManagePhoneFeature"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsManagePhoneFeatureFragment"
|
||||
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
||||
<argument
|
||||
android:name="permission"
|
||||
app:argType="integer"/>
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/sitePermissionsExceptionsFragment"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsExceptionsFragment"
|
||||
android:label="@string/preference_exceptions"
|
||||
tools:layout="@layout/fragment_site_permissions_exceptions">
|
||||
<action
|
||||
android:id="@+id/action_site_permissions_to_exceptions_to_site_permissions_details"
|
||||
app:destination="@id/sitePermissionsDetailsExceptionsFragment"
|
||||
app:popUpTo="@+id/sitePermissionsExceptionsFragment"/>
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/sitePermissionsDetailsExceptionsFragment"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsDetailsExceptionsFragment"
|
||||
tools:layout="@xml/site_permissions_details_exceptions_preferences">
|
||||
<action
|
||||
android:id="@+id/action_site_permissions_to_exceptions_to_manage_phone_feature"
|
||||
app:destination="@id/sitePermissionsManageExceptionsPhoneFeatureFragment"
|
||||
app:popUpTo="@+id/sitePermissionsDetailsExceptionsFragment"/>
|
||||
<argument android:name="sitePermissions"
|
||||
app:argType="mozilla.components.feature.sitepermissions.SitePermissions"/>
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/sitePermissionsManageExceptionsPhoneFeatureFragment"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsManageExceptionsPhoneFeatureFragment"
|
||||
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
||||
<argument
|
||||
android:name="phoneFeatureId"
|
||||
app:argType="integer"/>
|
||||
<argument android:name="sitePermissions"
|
||||
app:argType="mozilla.components.feature.sitepermissions.SitePermissions"/>
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/browserFragment"
|
||||
android:name="org.mozilla.fenix.browser.BrowserFragment"
|
||||
@ -202,14 +236,17 @@
|
||||
<fragment android:id="@+id/dataChoicesFragment" android:name="org.mozilla.fenix.settings.DataChoicesFragment"
|
||||
android:label="DataChoicesFragment"/>
|
||||
<fragment
|
||||
android:id="@+id/sitePermissionsFragment"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsFragment"
|
||||
android:label="@string/preferences_site_permissions">
|
||||
|
||||
android:id="@+id/sitePermissionsFragment"
|
||||
android:name="org.mozilla.fenix.settings.SitePermissionsFragment"
|
||||
android:label="@string/preferences_site_permissions">
|
||||
<action
|
||||
android:id="@+id/action_site_permissions_to_manage_phone_features"
|
||||
app:destination="@id/SitePermissionsManagePhoneFeature"
|
||||
app:popUpTo="@id/sitePermissionsFragment"/>
|
||||
<action
|
||||
android:id="@+id/action_site_permissions_to_exceptions"
|
||||
app:destination="@id/sitePermissionsExceptionsFragment"
|
||||
app:popUpTo="@id/sitePermissionsFragment"/>
|
||||
</fragment>
|
||||
|
||||
<fragment android:id="@+id/accessibilityFragment" android:name="org.mozilla.fenix.settings.AccessibilityFragment"
|
||||
|
@ -27,6 +27,8 @@
|
||||
<dimen name="radio_button_preference_drawable_padding">16dp</dimen>
|
||||
<dimen name="radio_button_preference_vertical">12dp</dimen>
|
||||
<dimen name="phone_feature_label_recommended_text_size">14sp</dimen>
|
||||
<dimen name="site_permissions_exceptions_item_text_size">18sp</dimen>
|
||||
<dimen name="site_permissions_exceptions_item_height">56dp</dimen>
|
||||
|
||||
<!--Quick Settings-->
|
||||
<dimen name="quicksettings_item_height">46dp</dimen>
|
||||
|
@ -8,8 +8,6 @@
|
||||
<string name="preference_optimize">Optimize</string>
|
||||
<!-- Label summary to explain how the optimize preference works -->
|
||||
<string name="preference_optimize_summary">Lower image quality, throttle streaming bandwidth, and platform-level optimizations</string>
|
||||
<!-- Preference for showing a list of websites that the default configurations won't apply to them -->
|
||||
<string name="preference_exceptions">Exceptions</string>
|
||||
<!-- Preference for applying recommend rules to all sites -->
|
||||
<string name="preference_recommended_settings">Use recommended settings</string>
|
||||
<!-- Label summary to explain how the recommended settings work -->
|
||||
@ -25,43 +23,23 @@
|
||||
<string name="preference_custom_settings">Use custom settings</string>
|
||||
<!-- Preference category for feature phone permissions likes Camera,Microphone, Location ... etc -->
|
||||
<string name="preference_category_phone_feature">Phone Feature</string>
|
||||
<!-- Preference for altering the camera access for all websites -->
|
||||
<string name="preference_phone_feature_camera">Camera</string>
|
||||
<!-- Preference for altering the microphone access for all websites -->
|
||||
<string name="preference_phone_feature_microphone">Microphone</string>
|
||||
<!-- Preference for altering the location access for all websites -->
|
||||
<string name="preference_phone_feature_location">Location</string>
|
||||
<!-- Preference for altering the notification access for all websites -->
|
||||
<string name="preference_phone_feature_notification">Notification</string>
|
||||
<!-- Label that indicates that a permission must be asked always -->
|
||||
<string name="preference_option_phone_feature_ask_to_allow">Ask to allow</string>
|
||||
<!-- Label that indicates that a permission must be blocked -->
|
||||
<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-->
|
||||
<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-->
|
||||
<string name="phone_feature_no_decision">No Decision</string>
|
||||
<!-- Alternative explanation label that is shown when a permissions like (camera,location and microphone) is required, this indicate to the user how to enable the permission via Android settings %1$s indicate the name of the permission (camera,location and microphone) -->
|
||||
<string name="phone_feature_blocked_by_android_explanation"><![CDATA[
|
||||
To allow it: <br/><br/> 1. Go to Android Settings <br/><br/>2. Tap <b>Permissions</b> <br/><br/> 3. Toggle <b>%1$s</b> to ON
|
||||
]]></string>
|
||||
<!-- Label that indicates that this option it the recommended one -->
|
||||
<string name="phone_feature_recommended">Recommended</string>
|
||||
<!-- Button label that take the user to the Android App setting -->
|
||||
<string name="phone_feature_go_to_settings">Go to Settings</string>
|
||||
|
||||
<!-- Content description (not visible, for screen readers etc.): Quick settings sheet
|
||||
to give users access to site specific information / settings. For example:
|
||||
Secure settings status and a button to modify site permissions -->
|
||||
<string name="quick_settings_sheet">Quick settings sheet</string>
|
||||
|
||||
<!-- Label that indicates a site is using a secure connection -->
|
||||
<string name="quick_settings_sheet_secure_connection">Secure Connection</string>
|
||||
<!-- Label that indicates a site is using a insecure connection -->
|
||||
<string name="quick_settings_sheet_insecure_connection">Insecure Connection</string>
|
||||
<!-- button that allows editing site permissions settings -->
|
||||
<string name="quick_settings_sheet_manage_site_permissions">Manage site permissions</string>
|
||||
<!-- Confirmation message for a dialog confirming if the user wants to delete all the permissions for all sites-->
|
||||
<string name="confirm_clear_permissions_on_all_sites">Are you sure that you want to clear all the permissions on all sites?</string>
|
||||
<!-- Confirmation message for a dialog confirming if the user wants to delete all the permissions for a site-->
|
||||
<string name="confirm_clear_permissions_site">Are you sure that you want to clear all the permissions for this site?</string>
|
||||
<!-- Confirmation message for a dialog confirming if the user wants to set default value a permission for a site-->
|
||||
<string name="confirm_clear_permission_site">Are you sure that you want to clear this permission for this site?</string>
|
||||
<!-- label shown when there are not site exceptions to show in the site exception settings -->
|
||||
<string name="no_site_exceptions">No site exceptions</string>
|
||||
</resources>
|
@ -49,6 +49,7 @@
|
||||
<string name="pref_key_phone_feature_microphone" translatable="false">pref_key_phone_feature_microphone</string>
|
||||
<string name="pref_key_phone_feature_notification" translatable="false">pref_key_phone_feature_notification</string>
|
||||
<string name="pref_key_category_phone_feature" translatable="false">pref_key_category_phone_feature</string>
|
||||
<string name="pref_key_exceptions_clear_site_permissions" translatable="false">pref_key_exceptions_clear_site_permissions</string>
|
||||
|
||||
<!-- Theme Settings -->
|
||||
<string name="pref_key_light_theme" translatable="false">pref_key_light_theme</string>
|
||||
|
@ -336,4 +336,42 @@
|
||||
|
||||
<!-- Message for copying the URL via long press on the toolbar -->
|
||||
<string name="url_copied">URL copied</string>
|
||||
|
||||
|
||||
<!-- Site Permissions -->
|
||||
<!-- Button label that take the user to the Android App setting -->
|
||||
<string name="phone_feature_go_to_settings">Go to Settings</string>
|
||||
|
||||
<!-- Content description (not visible, for screen readers etc.): Quick settings sheet
|
||||
to give users access to site specific information / settings. For example:
|
||||
Secure settings status and a button to modify site permissions -->
|
||||
<string name="quick_settings_sheet">Quick settings sheet</string>
|
||||
<!-- Label that indicates that this option it the recommended one -->
|
||||
<string name="phone_feature_recommended">Recommended</string>
|
||||
<!-- button that allows editing site permissions settings -->
|
||||
<string name="quick_settings_sheet_manage_site_permissions">Manage site permissions</string>
|
||||
<!-- Button label for clear all the information of a site permissions-->
|
||||
<string name="clear_permissions">Clear permissions</string>
|
||||
<!-- Button label for clear a site permissions-->
|
||||
<string name="clear_permission">Clear permission</string>
|
||||
<!-- Button label for clear all the information fall all sites-->
|
||||
<string name="clear_permissions_on_all_sites">Clear permissions on all sites</string>
|
||||
<!-- Preference for altering the camera access for all websites -->
|
||||
<string name="preference_phone_feature_camera">Camera</string>
|
||||
<!-- Preference for altering the microphone access for all websites -->
|
||||
<string name="preference_phone_feature_microphone">Microphone</string>
|
||||
<!-- Preference for altering the location access for all websites -->
|
||||
<string name="preference_phone_feature_location">Location</string>
|
||||
<!-- Preference for altering the notification access for all websites -->
|
||||
<string name="preference_phone_feature_notification">Notification</string>
|
||||
<!-- Label that indicates that a permission must be asked always -->
|
||||
<string name="preference_option_phone_feature_ask_to_allow">Ask to allow</string>
|
||||
<!-- Label that indicates that a permission must be blocked -->
|
||||
<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-->
|
||||
<string name="phone_feature_blocked_by_android">Blocked by Android</string>
|
||||
<!-- Preference for showing a list of websites that the default configurations won't apply to them -->
|
||||
<string name="preference_exceptions">Exceptions</string>
|
||||
</resources>
|
||||
|
@ -186,20 +186,11 @@
|
||||
<item name="android:background">@drawable/search_pill_drawable_button_background</item>
|
||||
</style>
|
||||
|
||||
<style name="SitePermissionButton" parent="Widget.AppCompat.Button.Borderless">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<style name="SitePermissionButton" parent="Widget.AppCompat.Button">
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">@color/photonWhite</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:padding">8dp</item>
|
||||
<item name="android:textColor">?attr/toolbarTextColor</item>
|
||||
<item name="android:paddingStart">24dp</item>
|
||||
<item name="android:paddingEnd">24dp</item>
|
||||
<item name="android:foreground">?android:attr/selectableItemBackground</item>
|
||||
<item name="android:background">@drawable/site_permissions_button_background</item>
|
||||
</style>
|
||||
|
||||
<style name="CurrentSessionBottomSheetDialogTheme" parent="Theme.MaterialComponents.Light.BottomSheetDialog">
|
||||
|
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.preference.PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<androidx.preference.Preference
|
||||
android:icon="@drawable/ic_camera"
|
||||
android:key="@string/pref_key_phone_feature_camera"
|
||||
android:title="@string/preference_phone_feature_camera"
|
||||
android:summary="@string/preference_option_phone_feature_ask_to_allow"/>
|
||||
|
||||
<androidx.preference.Preference
|
||||
android:icon="@drawable/ic_location"
|
||||
android:key="@string/pref_key_phone_feature_location"
|
||||
android:title="@string/preference_phone_feature_location"
|
||||
android:summary="@string/preference_option_phone_feature_ask_to_allow"/>
|
||||
|
||||
<androidx.preference.Preference
|
||||
android:icon="@drawable/ic_microphone"
|
||||
android:key="@string/pref_key_phone_feature_microphone"
|
||||
android:title="@string/preference_phone_feature_microphone"
|
||||
android:summary="@string/preference_option_phone_feature_ask_to_allow"/>
|
||||
|
||||
<androidx.preference.Preference
|
||||
android:icon="@drawable/ic_notification"
|
||||
android:key="@string/pref_key_phone_feature_notification"
|
||||
android:title="@string/preference_phone_feature_notification"
|
||||
android:summary="@string/preference_option_phone_feature_ask_to_allow"/>
|
||||
|
||||
<androidx.preference.Preference
|
||||
android:key="@string/pref_key_exceptions_clear_site_permissions"
|
||||
android:layout="@layout/layout_clear_permission_button"/>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user