1 /** 2 * 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.health.connect.TimeInstantRangeFilter 19 import android.util.Log 20 import androidx.lifecycle.LiveData 21 import androidx.lifecycle.MutableLiveData 22 import androidx.lifecycle.ViewModel 23 import androidx.lifecycle.viewModelScope 24 import com.android.healthconnect.controller.deletion.api.DeleteAllDataUseCase 25 import com.android.healthconnect.controller.deletion.api.DeleteAppDataUseCase 26 import com.android.healthconnect.controller.deletion.api.DeleteCategoryUseCase 27 import com.android.healthconnect.controller.deletion.api.DeleteEntryUseCase 28 import com.android.healthconnect.controller.deletion.api.DeletePermissionTypeUseCase 29 import dagger.hilt.android.lifecycle.HiltViewModel 30 import java.time.Instant 31 import javax.inject.Inject 32 import kotlinx.coroutines.launch 33 34 @HiltViewModel 35 @Deprecated("This won't be used once the NEW_INFORMATION_ARCHITECTURE feature is enabled.") 36 class DeletionViewModel 37 @Inject 38 constructor( 39 private val deleteAllDataUseCase: DeleteAllDataUseCase, 40 private val deleteCategoryUseCase: DeleteCategoryUseCase, 41 private val deletePermissionTypeUseCase: DeletePermissionTypeUseCase, 42 private val deleteEntryUseCase: DeleteEntryUseCase, 43 private val deleteAppDataUseCase: DeleteAppDataUseCase 44 ) : ViewModel() { 45 46 companion object { 47 private const val TAG = "DeletionViewModel" 48 } 49 50 private val _deletionParameters = MutableLiveData(DeletionParameters()) 51 private var _removePermissions = false 52 var isInactiveApp = false 53 54 val deletionParameters: LiveData<DeletionParameters> 55 get() = _deletionParameters 56 57 val showTimeRangeDialogFragment: Boolean 58 get() = currentDeletionParameters().showTimeRangePickerDialog 59 currentDeletionParametersnull60 private fun currentDeletionParameters() = _deletionParameters.value!! 61 62 fun setRemovePermissions(boolean: Boolean) { 63 _removePermissions = boolean 64 } 65 setDeletionTypenull66 fun setDeletionType(deletionType: DeletionType) { 67 val showTimeRangePickerDialog = 68 when (deletionType) { 69 is DeletionType.DeleteDataEntry -> false 70 else -> true 71 } 72 _deletionParameters.value = 73 currentDeletionParameters() 74 .copy( 75 showTimeRangePickerDialog = showTimeRangePickerDialog, 76 deletionType = deletionType) 77 } 78 setChosenRangenull79 fun setChosenRange(chosenRange: ChosenRange) { 80 _deletionParameters.value = _deletionParameters.value?.copy(chosenRange = chosenRange) 81 } 82 setEndTimenull83 fun setEndTime(endTime: Instant) { 84 _deletionParameters.value = 85 _deletionParameters.value?.copy(endTimeMs = endTime.toEpochMilli()) 86 } 87 setStartTimenull88 fun setStartTime(startTime: Instant) { 89 _deletionParameters.value = 90 _deletionParameters.value?.copy(startTimeMs = startTime.toEpochMilli()) 91 } 92 93 private var _categoriesReloadNeeded = MutableLiveData(false) 94 private val _appPermissionReloadNeeded = MutableLiveData(false) 95 96 // Whether the categories screen needs to be reloaded after category data deletion. 97 val categoriesReloadNeeded: LiveData<Boolean> 98 get() = _categoriesReloadNeeded 99 100 val appPermissionReloadNeeded: LiveData<Boolean> 101 get() = _appPermissionReloadNeeded 102 setDeletionStatenull103 private fun setDeletionState(newState: DeletionState) { 104 _deletionParameters.value = currentDeletionParameters().copy(deletionState = newState) 105 } 106 deletenull107 fun delete() { 108 viewModelScope.launch { 109 setDeletionState(DeletionState.STATE_DELETION_STARTED) 110 111 try { 112 113 setDeletionState(DeletionState.STATE_PROGRESS_INDICATOR_STARTED) 114 115 val timeRangeFilter = 116 TimeInstantRangeFilter.Builder() 117 .setStartTime(currentDeletionParameters().getStartTimeInstant()) 118 .setEndTime(currentDeletionParameters().getEndTimeInstant()) 119 .build() 120 121 when (val deletionType = currentDeletionParameters().deletionType) { 122 is DeletionType.DeleteDataEntry -> { 123 _deletionParameters.value?.let { deleteEntryUseCase.invoke(deletionType) } 124 } 125 is DeletionType.DeletionTypeAllData -> { 126 _deletionParameters.value?.let { 127 deleteAllDataUseCase.invoke(timeRangeFilter) 128 _categoriesReloadNeeded.postValue(true) 129 } 130 } 131 is DeletionType.DeletionTypeCategoryData -> { 132 deletionParameters.value?.let { 133 deleteCategoryUseCase.invoke(deletionType, timeRangeFilter) 134 _categoriesReloadNeeded.postValue(true) 135 } 136 } 137 is DeletionType.DeletionTypeHealthPermissionTypeData -> { 138 deletionParameters.value?.let { 139 deletePermissionTypeUseCase.invoke(deletionType, timeRangeFilter) 140 } 141 } 142 is DeletionType.DeletionTypeAppData -> { 143 deletionParameters.value?.let { 144 deleteAppDataUseCase.invoke( 145 deletionType, timeRangeFilter, _removePermissions) 146 if (_removePermissions) { 147 _appPermissionReloadNeeded.value = true 148 } 149 } 150 } 151 else -> {} 152 } 153 setDeletionState(DeletionState.STATE_DELETION_SUCCESSFUL) 154 } catch (error: Exception) { 155 Log.e(TAG, "Failed to delete data ${currentDeletionParameters()}", error) 156 157 setDeletionState(DeletionState.STATE_DELETION_FAILED) 158 } finally { 159 setDeletionState(DeletionState.STATE_PROGRESS_INDICATOR_CAN_END) 160 } 161 } 162 } 163 } 164