1 /*
2  * Copyright (C) 2022 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  *      http://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 package com.android.systemui.bouncer.ui.viewmodel
18 
19 import android.view.View
20 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
21 import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
22 import com.android.systemui.bouncer.ui.BouncerView
23 import com.android.systemui.bouncer.ui.BouncerViewDelegate
24 import javax.inject.Inject
25 import kotlinx.coroutines.flow.Flow
26 import kotlinx.coroutines.flow.filterNotNull
27 import kotlinx.coroutines.flow.map
28 import kotlinx.coroutines.flow.merge
29 
30 /** Models UI state for the lock screen bouncer; handles user input. */
31 class KeyguardBouncerViewModel
32 @Inject
33 constructor(
34     private val view: BouncerView,
35     private val interactor: PrimaryBouncerInteractor,
36 ) {
37     /** Observe on bouncer expansion amount. */
38     val bouncerExpansionAmount: Flow<Float> = interactor.panelExpansionAmount
39 
40     /** Can the user interact with the view? */
41     val isInteractable: Flow<Boolean> = interactor.isInteractable
42 
43     /** Observe whether bouncer is showing or not. */
44     val isShowing: Flow<Boolean> = interactor.isShowing
45 
46     /** Observe whether bouncer is starting to hide. */
47     val startingToHide: Flow<Unit> = interactor.startingToHide
48 
49     /** Observe whether we want to start the disappear animation. */
50     val startDisappearAnimation: Flow<Runnable> = interactor.startingDisappearAnimation
51 
52     /** Observe whether we want to update keyguard position. */
53     val keyguardPosition: Flow<Float> = interactor.keyguardPosition
54 
55     /** Observe whether we want to update resources. */
56     val updateResources: Flow<Boolean> = interactor.resourceUpdateRequests
57 
58     /** Observe whether we want to set a keyguard message when the bouncer shows. */
59     val bouncerShowMessage: Flow<BouncerShowMessageModel> = interactor.showMessage
60 
61     /** Observe whether keyguard is authenticated already. */
62     val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticated
63 
64     /** Observe whether the side fps is showing. */
65     val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
66 
67     /** Observe whether we should update fps is showing. */
68     val shouldUpdateSideFps: Flow<Unit> =
69         merge(
70             interactor.isShowing.map {},
71             interactor.startingToHide,
72             interactor.startingDisappearAnimation.filterNotNull().map {}
73         )
74 
75     /** Observe whether we want to update resources. */
76     fun notifyUpdateResources() {
77         interactor.notifyUpdatedResources()
78     }
79 
80     /** Notify that keyguard authenticated was handled */
81     fun notifyKeyguardAuthenticated() {
82         interactor.notifyKeyguardAuthenticatedHandled()
83     }
84 
85     /** Notifies that the message was shown. */
86     fun onMessageShown() {
87         interactor.onMessageShown()
88     }
89 
90     fun updateSideFpsVisibility() {
91         interactor.updateSideFpsVisibility()
92     }
93 
94     /** Observe whether back button is enabled. */
95     fun observeOnIsBackButtonEnabled(systemUiVisibility: () -> Int): Flow<Int> {
96         return interactor.isBackButtonEnabled.map { enabled ->
97             var vis: Int = systemUiVisibility()
98             vis =
99                 if (enabled) {
100                     vis and View.STATUS_BAR_DISABLE_BACK.inv()
101                 } else {
102                     vis or View.STATUS_BAR_DISABLE_BACK
103                 }
104             vis
105         }
106     }
107 
108     /** Set an abstraction that will hold reference to the ui delegate for the bouncer view. */
109     fun setBouncerViewDelegate(delegate: BouncerViewDelegate?) {
110         view.delegate = delegate
111     }
112 }
113