1
0
Fork 0

Closes #1165: Added Doorhanger to the toolbar.

master
Arturo Mejia 2019-04-01 23:40:40 -04:00 committed by Colin Lee
parent 2670f0e1d7
commit 4489edd97b
14 changed files with 642 additions and 36 deletions

View File

@ -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

View File

@ -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() {

View File

@ -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)
}
}
}

View File

@ -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<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());
@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<out String>): PhoneFeature? {
return PhoneFeature.values().find { feature ->
feature.androidPermissionsList.any { permission ->
permission == permissions.first()
}
}
}
}
}

View File

@ -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")

View File

@ -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 {

View File

@ -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<QuickSettingsState, QuickSettingsAction, QuickSettingsChange>(
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<QuickSettingsState, QuickSettingsAction, QuickSettingsChange> {
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<String>) : 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()
}

View File

@ -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<out String>, grantResults: IntArray) {
if (arePermissionsGranted(requestCode, grantResults)) {
val feature = requireNotNull(PhoneFeature.findFeatureBy(permissions))
getManagedEmitter<QuickSettingsChange>()
.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<QuickSettingsAction>()
.subscribe {
when (it) {
is QuickSettingsAction.SelectBlockedByAndroid -> {
requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
}
is QuickSettingsAction.DismissDialog -> dismiss()
}
}
if (isVisible) {
getManagedEmitter<QuickSettingsChange>()
.onNext(QuickSettingsChange.PromptRestarted)
}
}
}

View File

@ -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<QuickSettingsAction>,
changesObservable: Observable<QuickSettingsChange>,
override val view: View
) : UIView<QuickSettingsState, QuickSettingsAction, QuickSettingsChange>(
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<PhoneFeature>()
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<AppCompatTextView>(R.id.url)
securityInfoLabel = view.findViewById<AppCompatTextView>(R.id.security_info)
cameraActionLabel = view.findViewById<AppCompatTextView>(R.id.camera_action_label)
microphoneActionLabel = view.findViewById<AppCompatTextView>(R.id.microphone_action_label)
locationActionLabel = view.findViewById<AppCompatTextView>(R.id.location_action_label)
notificationActionLabel = view.findViewById<AppCompatTextView>(R.id.notification_action_label)
}
override fun updateView() = Consumer<QuickSettingsState> { 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<TextView>(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
}
}
}

View File

@ -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(

View File

@ -0,0 +1,136 @@
<?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:id="@+id/quick_action_sheet"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/quick_settings_sheet"
android:background="?attr/toolbarColor">
<TextView
android:id="@+id/url"
style="@style/QuickSettingsText"
android:layout_height="@dimen/quicksettings_item_height"
android:layout_width="wrap_content"
tools:text="https://wikipedia.org"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/security_info"
style="@style/QuickSettingsText.Icon"
android:layout_height="@dimen/quicksettings_item_height"
android:layout_width="wrap_content"
tools:drawableStartCompat="@drawable/mozac_ic_lock"
tools:drawableTint="@color/photonGreen50"
tools:text="Secure connection"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/url"/>
<View
android:id="@+id/line_divider"
android:layout_width="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_height="1dp"
android:background="?attr/homeDividerColor"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/security_info"/>
<TextView
android:id="@+id/camera_icon"
style="@style/QuickSettingsText.Icon"
android:layout_height="@dimen/quicksettings_item_height"
android:layout_width="wrap_content"
app:drawableStartCompat="@drawable/ic_camera"
android:text="@string/preference_phone_feature_camera"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/line_divider"/>
<TextView
android:id="@+id/camera_action_label"
android:layout_height="@dimen/quicksettings_item_height"
android:layout_width="wrap_content"
style="@style/QuickSettingsText.PermissionItemEnd"
tools:text="Allowed"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/line_divider"/>
<TextView
android:id="@+id/microphone_icon"
style="@style/QuickSettingsText.Icon"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
app:drawableStartCompat="@drawable/ic_microphone"
android:text="@string/preference_phone_feature_microphone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/camera_icon"/>
<TextView
android:id="@+id/microphone_action_label"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
style="@style/QuickSettingsText.PermissionItemEnd"
tools:text="Blocked by Android"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/camera_action_label"/>
<TextView
android:id="@+id/notification_icon"
style="@style/QuickSettingsText.Icon"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
app:drawableStartCompat="@drawable/ic_notification"
android:text="@string/preference_phone_feature_notification"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/microphone_icon"/>
<TextView
android:id="@+id/notification_action_label"
style="@style/QuickSettingsText.PermissionItemEnd"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
tools:text="Blocked"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/microphone_action_label"/>
<TextView
android:id="@+id/location_icon"
style="@style/QuickSettingsText.Icon"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
app:drawableStartCompat="@drawable/ic_location"
android:text="@string/preference_phone_feature_location"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/notification_icon"/>
<TextView
android:id="@+id/location_action_label"
style="@style/QuickSettingsText.PermissionItemEnd"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
tools:text="Blocked"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/notification_action_label"/>
<TextView
android:id="@+id/manage_site_permissions"
style="@style/QuickSettingsText"
android:layout_width="wrap_content"
android:layout_height="@dimen/quicksettings_item_height"
android:textColor="@color/photonBlue50"
android:background="?android:attr/selectableItemBackground"
android:text="@string/quick_settings_sheet_manage_site_permissions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/location_icon"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -27,4 +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>
<!--Quick Settings-->
<dimen name="quicksettings_item_height">46dp</dimen>
</resources>

View File

@ -39,6 +39,8 @@
<string name="preference_option_phone_feature_block">Block</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
@ -47,4 +49,14 @@
<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-->
<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>
</resources>

View File

@ -222,4 +222,23 @@
<style name="progressBarStyleHorizontal" parent="@style/Widget.AppCompat.ProgressBar.Horizontal">
<item name="android:progressDrawable">@drawable/progress_gradient</item>
</style>
<style name="QuickSettingsText">
<item name="android:textColor">?attr/toolbarTextColor</item>
<item name="android:textSize">14sp</item>
<item name="android:paddingStart">16dp</item>
<item name="android:gravity">center_vertical</item>
<item name="android:layout_alignParentStart">true</item>
</style>
<style name="QuickSettingsText.Icon">
<item name="android:drawablePadding">8dp</item>
</style>
<style name="QuickSettingsText.PermissionItemEnd">
<item name="android:layout_alignParentEnd">true</item>
<item name="android:paddingEnd">24dp</item>
<item name="android:gravity">end|center_vertical</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources>