diff --git a/CHANGELOG.md b/CHANGELOG.md index e4b1d4a22..205b8d355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #957 - Adds telemetry for the context menu - #1036 - Adds telemetry for Find in Page - #1049 - Add style for progress bar with gradient drawable - +- #1165 - Added doorhanger to the toolbar ### Changed ### Removed \ No newline at end of file diff --git a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt index dd04b83ae..2d6d9fceb 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -67,6 +67,7 @@ import org.mozilla.fenix.quickactionsheet.QuickActionAction import org.mozilla.fenix.quickactionsheet.QuickActionComponent import org.mozilla.fenix.utils.ItsNotBrokenSnack import org.mozilla.fenix.utils.Settings +import org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment class BrowserFragment : Fragment(), BackHandler { private lateinit var toolbarComponent: ToolbarComponent @@ -255,6 +256,17 @@ class BrowserFragment : Fragment(), BackHandler { view = view ) } + toolbarComponent.getView().setOnSiteSecurityClickedListener { + sessionId?.run { + val session = requireNotNull(requireContext().components.core.sessionManager.findSessionById(this)) + val quickSettingsSheet = QuickSettingsSheetDialogFragment.newInstance( + url = session.url, + isSecured = session.securityInfo.secure, + isSiteInExceptionList = false + ) + quickSettingsSheet.show(requireFragmentManager(), QuickSettingsSheetDialogFragment.FRAGMENT_TAG) + } + } } override fun onResume() { diff --git a/app/src/main/java/org/mozilla/fenix/settings/Extensions.kt b/app/src/main/java/org/mozilla/fenix/settings/Extensions.kt index 4c9777432..a3c8c744a 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/Extensions.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/Extensions.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.settings import android.content.Context +import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.feature.sitepermissions.SitePermissionsRules import org.mozilla.fenix.R @@ -18,3 +19,17 @@ internal fun SitePermissionsRules.Action.toString(context: Context): String { } } } + +internal fun SitePermissions.Status.toString(context: Context): String { + return when (this) { + SitePermissions.Status.BLOCKED -> { + context.getString(R.string.preference_option_phone_feature_block) + } + SitePermissions.Status.NO_DECISION -> { + context.getString(R.string.preference_option_phone_feature_ask_to_allow) + } + SitePermissions.Status.ALLOWED -> { + context.getString(R.string.phone_feature_no_decision) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/PhoneFeature.kt b/app/src/main/java/org/mozilla/fenix/settings/PhoneFeature.kt new file mode 100644 index 000000000..98e3e1655 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/PhoneFeature.kt @@ -0,0 +1,70 @@ +/* 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.Manifest +import android.Manifest.permission.ACCESS_COARSE_LOCATION +import android.Manifest.permission.ACCESS_FINE_LOCATION +import android.Manifest.permission.RECORD_AUDIO +import android.content.Context +import mozilla.components.feature.sitepermissions.SitePermissions +import mozilla.components.support.ktx.android.content.isPermissionGranted +import org.mozilla.fenix.utils.Settings + +enum class PhoneFeature(val id: Int, val androidPermissionsList: Array) { + 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()); + + @Suppress("SpreadOperator") + fun isAndroidPermissionGranted(context: Context): Boolean { + val permissions = when (this) { + CAMERA, LOCATION, MICROPHONE -> androidPermissionsList + NOTIFICATION -> return true + } + return context.isPermissionGranted(*permissions) + } + + fun getActionLabel(context: Context, sitePermissions: SitePermissions? = null, settings: Settings): String { + return when (this) { + CAMERA -> { + sitePermissions?.cameraBack?.toString(context) ?: settings + .getSitePermissionsPhoneFeatureCameraAction() + .toString(context) + } + LOCATION -> { + sitePermissions?.location?.toString(context) ?: settings + .getSitePermissionsPhoneFeatureLocation() + .toString(context) + } + MICROPHONE -> { + sitePermissions?.microphone?.toString(context) ?: settings + .getSitePermissionsPhoneFeatureMicrophoneAction() + .toString(context) + } + NOTIFICATION -> { + sitePermissions?.notification?.toString(context) ?: settings + .getSitePermissionsPhoneFeatureNotificationAction() + .toString(context) + } + } + } + + companion object { + fun findFeatureBy(permissions: Array): PhoneFeature? { + return PhoneFeature.values().find { feature -> + feature.androidPermissionsList.any { permission -> + permission == permissions.first() + } + } + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsFragment.kt index f87c1d94f..e7df0a4f9 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsFragment.kt @@ -12,11 +12,10 @@ import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceClickListener import androidx.preference.PreferenceFragmentCompat import org.mozilla.fenix.R -import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature -import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.NOTIFICATION -import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.LOCATION -import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.CAMERA -import org.mozilla.fenix.settings.SitePermissionsManagePhoneFeature.PhoneFeature.MICROPHONE +import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION +import org.mozilla.fenix.settings.PhoneFeature.LOCATION +import org.mozilla.fenix.settings.PhoneFeature.CAMERA +import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE import org.mozilla.fenix.utils.Settings @SuppressWarnings("TooManyFunctions") diff --git a/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsManagePhoneFeature.kt b/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsManagePhoneFeature.kt index 4a878b360..78c7518b1 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsManagePhoneFeature.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SitePermissionsManagePhoneFeature.kt @@ -4,10 +4,6 @@ package org.mozilla.fenix.settings -import android.Manifest.permission.ACCESS_COARSE_LOCATION -import android.Manifest.permission.CAMERA -import android.Manifest.permission.RECORD_AUDIO -import android.Manifest.permission.ACCESS_FINE_LOCATION import android.content.Intent import android.graphics.Color import android.net.Uri @@ -33,7 +29,6 @@ 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 org.mozilla.fenix.R class SitePermissionsManagePhoneFeature : Fragment() { @@ -126,13 +121,6 @@ class SitePermissionsManagePhoneFeature : Fragment() { } } - enum class PhoneFeature(val id: Int) { - CAMERA(CAMERA_PERMISSION), - LOCATION(LOCATION_PERMISSION), - MICROPHONE(MICROPHONE_PERMISSION), - NOTIFICATION(NOTIFICATION_PERMISSION) - } - private val PhoneFeature.label: String get() { return when (this) { @@ -143,18 +131,9 @@ class SitePermissionsManagePhoneFeature : Fragment() { } } - @Suppress("SpreadOperator") private val PhoneFeature.isAndroidPermissionGranted: Boolean get() { - val permissions = when (this) { - PhoneFeature.CAMERA -> arrayOf(CAMERA) - PhoneFeature.LOCATION -> arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION) - PhoneFeature.MICROPHONE -> arrayOf(RECORD_AUDIO) - PhoneFeature.NOTIFICATION -> { - return true - } - } - return requireContext().isPermissionGranted(*permissions) + return this.isAndroidPermissionGranted(requireContext()) } private fun Int.toPhoneFeature(): PhoneFeature { diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsComponent.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsComponent.kt new file mode 100644 index 000000000..312b50821 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsComponent.kt @@ -0,0 +1,79 @@ +/* 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.quicksettings + +import android.view.ViewGroup +import org.mozilla.fenix.mvi.Action +import org.mozilla.fenix.mvi.ActionBusFactory +import org.mozilla.fenix.mvi.Change +import org.mozilla.fenix.mvi.UIComponent +import org.mozilla.fenix.mvi.UIView +import org.mozilla.fenix.mvi.ViewState +import org.mozilla.fenix.settings.PhoneFeature + +class QuickSettingsComponent( + private val container: ViewGroup, + bus: ActionBusFactory, + override var initialState: QuickSettingsState +) : UIComponent( + bus.getManagedEmitter(QuickSettingsAction::class.java), + bus.getSafeManagedObservable(QuickSettingsChange::class.java) +) { + override val reducer: (QuickSettingsState, QuickSettingsChange) -> QuickSettingsState = { state, change -> + when (change) { + is QuickSettingsChange.Change -> { + state.copy( + mode = QuickSettingsState.Mode.Normal( + change.url, + change.isSecured, + change.isSiteInExceptionList + ) + ) + } + is QuickSettingsChange.PermissionGranted -> { + state.copy( + mode = QuickSettingsState.Mode.ActionLabelUpdated(change.phoneFeature) + ) + } + QuickSettingsChange.PromptRestarted -> { + state.copy( + mode = QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid + ) + } + } + } + + override fun initView(): UIView { + return QuickSettingsUIView(container, actionEmitter, changesObservable, container) + } + + init { + render(reducer) + } +} + +data class QuickSettingsState(val mode: Mode) : ViewState { + sealed class Mode { + data class Normal(val url: String, val isSecured: Boolean, val isSiteInExceptionList: Boolean) : Mode() + data class ActionLabelUpdated(val phoneFeature: PhoneFeature) : Mode() + object CheckPendingFeatureBlockedByAndroid : Mode() + } +} + +sealed class QuickSettingsAction : Action { + data class SelectBlockedByAndroid(val permissions: Array) : QuickSettingsAction() + object DismissDialog : QuickSettingsAction() +} + +sealed class QuickSettingsChange : Change { + data class Change( + val url: String, + val isSecured: Boolean, + val isSiteInExceptionList: Boolean + ) : QuickSettingsChange() + + data class PermissionGranted(val phoneFeature: PhoneFeature) : QuickSettingsChange() + object PromptRestarted : QuickSettingsChange() +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt new file mode 100644 index 000000000..76e56a834 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt @@ -0,0 +1,97 @@ +/* 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.quicksettings + +import android.content.pm.PackageManager.PERMISSION_GRANTED +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintLayout +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import org.mozilla.fenix.R +import org.mozilla.fenix.mvi.ActionBusFactory +import org.mozilla.fenix.mvi.getAutoDisposeObservable +import org.mozilla.fenix.mvi.getManagedEmitter +import org.mozilla.fenix.settings.PhoneFeature + +private const val KEY_URL = "KEY_URL" +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 REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4 + +@SuppressWarnings("TooManyFunctions") +class QuickSettingsSheetDialogFragment : BottomSheetDialogFragment() { + private val safeArguments get() = requireNotNull(arguments) + private val url: String by lazy { safeArguments.getString(KEY_URL) } + 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 + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_quick_settings_dialog_sheet, container, false) + } + + override fun onViewCreated(rootView: View, savedInstanceState: Bundle?) { + super.onViewCreated(rootView, savedInstanceState) + quickSettingsComponent = QuickSettingsComponent( + rootView as ConstraintLayout, ActionBusFactory.get(this), + QuickSettingsState( + QuickSettingsState.Mode.Normal(url, isSecured, isSiteInExceptionList) + ) + ) + } + + companion object { + const val FRAGMENT_TAG = "QUICK_SETTINGS_FRAGMENT_TAG" + + fun newInstance( + url: String, + isSecured: Boolean, + isSiteInExceptionList: Boolean + ): QuickSettingsSheetDialogFragment { + + val fragment = QuickSettingsSheetDialogFragment() + val arguments = fragment.arguments ?: Bundle() + + with(arguments) { + putString(KEY_URL, url) + putBoolean(KEY_IS_SECURED, isSecured) + putBoolean(KEY_IS_SITE_IN_EXCEPTION_LIST, isSiteInExceptionList) + } + fragment.arguments = arguments + return fragment + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + if (arePermissionsGranted(requestCode, grantResults)) { + val feature = requireNotNull(PhoneFeature.findFeatureBy(permissions)) + getManagedEmitter() + .onNext(QuickSettingsChange.PermissionGranted(feature)) + } + } + + private fun arePermissionsGranted(requestCode: Int, grantResults: IntArray) = + requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED } + + override fun onResume() { + super.onResume() + getAutoDisposeObservable() + .subscribe { + when (it) { + is QuickSettingsAction.SelectBlockedByAndroid -> { + requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS) + } + is QuickSettingsAction.DismissDialog -> dismiss() + } + } + + if (isVisible) { + getManagedEmitter() + .onNext(QuickSettingsChange.PromptRestarted) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsUIView.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsUIView.kt new file mode 100644 index 000000000..ecb99e3ee --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsUIView.kt @@ -0,0 +1,168 @@ +/* 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.quicksettings + +import android.util.TypedValue +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.appcompat.content.res.AppCompatResources +import androidx.appcompat.widget.AppCompatTextView +import androidx.core.content.ContextCompat +import io.reactivex.Observable +import io.reactivex.Observer +import io.reactivex.functions.Consumer +import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes +import mozilla.components.support.ktx.kotlin.toUri +import org.jetbrains.anko.textColorResource +import org.mozilla.fenix.R +import org.mozilla.fenix.mvi.UIView +import org.mozilla.fenix.settings.PhoneFeature +import org.mozilla.fenix.settings.PhoneFeature.CAMERA +import org.mozilla.fenix.settings.PhoneFeature.LOCATION +import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE +import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION +import org.mozilla.fenix.utils.ItsNotBrokenSnack +import org.mozilla.fenix.utils.Settings + +class QuickSettingsUIView( + container: ViewGroup, + actionEmitter: Observer, + changesObservable: Observable, + override val view: View +) : UIView( + container, actionEmitter, changesObservable +) { + private val securityInfoLabel: TextView + private val urlLabel: TextView + private val cameraActionLabel: TextView + private val microphoneActionLabel: TextView + private val locationActionLabel: TextView + private val notificationActionLabel: TextView + private val blockedByAndroidPhoneFeatures = mutableListOf() + private val context get() = view.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 { + urlLabel = view.findViewById(R.id.url) + securityInfoLabel = view.findViewById(R.id.security_info) + cameraActionLabel = view.findViewById(R.id.camera_action_label) + microphoneActionLabel = view.findViewById(R.id.microphone_action_label) + locationActionLabel = view.findViewById(R.id.location_action_label) + notificationActionLabel = view.findViewById(R.id.notification_action_label) + } + + override fun updateView() = Consumer { state -> + when (state.mode) { + is QuickSettingsState.Mode.Normal -> { + bindUrl(state.mode.url) + bindSecurityInfo(state.mode.isSecured) + bindPhoneFeatureItem(cameraActionLabel, CAMERA) + bindPhoneFeatureItem(microphoneActionLabel, MICROPHONE) + bindPhoneFeatureItem(notificationActionLabel, NOTIFICATION) + bindPhoneFeatureItem(locationActionLabel, LOCATION) + bindManagePermissionsButton() + } + is QuickSettingsState.Mode.ActionLabelUpdated -> { + bindPhoneFeatureItem( + state.mode.phoneFeature.actionLabel, + state.mode.phoneFeature + ) + } + is QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid -> { + checkFeaturesBlockedByAndroid() + } + } + } + + private fun bindUrl(url: String) { + urlLabel.text = url.toUri().hostWithoutCommonPrefixes + } + + private fun bindSecurityInfo(isSecured: Boolean) { + val stringId: Int + val drawableId: Int + val drawableTint: Int + + if (isSecured) { + stringId = R.string.quick_settings_sheet_secure_connection + drawableId = R.drawable.mozac_ic_lock + drawableTint = R.color.photonGreen50 + } else { + stringId = R.string.quick_settings_sheet_insecure_connection + drawableId = R.drawable.mozac_ic_globe + drawableTint = R.color.photonRed50 + } + + val icon = AppCompatResources.getDrawable(context, drawableId) + icon?.setTint(ContextCompat.getColor(context, drawableTint)) + securityInfoLabel.setText(stringId) + securityInfoLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null) + } + + private fun bindPhoneFeatureItem(actionLabel: TextView, phoneFeature: PhoneFeature) { + if (!phoneFeature.isAndroidPermissionGranted(context)) { + handleBlockedByAndroidAction(actionLabel, phoneFeature) + } else { + bindPhoneAction(actionLabel, phoneFeature) + } + } + + private fun handleBlockedByAndroidAction(actionLabel: TextView, phoneFeature: PhoneFeature) { + actionLabel.setText(R.string.phone_feature_blocked_by_android) + actionLabel.setTextColor(ContextCompat.getColor(context, R.color.photonBlue50)) + actionLabel.tag = phoneFeature + actionLabel.setOnClickListener { + val feature = it.tag as PhoneFeature + actionEmitter.onNext( + QuickSettingsAction.SelectBlockedByAndroid( + feature.androidPermissionsList + ) + ) + } + blockedByAndroidPhoneFeatures.add(phoneFeature) + } + + private fun bindPhoneAction(actionLabel: TextView, phoneFeature: PhoneFeature) { + actionLabel.text = phoneFeature.getActionLabel(context = context, settings = settings) + actionLabel.textColorResource = toolbarTextColorId + actionLabel.isEnabled = false + blockedByAndroidPhoneFeatures.remove(phoneFeature) + } + + private fun bindManagePermissionsButton() { + val urlLabel = view.findViewById(R.id.manage_site_permissions) + urlLabel.setOnClickListener { + actionEmitter.onNext(QuickSettingsAction.DismissDialog) + ItsNotBrokenSnack(context).showSnackbar(issueNumber = "1170") + } + } + + private fun checkFeaturesBlockedByAndroid() { + val clonedList = blockedByAndroidPhoneFeatures.toTypedArray() + clonedList.forEach { phoneFeature -> + if (phoneFeature.isAndroidPermissionGranted(context)) { + val actionLabel = phoneFeature.actionLabel + bindPhoneAction(actionLabel, phoneFeature) + } + } + } + + private val PhoneFeature.actionLabel + get(): TextView { + return when (this) { + CAMERA -> cameraActionLabel + LOCATION -> locationActionLabel + MICROPHONE -> microphoneActionLabel + NOTIFICATION -> notificationActionLabel + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index 2041f8eca..e7e460dd2 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -117,8 +117,12 @@ class Settings private constructor(context: Context) { } fun getSitePermissionsPhoneFeatureCameraAction(): SitePermissionsRules.Action { - return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_camera), 1) - .toSitePermissionsRulesAction() + return if (shouldRecommendedSettingsBeActivated) { + getSitePermissionsRecommendedSettingsRules().camera + } else { + preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_camera), 1) + .toSitePermissionsRulesAction() + } } fun setSitePermissionsPhoneFeatureMicrophoneAction(action: SitePermissionsRules.Action) { @@ -128,8 +132,12 @@ class Settings private constructor(context: Context) { } fun getSitePermissionsPhoneFeatureMicrophoneAction(): SitePermissionsRules.Action { - return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_microphone), 1) - .toSitePermissionsRulesAction() + return if (shouldRecommendedSettingsBeActivated) { + getSitePermissionsRecommendedSettingsRules().microphone + } else { + preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_microphone), 1) + .toSitePermissionsRulesAction() + } } fun setSitePermissionsPhoneFeatureNotificationAction(action: SitePermissionsRules.Action) { @@ -139,8 +147,12 @@ class Settings private constructor(context: Context) { } fun getSitePermissionsPhoneFeatureNotificationAction(): SitePermissionsRules.Action { - return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_notification), 1) - .toSitePermissionsRulesAction() + return if (shouldRecommendedSettingsBeActivated) { + getSitePermissionsRecommendedSettingsRules().notification + } else { + return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_notification), 1) + .toSitePermissionsRulesAction() + } } fun setSitePermissionsPhoneFeatureLocation(action: SitePermissionsRules.Action) { @@ -150,8 +162,12 @@ class Settings private constructor(context: Context) { } fun getSitePermissionsPhoneFeatureLocation(): SitePermissionsRules.Action { - return preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_location), 1) - .toSitePermissionsRulesAction() + return if (shouldRecommendedSettingsBeActivated) { + getSitePermissionsRecommendedSettingsRules().location + } else { + preferences.getInt(appContext.getPreferenceKey(R.string.pref_key_phone_feature_location), 1) + .toSitePermissionsRulesAction() + } } fun getSitePermissionsRecommendedSettingsRules() = SitePermissionsRules( diff --git a/app/src/main/res/layout/fragment_quick_settings_dialog_sheet.xml b/app/src/main/res/layout/fragment_quick_settings_dialog_sheet.xml new file mode 100644 index 000000000..9ac01da90 --- /dev/null +++ b/app/src/main/res/layout/fragment_quick_settings_dialog_sheet.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 07d3e0d38..45adcae83 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -27,4 +27,8 @@ 16dp 12dp 14sp + + + 46dp + \ No newline at end of file diff --git a/app/src/main/res/values/permissions_settings_strings.xml b/app/src/main/res/values/permissions_settings_strings.xml index 053ba3ab9..15eb2abff 100644 --- a/app/src/main/res/values/permissions_settings_strings.xml +++ b/app/src/main/res/values/permissions_settings_strings.xml @@ -39,6 +39,8 @@ Block Blocked by Android + + No Decision
1. Go to Android Settings

2. Tap Permissions

3. Toggle %1$s to ON @@ -47,4 +49,14 @@ Recommended Go to Settings + + + Quick settings sheet + + + Secure Connection + + Insecure Connection + + Manage site permissions \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 59040f3c0..bcc0abceb 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -222,4 +222,23 @@ + + + + + +