Closes #1167: Added behavior for site permissions custom settings.

This commit is contained in:
Arturo Mejia 2019-03-29 13:57:49 -04:00 committed by Colin Lee
parent 0bf8b83e03
commit 061b6f3cd5
8 changed files with 199 additions and 30 deletions

View File

@ -33,7 +33,6 @@ import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.session.ThumbnailsFeature import mozilla.components.feature.session.ThumbnailsFeature
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.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
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
@ -345,16 +344,10 @@ class BrowserFragment : Fragment(), BackHandler {
private fun assignSitePermissionsRules() { private fun assignSitePermissionsRules() {
val settings = Settings.getInstance(requireContext()) val settings = Settings.getInstance(requireContext())
val recommendedSettings = SitePermissionsRules( val rules: SitePermissionsRules = if (settings.shouldRecommendedSettingsBeActivated) {
camera = ASK_TO_ALLOW, settings.getSitePermissionsRecommendedSettingsRules()
notification = ASK_TO_ALLOW,
location = ASK_TO_ALLOW,
microphone = ASK_TO_ALLOW
)
val rules: SitePermissionsRules? = if (settings.shouldRecommendedSettingsBeActivated) {
recommendedSettings
} else { } else {
null settings.getSitePermissionsCustomSettingsRules()
} }
sitePermissionsFeature.withFeature { sitePermissionsFeature.withFeature {
it.sitePermissionsRules = rules it.sitePermissionsRules = rules

View File

@ -0,0 +1,20 @@
/* 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.Context
import mozilla.components.feature.sitepermissions.SitePermissionsRules
import org.mozilla.fenix.R
internal fun SitePermissionsRules.Action.toString(context: Context): String {
return when (this) {
SitePermissionsRules.Action.ASK_TO_ALLOW -> {
context.getString(R.string.preference_option_phone_feature_ask_to_allow)
}
SitePermissionsRules.Action.BLOCKED -> {
context.getString(R.string.preference_option_phone_feature_block)
}
}
}

View File

@ -8,9 +8,11 @@ import android.view.View
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import android.widget.TextView import android.widget.TextView
import android.content.Context import android.content.Context
import android.content.res.TypedArray
import android.text.TextUtils import android.text.TextUtils
import android.util.AttributeSet import android.util.AttributeSet
import android.widget.RadioButton import android.widget.RadioButton
import androidx.core.content.res.TypedArrayUtils
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.preference.Preference import androidx.preference.Preference
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -20,19 +22,22 @@ class RadioButtonPreference : Preference {
private lateinit var summaryView: TextView private lateinit var summaryView: TextView
private lateinit var radioButton: RadioButton private lateinit var radioButton: RadioButton
var shouldSummaryBeParsedAsHtmlContent: Boolean = true var shouldSummaryBeParsedAsHtmlContent: Boolean = true
private var defaultValue: Boolean = false
private var clickListener: (() -> Unit)? = null private var clickListener: (() -> Unit)? = null
init { init {
layoutResource = R.layout.preference_widget_radiobutton layoutResource = R.layout.preference_widget_radiobutton
} }
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
val typedArray = context.obtainStyledAttributes(
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( attrs, androidx.preference.R.styleable.Preference, TypedArrayUtils.getAttr(
context, context, androidx.preference.R.attr.preferenceStyle,
attrs, android.R.attr.preferenceStyle
defStyleAttr ), 0
) )
initDefaultValue(typedArray)
}
fun addToRadioGroup(radioPreference: RadioButtonPreference) { fun addToRadioGroup(radioPreference: RadioButtonPreference) {
radioGroups.add(radioPreference) radioGroups.add(radioPreference)
@ -67,7 +72,15 @@ class RadioButtonPreference : Preference {
private fun bindRadioButton(holder: PreferenceViewHolder) { private fun bindRadioButton(holder: PreferenceViewHolder) {
radioButton = holder.findViewById(R.id.radio_button) as RadioButton radioButton = holder.findViewById(R.id.radio_button) as RadioButton
radioButton.isChecked = getPersistedBoolean(false) radioButton.isChecked = getPersistedBoolean(defaultValue)
}
private fun initDefaultValue(typedArray: TypedArray) {
if (typedArray.hasValue(androidx.preference.R.styleable.Preference_defaultValue)) {
defaultValue = typedArray.getBoolean(androidx.preference.R.styleable.Preference_defaultValue, false)
} else if (typedArray.hasValue(androidx.preference.R.styleable.Preference_android_defaultValue)) {
defaultValue = typedArray.getBoolean(androidx.preference.R.styleable.Preference_android_defaultValue, false)
}
} }
private fun toggleRadioGroups() { private fun toggleRadioGroups() {

View File

@ -17,6 +17,7 @@ import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature
import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.LOCATION import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.LOCATION
import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.CAMERA import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.CAMERA
import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.MICROPHONE import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.MICROPHONE
import org.mozilla.fenix.utils.Settings
@SuppressWarnings("TooManyFunctions") @SuppressWarnings("TooManyFunctions")
class SitePermissionsFragment : PreferenceFragmentCompat() { class SitePermissionsFragment : PreferenceFragmentCompat() {
@ -82,15 +83,35 @@ class SitePermissionsFragment : PreferenceFragmentCompat() {
if (isCategoryActivate) { if (isCategoryActivate) {
categoryPhoneFeatures.isVisible = true categoryPhoneFeatures.isVisible = true
} }
initPhoneFeature(CAMERA)
initPhoneFeature(LOCATION) val settings = Settings.getInstance(requireContext())
initPhoneFeature(MICROPHONE)
initPhoneFeature(NOTIFICATION) val cameraAction = settings
.getSitePermissionsPhoneFeatureCameraAction()
.toString(requireContext())
val locationAction = settings
.getSitePermissionsPhoneFeatureLocation()
.toString(requireContext())
val microPhoneAction = settings
.getSitePermissionsPhoneFeatureMicrophoneAction()
.toString(requireContext())
val notificationAction = settings
.getSitePermissionsPhoneFeatureNotificationAction()
.toString(requireContext())
initPhoneFeature(CAMERA, cameraAction)
initPhoneFeature(LOCATION, locationAction)
initPhoneFeature(MICROPHONE, microPhoneAction)
initPhoneFeature(NOTIFICATION, notificationAction)
} }
private fun initPhoneFeature(phoneFeature: PhoneFeature) { private fun initPhoneFeature(phoneFeature: PhoneFeature, summary: String) {
val keyPreference = getPreferenceKeyBy(phoneFeature) val keyPreference = getPreferenceKeyBy(phoneFeature)
val cameraPhoneFeatures: Preference = requireNotNull(findPreference(keyPreference)) val cameraPhoneFeatures: Preference = requireNotNull(findPreference(keyPreference))
cameraPhoneFeatures.summary = summary
cameraPhoneFeatures.onPreferenceClickListener = OnPreferenceClickListener { cameraPhoneFeatures.onPreferenceClickListener = OnPreferenceClickListener {
navigateToPhoneFeature(phoneFeature) navigateToPhoneFeature(phoneFeature)

View File

@ -12,7 +12,8 @@ import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import org.mozilla.fenix.utils.Settings
import android.text.SpannableString import android.text.SpannableString
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE import android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE
@ -29,12 +30,16 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT
import androidx.fragment.app.Fragment 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.support.ktx.android.content.isPermissionGranted import mozilla.components.support.ktx.android.content.isPermissionGranted
import org.mozilla.fenix.R import org.mozilla.fenix.R
class SitePermissionsManagePhoneFeature : Fragment() { class SitePermissionsManagePhoneFeature : Fragment() {
private lateinit var phoneFeature: PhoneFeature private lateinit var phoneFeature: PhoneFeature
private lateinit var settings: Settings
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -45,6 +50,7 @@ class SitePermissionsManagePhoneFeature : Fragment() {
(activity as AppCompatActivity).title = phoneFeature.label (activity as AppCompatActivity).title = phoneFeature.label
(activity as AppCompatActivity).supportActionBar?.show() (activity as AppCompatActivity).supportActionBar?.show()
settings = Settings.getInstance(requireContext())
} }
override fun onCreateView( override fun onCreateView(
@ -55,14 +61,14 @@ class SitePermissionsManagePhoneFeature : Fragment() {
val rootView = inflater.inflate(R.layout.fragment_manage_site_permissions_feature_phone, container, false) val rootView = inflater.inflate(R.layout.fragment_manage_site_permissions_feature_phone, container, false)
initAskToAllowRadio(rootView) initAskToAllowRadio(rootView)
initBlockRadio(rootView)
initBockedByAndroidContainer(rootView) initBockedByAndroidContainer(rootView)
return rootView return rootView
} }
private fun initAskToAllowRadio(rootView: View) { private fun initAskToAllowRadio(rootView: View) {
val radio = rootView.findViewById<RadioButton>(R.id.ask_to_allow_switch) val radio = rootView.findViewById<RadioButton>(R.id.ask_to_allow_radio)
val askToAllowText = getString(R.string.preference_option_phone_feature_ask_to_allow) val askToAllowText = getString(R.string.preference_option_phone_feature_ask_to_allow)
val recommendedText = getString(R.string.phone_feature_recommended) val recommendedText = getString(R.string.phone_feature_recommended)
val recommendedTextSize = resources.getDimensionPixelSize(R.dimen.phone_feature_label_recommended_text_size) val recommendedTextSize = resources.getDimensionPixelSize(R.dimen.phone_feature_label_recommended_text_size)
@ -87,6 +93,24 @@ class SitePermissionsManagePhoneFeature : Fragment() {
append(recommendedSpannable) append(recommendedSpannable)
this this
} }
radio.setOnClickListener {
saveActionInSettings(ASK_TO_ALLOW)
}
radio.restoreState(ASK_TO_ALLOW)
}
private fun RadioButton.restoreState(action: SitePermissionsRules.Action) {
if (phoneFeature.action == action) {
this.isChecked = true
}
}
private fun initBlockRadio(rootView: View) {
val radio = rootView.findViewById<RadioButton>(R.id.block_radio)
radio.setOnClickListener {
saveActionInSettings(BLOCKED)
}
radio.restoreState(BLOCKED)
} }
private fun initBockedByAndroidContainer(rootView: View) { private fun initBockedByAndroidContainer(rootView: View) {
@ -141,6 +165,16 @@ class SitePermissionsManagePhoneFeature : Fragment() {
} }
} }
private val PhoneFeature.action: SitePermissionsRules.Action
get() {
return when (phoneFeature) {
PhoneFeature.CAMERA -> settings.getSitePermissionsPhoneFeatureCameraAction()
PhoneFeature.LOCATION -> settings.getSitePermissionsPhoneFeatureLocation()
PhoneFeature.MICROPHONE -> settings.getSitePermissionsPhoneFeatureMicrophoneAction()
PhoneFeature.NOTIFICATION -> settings.getSitePermissionsPhoneFeatureNotificationAction()
}
}
private fun initSettingsButton(rootView: View) { private fun initSettingsButton(rootView: View) {
val button = rootView.findViewById<Button>(R.id.settings_button) val button = rootView.findViewById<Button>(R.id.settings_button)
button.setOnClickListener { button.setOnClickListener {
@ -149,12 +183,21 @@ class SitePermissionsManagePhoneFeature : Fragment() {
} }
private fun openSettings() { private fun openSettings() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val intent = Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", requireContext().packageName, null) val uri = Uri.fromParts("package", requireContext().packageName, null)
intent.data = uri intent.data = uri
startActivity(intent) startActivity(intent)
} }
private fun saveActionInSettings(action: SitePermissionsRules.Action) {
when (phoneFeature) {
PhoneFeature.CAMERA -> settings.setSitePermissionsPhoneFeatureCameraAction(action)
PhoneFeature.LOCATION -> settings.setSitePermissionsPhoneFeatureLocation(action)
PhoneFeature.MICROPHONE -> settings.setSitePermissionsPhoneFeatureMicrophoneAction(action)
PhoneFeature.NOTIFICATION -> settings.setSitePermissionsPhoneFeatureNotificationAction(action)
}
}
companion object { companion object {
const val CAMERA_PERMISSION = 0 const val CAMERA_PERMISSION = 0
const val LOCATION_PERMISSION = 1 const val LOCATION_PERMISSION = 1

View File

@ -7,12 +7,15 @@ package org.mozilla.fenix.utils
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.preference.PreferenceManager import android.preference.PreferenceManager
import mozilla.components.feature.sitepermissions.SitePermissionsRules
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.getPreferenceKey
import java.security.InvalidParameterException
/** /**
* A simple wrapper for SharedPreferences that makes reading preference a little bit easier. * A simple wrapper for SharedPreferences that makes reading preference a little bit easier.
*/ */
@SuppressWarnings("TooManyFunctions")
class Settings private constructor(context: Context) { class Settings private constructor(context: Context) {
companion object { companion object {
@ -71,4 +74,80 @@ class Settings private constructor(context: Context) {
appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions), appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions),
true true
) )
fun setSitePermissionsPhoneFeatureCameraAction(action: SitePermissionsRules.Action) {
preferences.edit()
.putInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_camera), action.id)
.apply()
}
fun getSitePermissionsPhoneFeatureCameraAction(): SitePermissionsRules.Action {
return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_camera), 1)
.toSitePermissionsRulesAction()
}
fun setSitePermissionsPhoneFeatureMicrophoneAction(action: SitePermissionsRules.Action) {
preferences.edit()
.putInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_microphone), action.id)
.apply()
}
fun getSitePermissionsPhoneFeatureMicrophoneAction(): SitePermissionsRules.Action {
return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_microphone), 1)
.toSitePermissionsRulesAction()
}
fun setSitePermissionsPhoneFeatureNotificationAction(action: SitePermissionsRules.Action) {
preferences.edit()
.putInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_notification), action.id)
.apply()
}
fun getSitePermissionsPhoneFeatureNotificationAction(): SitePermissionsRules.Action {
return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_notification), 1)
.toSitePermissionsRulesAction()
}
fun setSitePermissionsPhoneFeatureLocation(action: SitePermissionsRules.Action) {
preferences.edit()
.putInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_location), action.id)
.apply()
}
fun getSitePermissionsPhoneFeatureLocation(): SitePermissionsRules.Action {
return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_location), 1)
.toSitePermissionsRulesAction()
}
fun getSitePermissionsRecommendedSettingsRules() = SitePermissionsRules(
camera = SitePermissionsRules.Action.ASK_TO_ALLOW,
notification = SitePermissionsRules.Action.ASK_TO_ALLOW,
location = SitePermissionsRules.Action.ASK_TO_ALLOW,
microphone = SitePermissionsRules.Action.ASK_TO_ALLOW
)
fun getSitePermissionsCustomSettingsRules(): SitePermissionsRules {
return SitePermissionsRules(
notification = getSitePermissionsPhoneFeatureNotificationAction(),
microphone = getSitePermissionsPhoneFeatureMicrophoneAction(),
location = getSitePermissionsPhoneFeatureLocation(),
camera = getSitePermissionsPhoneFeatureCameraAction()
)
}
private val SitePermissionsRules.Action.id: Int
get() {
return when (this) {
SitePermissionsRules.Action.BLOCKED -> 0
SitePermissionsRules.Action.ASK_TO_ALLOW -> 1
}
}
private fun Int.toSitePermissionsRulesAction(): SitePermissionsRules.Action {
return when (this) {
0 -> SitePermissionsRules.Action.BLOCKED
1 -> SitePermissionsRules.Action.ASK_TO_ALLOW
else -> throw InvalidParameterException("$this is not a valid SitePermissionsRules.Action")
}
}
} }

View File

@ -16,7 +16,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<RadioButton <RadioButton
android:id="@+id/ask_to_allow_switch" android:id="@+id/ask_to_allow_radio"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/preference_option_phone_feature_ask_to_allow" android:text="@string/preference_option_phone_feature_ask_to_allow"
@ -31,7 +31,7 @@
android:paddingBottom="@dimen/radio_button_preference_vertical"/> android:paddingBottom="@dimen/radio_button_preference_vertical"/>
<RadioButton <RadioButton
android:id="@+id/block_switch" 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_block"

View File

@ -22,7 +22,7 @@
android:key="@string/pref_key_recommended_settings" android:key="@string/pref_key_recommended_settings"
android:title="@string/preference_recommended_settings" android:title="@string/preference_recommended_settings"
android:summary="@string/preference_recommended_settings_summary" android:summary="@string/preference_recommended_settings_summary"
android:defaultValue="false"/> android:defaultValue="true"/>
<org.mozilla.fenix.settings.RadioButtonPreference <org.mozilla.fenix.settings.RadioButtonPreference
android:key="@string/pref_key_custom_settings" android:key="@string/pref_key_custom_settings"