• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.statusbar.pipeline.wifi.shared.model
18 
19 import android.telephony.SubscriptionManager
20 import androidx.annotation.VisibleForTesting
21 import com.android.systemui.log.table.Diffable
22 import com.android.systemui.log.table.TableRowLogger
23 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
24 
25 /** Provides information about the current wifi network. */
26 sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
27 
28     // TODO(b/238425913): Have a better, more unified strategy for diff-logging instead of
29     //   copy-pasting the column names for each sub-object.
30 
31     /**
32      * A model representing that we couldn't fetch any wifi information.
33      *
34      * This is only used with [DisabledWifiRepository], where [WifiManager] is null.
35      */
36     object Unavailable : WifiNetworkModel() {
toStringnull37         override fun toString() = "WifiNetwork.Unavailable"
38         override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
39             if (prevVal is Unavailable) {
40                 return
41             }
42 
43             logFull(row)
44         }
45 
logFullnull46         override fun logFull(row: TableRowLogger) {
47             row.logChange(COL_NETWORK_TYPE, TYPE_UNAVAILABLE)
48             row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
49             row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
50             row.logChange(COL_VALIDATED, false)
51             row.logChange(COL_LEVEL, LEVEL_DEFAULT)
52             row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
53             row.logChange(COL_SSID, null)
54             row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
55             row.logChange(COL_ONLINE_SIGN_UP, false)
56             row.logChange(COL_PASSPOINT_NAME, null)
57         }
58     }
59 
60     /** A model representing that the wifi information we received was invalid in some way. */
61     data class Invalid(
62         /** A description of why the wifi information was invalid. */
63         val invalidReason: String,
64     ) : WifiNetworkModel() {
toStringnull65         override fun toString() = "WifiNetwork.Invalid[$invalidReason]"
66         override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
67             if (prevVal !is Invalid) {
68                 logFull(row)
69                 return
70             }
71 
72             if (invalidReason != prevVal.invalidReason) {
73                 row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
74             }
75         }
76 
logFullnull77         override fun logFull(row: TableRowLogger) {
78             row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
79             row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
80             row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
81             row.logChange(COL_VALIDATED, false)
82             row.logChange(COL_LEVEL, LEVEL_DEFAULT)
83             row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
84             row.logChange(COL_SSID, null)
85             row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
86             row.logChange(COL_ONLINE_SIGN_UP, false)
87             row.logChange(COL_PASSPOINT_NAME, null)
88         }
89     }
90 
91     /** A model representing that we have no active wifi network. */
92     object Inactive : WifiNetworkModel() {
toStringnull93         override fun toString() = "WifiNetwork.Inactive"
94 
95         override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
96             if (prevVal is Inactive) {
97                 return
98             }
99 
100             // When changing to Inactive, we need to log diffs to all the fields.
101             logFull(row)
102         }
103 
logFullnull104         override fun logFull(row: TableRowLogger) {
105             row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
106             row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
107             row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
108             row.logChange(COL_VALIDATED, false)
109             row.logChange(COL_LEVEL, LEVEL_DEFAULT)
110             row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
111             row.logChange(COL_SSID, null)
112             row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
113             row.logChange(COL_ONLINE_SIGN_UP, false)
114             row.logChange(COL_PASSPOINT_NAME, null)
115         }
116     }
117 
118     /**
119      * A model representing that our wifi network is actually a carrier merged network, meaning it's
120      * treated as more of a mobile network.
121      *
122      * See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
123      */
124     data class CarrierMerged(
125         /**
126          * The [android.net.Network.netId] we received from
127          * [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
128          *
129          * Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
130          */
131         val networkId: Int,
132 
133         /**
134          * The subscription ID that this connection represents.
135          *
136          * Comes from [android.net.wifi.WifiInfo.getSubscriptionId].
137          *
138          * Per that method, this value must not be [INVALID_SUBSCRIPTION_ID] (if it was invalid,
139          * then this is *not* a carrier merged network).
140          */
141         val subscriptionId: Int,
142 
143         /** The signal level, guaranteed to be 0 <= level <= numberOfLevels. */
144         val level: Int,
145 
146         /** The maximum possible level. */
147         val numberOfLevels: Int = MobileConnectionRepository.DEFAULT_NUM_LEVELS,
148     ) : WifiNetworkModel() {
149         init {
<lambda>null150             require(level in MIN_VALID_LEVEL..numberOfLevels) {
151                 "0 <= wifi level <= $numberOfLevels required; level was $level"
152             }
<lambda>null153             require(subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
154                 "subscription ID cannot be invalid"
155             }
156         }
157 
logDiffsnull158         override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
159             if (prevVal !is CarrierMerged) {
160                 logFull(row)
161                 return
162             }
163 
164             if (prevVal.networkId != networkId) {
165                 row.logChange(COL_NETWORK_ID, networkId)
166             }
167             if (prevVal.subscriptionId != subscriptionId) {
168                 row.logChange(COL_SUB_ID, subscriptionId)
169             }
170             if (prevVal.level != level) {
171                 row.logChange(COL_LEVEL, level)
172             }
173             if (prevVal.numberOfLevels != numberOfLevels) {
174                 row.logChange(COL_NUM_LEVELS, numberOfLevels)
175             }
176         }
177 
logFullnull178         override fun logFull(row: TableRowLogger) {
179             row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
180             row.logChange(COL_NETWORK_ID, networkId)
181             row.logChange(COL_SUB_ID, subscriptionId)
182             row.logChange(COL_VALIDATED, true)
183             row.logChange(COL_LEVEL, level)
184             row.logChange(COL_NUM_LEVELS, numberOfLevels)
185             row.logChange(COL_SSID, null)
186             row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
187             row.logChange(COL_ONLINE_SIGN_UP, false)
188             row.logChange(COL_PASSPOINT_NAME, null)
189         }
190     }
191 
192     /** Provides information about an active wifi network. */
193     data class Active(
194         /**
195          * The [android.net.Network.netId] we received from
196          * [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
197          *
198          * Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
199          */
200         val networkId: Int,
201 
202         /** See [android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED]. */
203         val isValidated: Boolean = false,
204 
205         /** The wifi signal level, guaranteed to be 0 <= level <= 4. */
206         val level: Int,
207 
208         /** See [android.net.wifi.WifiInfo.ssid]. */
209         val ssid: String? = null,
210 
211         /** See [android.net.wifi.WifiInfo.isPasspointAp]. */
212         val isPasspointAccessPoint: Boolean = false,
213 
214         /** See [android.net.wifi.WifiInfo.isOsuAp]. */
215         val isOnlineSignUpForPasspointAccessPoint: Boolean = false,
216 
217         /** See [android.net.wifi.WifiInfo.passpointProviderFriendlyName]. */
218         val passpointProviderFriendlyName: String? = null,
219     ) : WifiNetworkModel() {
220         init {
<lambda>null221             require(level in MIN_VALID_LEVEL..MAX_VALID_LEVEL) {
222                 "0 <= wifi level <= 4 required; level was $level"
223             }
224         }
225 
logDiffsnull226         override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
227             if (prevVal !is Active) {
228                 logFull(row)
229                 return
230             }
231 
232             if (prevVal.networkId != networkId) {
233                 row.logChange(COL_NETWORK_ID, networkId)
234             }
235             if (prevVal.isValidated != isValidated) {
236                 row.logChange(COL_VALIDATED, isValidated)
237             }
238             if (prevVal.level != level) {
239                 row.logChange(COL_LEVEL, level)
240             }
241             if (prevVal.ssid != ssid) {
242                 row.logChange(COL_SSID, ssid)
243             }
244 
245             // TODO(b/238425913): The passpoint-related values are frequently never used, so it
246             //   would be great to not log them when they're not used.
247             if (prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
248                 row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
249             }
250             if (
251                 prevVal.isOnlineSignUpForPasspointAccessPoint !=
252                     isOnlineSignUpForPasspointAccessPoint
253             ) {
254                 row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
255             }
256             if (prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
257                 row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
258             }
259         }
260 
logFullnull261         override fun logFull(row: TableRowLogger) {
262             row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
263             row.logChange(COL_NETWORK_ID, networkId)
264             row.logChange(COL_SUB_ID, null)
265             row.logChange(COL_VALIDATED, isValidated)
266             row.logChange(COL_LEVEL, level)
267             row.logChange(COL_NUM_LEVELS, null)
268             row.logChange(COL_SSID, ssid)
269             row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
270             row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
271             row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
272         }
273 
toStringnull274         override fun toString(): String {
275             // Only include the passpoint-related values in the string if we have them. (Most
276             // networks won't have them so they'll be mostly clutter.)
277             val passpointString =
278                 if (
279                     isPasspointAccessPoint ||
280                         isOnlineSignUpForPasspointAccessPoint ||
281                         passpointProviderFriendlyName != null
282                 ) {
283                     ", isPasspointAp=$isPasspointAccessPoint, " +
284                         "isOnlineSignUpForPasspointAp=$isOnlineSignUpForPasspointAccessPoint, " +
285                         "passpointName=$passpointProviderFriendlyName"
286                 } else {
287                     ""
288                 }
289 
290             return "WifiNetworkModel.Active(networkId=$networkId, isValidated=$isValidated, " +
291                 "level=$level, ssid=$ssid$passpointString)"
292         }
293 
294         companion object {
295             @VisibleForTesting internal const val MAX_VALID_LEVEL = 4
296         }
297     }
298 
299     companion object {
300         @VisibleForTesting internal const val MIN_VALID_LEVEL = 0
301     }
302 }
303 
304 const val TYPE_CARRIER_MERGED = "CarrierMerged"
305 const val TYPE_UNAVAILABLE = "Unavailable"
306 const val TYPE_INACTIVE = "Inactive"
307 const val TYPE_ACTIVE = "Active"
308 
309 const val COL_NETWORK_TYPE = "type"
310 const val COL_NETWORK_ID = "networkId"
311 const val COL_SUB_ID = "subscriptionId"
312 const val COL_VALIDATED = "isValidated"
313 const val COL_LEVEL = "level"
314 const val COL_NUM_LEVELS = "maxLevel"
315 const val COL_SSID = "ssid"
316 const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
317 const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
318 const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
319 
320 val LEVEL_DEFAULT: String? = null
321 val NUM_LEVELS_DEFAULT: String? = null
322 val NETWORK_ID_DEFAULT: String? = null
323 val SUB_ID_DEFAULT: String? = null
324