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.permissions.connectedapps
17 
18 import android.util.Log
19 import androidx.lifecycle.LiveData
20 import androidx.lifecycle.MutableLiveData
21 import androidx.lifecycle.ViewModel
22 import androidx.lifecycle.viewModelScope
23 import com.android.healthconnect.controller.permissions.api.RevokeAllHealthPermissionsUseCase
24 import com.android.healthconnect.controller.permissions.connectedapps.searchapps.SearchHealthPermissionApps
25 import com.android.healthconnect.controller.service.IoDispatcher
26 import com.android.healthconnect.controller.shared.app.ConnectedAppMetadata
27 import com.android.healthconnect.controller.utils.postValueIfUpdated
28 import dagger.hilt.android.lifecycle.HiltViewModel
29 import javax.inject.Inject
30 import kotlinx.coroutines.CoroutineDispatcher
31 import kotlinx.coroutines.launch
32 
33 @HiltViewModel
34 class ConnectedAppsViewModel
35 @Inject
36 constructor(
37     private val loadHealthPermissionApps: ILoadHealthPermissionApps,
38     private val searchHealthPermissionApps: SearchHealthPermissionApps,
39     private val revokeAllHealthPermissionsUseCase: RevokeAllHealthPermissionsUseCase,
40     @IoDispatcher val ioDispatcher: CoroutineDispatcher
41 ) : ViewModel() {
42 
43     companion object {
44         private const val TAG = "ConnectedAppsViewModel"
45     }
46 
47     private val _connectedApps = MutableLiveData<List<ConnectedAppMetadata>>()
48     val connectedApps: LiveData<List<ConnectedAppMetadata>>
49         get() = _connectedApps
50 
51     private val _disconnectAllState =
52         MutableLiveData<DisconnectAllState>(DisconnectAllState.NotStarted)
53     val disconnectAllState: LiveData<DisconnectAllState>
54         get() = _disconnectAllState
55 
56     private val _alertDialogActive = MutableLiveData(false)
57     val alertDialogActive: LiveData<Boolean>
58         get() = _alertDialogActive
59 
60     init {
61         loadConnectedApps()
62     }
63 
64     fun setAlertDialogStatus(isActive: Boolean) {
65         _alertDialogActive.postValue(isActive)
66     }
67 
68     fun loadConnectedApps() {
69         viewModelScope.launch {
70             _connectedApps.postValueIfUpdated(loadHealthPermissionApps.invoke())
71         }
72     }
73 
74     fun searchConnectedApps(searchValue: String) {
75         viewModelScope.launch {
76             _connectedApps.postValueIfUpdated(
77                 searchHealthPermissionApps.search(loadHealthPermissionApps.invoke(), searchValue))
78         }
79     }
80 
81     fun disconnectAllApps(apps: List<ConnectedAppMetadata>): Boolean {
82         try {
83             viewModelScope.launch(ioDispatcher) {
84                 _disconnectAllState.postValue(DisconnectAllState.Loading)
85                 apps.forEach { app ->
86                     revokeAllHealthPermissionsUseCase.invoke(app.appMetadata.packageName)
87                 }
88                 loadConnectedApps()
89                 _disconnectAllState.postValue(DisconnectAllState.Updated)
90             }
91             _alertDialogActive.postValue(false)
92             return true
93         } catch (ex: Exception) {
94             Log.e(TAG, "Failed to update permissions!", ex)
95         }
96         _alertDialogActive.postValue(false)
97         return false
98     }
99 
100     sealed class DisconnectAllState {
101         object NotStarted : DisconnectAllState()
102 
103         object Loading : DisconnectAllState()
104 
105         object Updated : DisconnectAllState()
106     }
107 }
108