[fenix] Closes https://github.com/mozilla-mobile/fenix/issues/1165: Added Doorhanger to the toolbar.
parent
8bbcf4490a
commit
e59989ef9c
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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()
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue