1 /*
<lambda>null2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  *
17  */
18 
19 package com.android.healthconnect.controller.permissions.additionalaccess
20 
21 import android.app.Dialog
22 import android.content.Intent.EXTRA_PACKAGE_NAME
23 import android.os.Bundle
24 import android.util.Log
25 import android.view.View
26 import android.widget.ImageView
27 import android.widget.RadioGroup
28 import android.widget.TextView
29 import androidx.annotation.IdRes
30 import androidx.core.os.bundleOf
31 import androidx.fragment.app.DialogFragment
32 import androidx.fragment.app.activityViewModels
33 import com.android.healthconnect.controller.R
34 import com.android.healthconnect.controller.permissions.additionalaccess.PermissionUiState.ALWAYS_ALLOW
35 import com.android.healthconnect.controller.permissions.additionalaccess.PermissionUiState.ASK_EVERY_TIME
36 import com.android.healthconnect.controller.permissions.additionalaccess.PermissionUiState.NEVER_ALLOW
37 import com.android.healthconnect.controller.permissions.app.AppPermissionViewModel
38 import com.android.healthconnect.controller.shared.dialog.AlertDialogBuilder
39 import com.android.healthconnect.controller.utils.logging.AdditionalAccessElement.EXERCISE_ROUTES_ALLOW_ALL_BUTTON
40 import com.android.healthconnect.controller.utils.logging.AdditionalAccessElement.EXERCISE_ROUTES_ASK_BUTTON
41 import com.android.healthconnect.controller.utils.logging.AdditionalAccessElement.EXERCISE_ROUTES_DIALOG_CONTAINER
42 import com.android.healthconnect.controller.utils.logging.AdditionalAccessElement.EXERCISE_ROUTES_DIALOG_DENY_BUTTON
43 import com.android.healthconnect.controller.utils.logging.HealthConnectLogger
44 import dagger.hilt.android.AndroidEntryPoint
45 import javax.inject.Inject
46 
47 /** Dialog fragment to allow the user to change Exercise routes permission state. */
48 @AndroidEntryPoint(DialogFragment::class)
49 class ExerciseRoutesPermissionDialogFragment : Hilt_ExerciseRoutesPermissionDialogFragment() {
50 
51     @Inject lateinit var logger: HealthConnectLogger
52 
53     private lateinit var permissionRadioGroup: RadioGroup
54     private lateinit var appIcon: ImageView
55     private lateinit var packageName: String
56 
57     private val viewModel: AdditionalAccessViewModel by activityViewModels()
58     private val permissionsViewModel: AppPermissionViewModel by activityViewModels()
59     private val permissionChangedListener =
60         RadioGroup.OnCheckedChangeListener { _, selectedId ->
61             when (selectedId) {
62                 R.id.radio_button_always_allow -> {
63                     viewModel.updateExerciseRouteState(packageName, ALWAYS_ALLOW)
64                     logger.logInteraction(EXERCISE_ROUTES_ALLOW_ALL_BUTTON)
65                 }
66                 R.id.radio_button_ask -> {
67                     viewModel.updateExerciseRouteState(packageName, ASK_EVERY_TIME)
68                     logger.logInteraction(EXERCISE_ROUTES_ASK_BUTTON)
69                 }
70                 R.id.radio_button_revoke -> {
71                     viewModel.updateExerciseRouteState(packageName, NEVER_ALLOW)
72                     logger.logInteraction(EXERCISE_ROUTES_DIALOG_DENY_BUTTON)
73                 }
74             }
75             this.dismiss()
76         }
77     private val extraLogger = {
78         logger.logImpression(EXERCISE_ROUTES_ALLOW_ALL_BUTTON)
79         logger.logImpression(EXERCISE_ROUTES_ASK_BUTTON)
80         logger.logImpression(EXERCISE_ROUTES_DIALOG_DENY_BUTTON)
81     }
82 
83     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
84         val view = layoutInflater.inflate(R.layout.dialog_exercise_routes_permission, null)
85 
86         val packageNameExtra = requireArguments().getString(EXTRA_PACKAGE_NAME)
87         if (packageNameExtra.isNullOrEmpty()) {
88             Log.e(TAG, "Invalid Intent Extras, finishing.")
89             return super.onCreateDialog(savedInstanceState)
90         }
91         packageName = packageNameExtra
92 
93         setupMessage(view)
94         setupAppIcon(view)
95         setupPermissionRadioGroup(view)
96 
97         return AlertDialogBuilder(this, EXERCISE_ROUTES_DIALOG_CONTAINER)
98             .setAdditionalLogging(extraLogger)
99             .setView(view)
100             .create()
101     }
102 
103     private fun setupMessage(view: View) {
104         val dialogMessage = view.findViewById(R.id.dialog_message) as TextView
105         permissionsViewModel.appInfo.observe(this) { app ->
106             dialogMessage.text = getString(R.string.route_permissions_summary, app.appName)
107         }
108     }
109 
110     private fun setupAppIcon(view: View) {
111         appIcon = view.findViewById(R.id.dialog_icon)
112         permissionsViewModel.appInfo.observe(this) { app -> appIcon.setImageDrawable(app.icon) }
113     }
114 
115     private fun setupPermissionRadioGroup(view: View) {
116         permissionRadioGroup = view.findViewById(R.id.radio_group_route_permission)
117         permissionRadioGroup.apply {
118             val state = viewModel.additionalAccessState.value?.exerciseRoutePermissionUIState
119             if (state != null) {
120                 setOnCheckedChangeListener(null)
121                 check(getId(state))
122             }
123             setOnCheckedChangeListener(permissionChangedListener)
124         }
125     }
126 
127     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
128         super.onViewCreated(view, savedInstanceState)
129         viewModel.additionalAccessState.observe(viewLifecycleOwner) { screenState ->
130             permissionRadioGroup.check(getId(screenState.exerciseRoutePermissionUIState))
131         }
132     }
133 
134     fun setPackageName(packageName: String) {
135         this.packageName = packageName
136     }
137 
138     @IdRes
139     private fun getId(currentState: PermissionUiState): Int {
140         return when (currentState) {
141             ALWAYS_ALLOW -> R.id.radio_button_always_allow
142             NEVER_ALLOW -> R.id.radio_button_revoke
143             else -> R.id.radio_button_ask
144         }
145     }
146 
147     companion object {
148         private const val TAG = "ERPermissionDialog"
149 
150         fun createDialog(packageName: String): ExerciseRoutesPermissionDialogFragment {
151             return ExerciseRoutesPermissionDialogFragment().apply {
152                 arguments = bundleOf(EXTRA_PACKAGE_NAME to packageName)
153             }
154         }
155     }
156 }
157