• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
<lambda>null2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * ```
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * ```
10  *
11  * Unless required by applicable law or agreed to in writing, software distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.healthconnect.controller.deletion
17 
18 import android.os.Bundle
19 import android.view.LayoutInflater
20 import android.view.View
21 import android.view.ViewGroup
22 import androidx.fragment.app.Fragment
23 import androidx.fragment.app.activityViewModels
24 import com.android.healthconnect.controller.R
25 import com.android.healthconnect.controller.deletion.DeletionConstants.CONFIRMATION_EVENT
26 import com.android.healthconnect.controller.deletion.DeletionConstants.DELETION_TYPE
27 import com.android.healthconnect.controller.deletion.DeletionConstants.END_TIME
28 import com.android.healthconnect.controller.deletion.DeletionConstants.GO_BACK_EVENT
29 import com.android.healthconnect.controller.deletion.DeletionConstants.START_DELETION_EVENT
30 import com.android.healthconnect.controller.deletion.DeletionConstants.START_INACTIVE_APP_DELETION_EVENT
31 import com.android.healthconnect.controller.deletion.DeletionConstants.START_TIME
32 import com.android.healthconnect.controller.deletion.DeletionConstants.TIME_RANGE_SELECTION_EVENT
33 import com.android.healthconnect.controller.deletion.DeletionConstants.TRY_AGAIN_EVENT
34 import com.android.healthconnect.controller.shared.dialog.ProgressDialogFragment
35 import dagger.hilt.android.AndroidEntryPoint
36 import java.time.Instant
37 
38 /**
39  * Invisible fragment that handles every deletion flow with the deletion dialogs.
40  *
41  * <p>This fragment needs to be added to every page that performs deletion. Then the deletion flow
42  * can be started via {@link StartDeletionEvent}.
43  *
44  * <p>It can be added to the parent fragment without attaching to a view via the following snippet:
45  * <pre> if (childFragmentManager.findFragmentByTag(FRAGMENT_TAG_DELETION) == null) {
46  * ```
47  *      childFragmentManager
48  *          .commitNow {
49  *              add({@link DeletionFragment}(), FRAGMENT_TAG_DELETION)
50  *          }
51  * ```
52  * } </pre>
53  */
54 @AndroidEntryPoint(Fragment::class)
55 class DeletionFragment : Hilt_DeletionFragment() {
56 
57     private val viewModel: DeletionViewModel by activityViewModels()
58 
59     override fun onCreate(savedInstanceState: Bundle?) {
60         super.onCreate(savedInstanceState)
61 
62         // set event listeners
63         // start deletion
64         parentFragmentManager.setFragmentResultListener(START_DELETION_EVENT, this) { _, bundle ->
65             val deletionType = bundle.getParcelable(DELETION_TYPE, DeletionType::class.java)
66             val startTime = bundle.getParcelable(START_TIME, Instant::class.java)
67             val endTime = bundle.getParcelable(END_TIME, Instant::class.java)
68             viewModel.setDeletionType(deletionType!!)
69             if (startTime != null && endTime != null) {
70                 viewModel.setStartTime(startTime)
71                 viewModel.setEndTime(endTime)
72             }
73             showFirstDialog(deletionType, false)
74         }
75 
76         parentFragmentManager.setFragmentResultListener(START_INACTIVE_APP_DELETION_EVENT, this) {
77             _,
78             bundle ->
79             val deletionType = bundle.getParcelable(DELETION_TYPE, DeletionType::class.java)
80             viewModel.setDeletionType(deletionType!!)
81             showFirstDialog(deletionType, true)
82         }
83 
84         // time range selection
85         childFragmentManager.setFragmentResultListener(TIME_RANGE_SELECTION_EVENT, this) { _, _ ->
86             showConfirmationDialog()
87         }
88 
89         // confirmation dialog
90         childFragmentManager.setFragmentResultListener(GO_BACK_EVENT, this) { _, _ ->
91             showTimeRagePickerDialog()
92         }
93 
94         // deletion in progress
95         childFragmentManager.setFragmentResultListener(CONFIRMATION_EVENT, this) { _, _ ->
96             // start deletion from here which will trigger the progressDialog from observable
97             viewModel.delete()
98         }
99 
100         // try again
101         childFragmentManager.setFragmentResultListener(TRY_AGAIN_EVENT, this) { _, _ ->
102             showConfirmationDialog()
103         }
104     }
105 
106     override fun onCreateView(
107         inflater: LayoutInflater,
108         container: ViewGroup?,
109         savedInstanceState: Bundle?
110     ): View? {
111         return inflater.inflate(R.layout.fragment_deletion, container, false)
112     }
113 
114     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
115         super.onViewCreated(view, savedInstanceState)
116 
117         viewModel.deletionParameters.observe(viewLifecycleOwner) { deletion ->
118             deletion?.let { render(deletion) }
119         }
120     }
121 
122     private fun render(deletionParameters: DeletionParameters) {
123         when (deletionParameters.deletionState) {
124             DeletionState.STATE_NO_DELETION_IN_PROGRESS -> {
125                 hideProgressDialog()
126             }
127             DeletionState.STATE_PROGRESS_INDICATOR_STARTED -> {
128                 showProgressDialogFragment()
129             }
130             DeletionState.STATE_PROGRESS_INDICATOR_CAN_END -> {
131                 hideProgressDialog()
132             }
133             DeletionState.STATE_DELETION_SUCCESSFUL -> {
134                 showSuccessDialogFragment()
135             }
136             DeletionState.STATE_DELETION_FAILED -> {
137                 showFailedDialogFragment()
138             }
139             else -> {
140                 // do nothing
141             }
142         }
143     }
144 
145     private fun showConfirmationDialog() {
146         if (viewModel.deletionParameters.value?.deletionType is DeletionType.DeletionTypeAppData &&
147             viewModel.deletionParameters.value?.chosenRange == ChosenRange.DELETE_RANGE_ALL_DATA) {
148             showAppDeleteConfirmationDialog()
149         } else {
150             DeletionConfirmationDialogFragment()
151                 .show(childFragmentManager, DeletionConfirmationDialogFragment.TAG)
152         }
153     }
154 
155     private fun showAppDeleteConfirmationDialog() {
156         DeletionAppDataConfirmationDialogFragment()
157             .show(childFragmentManager, DeletionAppDataConfirmationDialogFragment.TAG)
158     }
159 
160     private fun showTimeRagePickerDialog() {
161         TimeRangeDialogFragment().show(childFragmentManager, TimeRangeDialogFragment.TAG)
162     }
163 
164     private fun showProgressDialogFragment() {
165         ProgressDialogFragment(titleRes = R.string.delete_progress_indicator)
166             .show(childFragmentManager, ProgressDialogFragment.TAG)
167     }
168 
169     private fun showSuccessDialogFragment() {
170         hideProgressDialog()
171         SuccessDialogFragment().show(childFragmentManager, SuccessDialogFragment.TAG)
172     }
173 
174     private fun showFailedDialogFragment() {
175         hideProgressDialog()
176         FailedDialogFragment().show(childFragmentManager, FailedDialogFragment.TAG)
177     }
178 
179     private fun showFirstDialog(deletionType: DeletionType, isInactiveApp: Boolean) {
180         if (isInactiveApp) {
181             showAppDeleteConfirmationDialog()
182         } else {
183             when (deletionType) {
184                 is DeletionType.DeleteDataEntry -> showConfirmationDialog()
185                 else -> showTimeRagePickerDialog()
186             }
187         }
188     }
189 
190     private fun hideProgressDialog() {
191         (childFragmentManager.findFragmentByTag(ProgressDialogFragment.TAG)
192                 as ProgressDialogFragment?)
193             ?.dismiss()
194     }
195 }
196