blob: 0715c8885978c0d979c58966ea6313d149ab75de [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package com.android.healthconnect.controller.permissions.request
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceGroup
import androidx.preference.SwitchPreference
import com.android.healthconnect.controller.R
import com.android.healthconnect.controller.permissions.data.HealthPermission
import com.android.healthconnect.controller.permissions.data.HealthPermissionStrings
import com.android.healthconnect.controller.permissions.data.PermissionsAccessType
import com.android.healthconnect.controller.shared.HealthDataCategoryExtensions.fromHealthPermissionType
import com.android.healthconnect.controller.shared.HealthDataCategoryExtensions.icon
import com.android.healthconnect.controller.shared.HealthPermissionReader
import com.android.healthconnect.controller.shared.children
import com.android.healthconnect.controller.shared.preference.HealthMainSwitchPreference
import com.android.healthconnect.controller.shared.preference.HealthSwitchPreference
import com.android.healthconnect.controller.utils.logging.HealthConnectLogger
import com.android.healthconnect.controller.utils.logging.PageName
import com.android.healthconnect.controller.utils.logging.PermissionsElement
import com.android.settingslib.widget.OnMainSwitchChangeListener
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/** Fragment for displaying permission switches. */
@AndroidEntryPoint(PreferenceFragmentCompat::class)
class PermissionsFragment : Hilt_PermissionsFragment() {
companion object {
private const val ALLOW_ALL_PREFERENCE = "allow_all_preference"
private const val READ_CATEGORY = "read_permission_category"
private const val WRITE_CATEGORY = "write_permission_category"
private const val HEADER = "request_permissions_header"
}
private val pageName = PageName.REQUEST_PERMISSIONS_PAGE
@Inject lateinit var logger: HealthConnectLogger
private val viewModel: RequestPermissionViewModel by activityViewModels()
@Inject lateinit var healthPermissionReader: HealthPermissionReader
private val header: RequestPermissionHeaderPreference? by lazy {
preferenceScreen.findPreference(HEADER)
}
private val allowAllPreference: HealthMainSwitchPreference? by lazy {
preferenceScreen.findPreference(ALLOW_ALL_PREFERENCE)
}
private val mReadPermissionCategory: PreferenceGroup? by lazy {
preferenceScreen.findPreference(READ_CATEGORY)
}
private val mWritePermissionCategory: PreferenceGroup? by lazy {
preferenceScreen.findPreference(WRITE_CATEGORY)
}
private val onSwitchChangeListener: OnMainSwitchChangeListener =
OnMainSwitchChangeListener { _, grant ->
mReadPermissionCategory?.children?.forEach { preference ->
(preference as SwitchPreference).isChecked = grant
}
mWritePermissionCategory?.children?.forEach { preference ->
(preference as SwitchPreference).isChecked = grant
}
viewModel.updatePermissions(grant)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
logger.setPageId(pageName)
}
override fun onResume() {
super.onResume()
logger.setPageId(pageName)
logger.logPageImpression()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
logger.setPageId(pageName)
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.permissions_screen, rootKey)
allowAllPreference?.logNameActive = PermissionsElement.ALLOW_ALL_SWITCH
allowAllPreference?.logNameInactive = PermissionsElement.ALLOW_ALL_SWITCH
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.appMetadata.observe(viewLifecycleOwner) { app ->
logger.logImpression(PermissionsElement.APP_RATIONALE_LINK)
header?.bind(app.appName) {
val startRationaleIntent =
healthPermissionReader.getApplicationRationaleIntent(app.packageName)
logger.logInteraction(PermissionsElement.APP_RATIONALE_LINK)
startActivity(startRationaleIntent)
}
mReadPermissionCategory?.title =
getString(R.string.read_permission_category, app.appName)
mWritePermissionCategory?.title =
getString(R.string.write_permission_category, app.appName)
}
viewModel.permissionsList.observe(viewLifecycleOwner) { permissions ->
updateDataList(permissions)
setupAllowAll()
}
}
private fun setupAllowAll() {
viewModel.allPermissionsGranted.observe(viewLifecycleOwner) { allPermissionsGranted ->
// does not trigger removing/enabling all permissions
allowAllPreference?.removeOnSwitchChangeListener(onSwitchChangeListener)
allowAllPreference?.isChecked = allPermissionsGranted
allowAllPreference?.addOnSwitchChangeListener(onSwitchChangeListener)
}
allowAllPreference?.addOnSwitchChangeListener(onSwitchChangeListener)
}
private fun updateDataList(permissionsList: List<HealthPermission>) {
mReadPermissionCategory?.removeAll()
mWritePermissionCategory?.removeAll()
permissionsList.forEach { permission ->
val value = viewModel.isPermissionGranted(permission)
if (PermissionsAccessType.READ == permission.permissionsAccessType) {
mReadPermissionCategory?.addPreference(getPermissionPreference(value, permission))
} else if (PermissionsAccessType.WRITE == permission.permissionsAccessType) {
mWritePermissionCategory?.addPreference(getPermissionPreference(value, permission))
}
}
mReadPermissionCategory?.apply { isVisible = (preferenceCount != 0) }
mWritePermissionCategory?.apply { isVisible = (preferenceCount != 0) }
}
private fun getPermissionPreference(
defaultValue: Boolean,
permission: HealthPermission
): Preference {
return HealthSwitchPreference(requireContext()).also {
val healthCategory = fromHealthPermissionType(permission.healthPermissionType)
it.setIcon(healthCategory.icon())
it.setDefaultValue(defaultValue)
it.setTitle(
HealthPermissionStrings.fromPermissionType(permission.healthPermissionType)
.uppercaseLabel)
it.logNameActive = PermissionsElement.PERMISSION_SWITCH
it.logNameInactive = PermissionsElement.PERMISSION_SWITCH
it.setOnPreferenceChangeListener { _, newValue ->
viewModel.updatePermission(permission, newValue as Boolean)
true
}
}
}
}