• 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");
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.statusbar.pipeline.mobile.ui.binder
18 
19 import android.content.res.ColorStateList
20 import android.view.View
21 import android.view.View.GONE
22 import android.view.View.INVISIBLE
23 import android.view.View.VISIBLE
24 import android.view.ViewGroup
25 import android.widget.ImageView
26 import android.widget.Space
27 import androidx.core.view.isVisible
28 import androidx.lifecycle.Lifecycle
29 import androidx.lifecycle.repeatOnLifecycle
30 import com.android.settingslib.graph.SignalDrawable
31 import com.android.systemui.R
32 import com.android.systemui.common.ui.binder.ContentDescriptionViewBinder
33 import com.android.systemui.common.ui.binder.IconViewBinder
34 import com.android.systemui.lifecycle.repeatWhenAttached
35 import com.android.systemui.statusbar.StatusBarIconView
36 import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
37 import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
38 import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
39 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
40 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
41 import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
42 import kotlinx.coroutines.awaitCancellation
43 import kotlinx.coroutines.flow.MutableStateFlow
44 import kotlinx.coroutines.flow.distinctUntilChanged
45 import kotlinx.coroutines.launch
46 
47 object MobileIconBinder {
48     /** Binds the view to the view-model, continuing to update the former based on the latter */
49     @JvmStatic
50     fun bind(
51         view: ViewGroup,
52         viewModel: LocationBasedMobileViewModel,
53         logger: MobileViewLogger,
54     ): ModernStatusBarViewBinding {
55         val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
56         val activityContainer = view.requireViewById<View>(R.id.inout_container)
57         val activityIn = view.requireViewById<ImageView>(R.id.mobile_in)
58         val activityOut = view.requireViewById<ImageView>(R.id.mobile_out)
59         val networkTypeView = view.requireViewById<ImageView>(R.id.mobile_type)
60         val iconView = view.requireViewById<ImageView>(R.id.mobile_signal)
61         val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
62         val roamingView = view.requireViewById<ImageView>(R.id.mobile_roaming)
63         val roamingSpace = view.requireViewById<Space>(R.id.mobile_roaming_space)
64         val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
65 
66         view.isVisible = true
67         iconView.isVisible = true
68 
69         // TODO(b/238425913): We should log this visibility state.
70         @StatusBarIconView.VisibleState
71         val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
72 
73         val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
74         val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
75 
76         var isCollecting: Boolean = false
77 
78         view.repeatWhenAttached {
79             repeatOnLifecycle(Lifecycle.State.STARTED) {
80                 logger.logCollectionStarted(view, viewModel)
81                 isCollecting = true
82 
83                 launch {
84                     visibilityState.collect { state ->
85                         when (state) {
86                             STATE_ICON -> {
87                                 mobileGroupView.visibility = VISIBLE
88                                 dotView.visibility = GONE
89                             }
90                             STATE_DOT -> {
91                                 mobileGroupView.visibility = INVISIBLE
92                                 dotView.visibility = VISIBLE
93                             }
94                             STATE_HIDDEN -> {
95                                 mobileGroupView.visibility = INVISIBLE
96                                 dotView.visibility = INVISIBLE
97                             }
98                         }
99                     }
100                 }
101 
102                 launch { viewModel.isVisible.collect { isVisible -> view.isVisible = isVisible } }
103 
104                 // Set the icon for the triangle
105                 launch {
106                     viewModel.icon.distinctUntilChanged().collect { icon ->
107                         viewModel.verboseLogger?.logBinderReceivedSignalIcon(
108                             view,
109                             viewModel.subscriptionId,
110                             icon,
111                         )
112                         mobileDrawable.level =
113                             SignalDrawable.getState(
114                                 icon.level,
115                                 icon.numberOfLevels,
116                                 icon.showExclamationMark,
117                             )
118                     }
119                 }
120 
121                 launch {
122                     viewModel.contentDescription.distinctUntilChanged().collect {
123                         ContentDescriptionViewBinder.bind(it, view)
124                     }
125                 }
126 
127                 // Set the network type icon
128                 launch {
129                     viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
130                         viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
131                             view,
132                             viewModel.subscriptionId,
133                             dataTypeId,
134                         )
135                         dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
136                         networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
137                     }
138                 }
139 
140                 // Set the roaming indicator
141                 launch {
142                     viewModel.roaming.distinctUntilChanged().collect { isRoaming ->
143                         roamingView.isVisible = isRoaming
144                         roamingSpace.isVisible = isRoaming
145                     }
146                 }
147 
148                 // Set the activity indicators
149                 launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
150 
151                 launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
152 
153                 launch {
154                     viewModel.activityContainerVisible.collect { activityContainer.isVisible = it }
155                 }
156 
157                 // Set the tint
158                 launch {
159                     iconTint.collect { tint ->
160                         val tintList = ColorStateList.valueOf(tint)
161                         iconView.imageTintList = tintList
162                         networkTypeView.imageTintList = tintList
163                         roamingView.imageTintList = tintList
164                         activityIn.imageTintList = tintList
165                         activityOut.imageTintList = tintList
166                         dotView.setDecorColor(tint)
167                     }
168                 }
169 
170                 launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
171 
172                 try {
173                     awaitCancellation()
174                 } finally {
175                     isCollecting = false
176                     logger.logCollectionStopped(view, viewModel)
177                 }
178             }
179         }
180 
181         return object : ModernStatusBarViewBinding {
182             override fun getShouldIconBeVisible(): Boolean {
183                 return viewModel.isVisible.value
184             }
185 
186             override fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) {
187                 visibilityState.value = state
188             }
189 
190             override fun onIconTintChanged(newTint: Int) {
191                 if (viewModel.useDebugColoring) {
192                     return
193                 }
194                 iconTint.value = newTint
195             }
196 
197             override fun onDecorTintChanged(newTint: Int) {
198                 if (viewModel.useDebugColoring) {
199                     return
200                 }
201                 decorTint.value = newTint
202             }
203 
204             override fun isCollecting(): Boolean {
205                 return isCollecting
206             }
207         }
208     }
209 }
210