[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