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.ui.model
18 
19 import android.annotation.DrawableRes
20 import android.content.Context
21 import androidx.annotation.StringRes
22 import androidx.annotation.VisibleForTesting
23 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
24 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
25 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
26 import com.android.systemui.common.shared.model.ContentDescription
27 import com.android.systemui.common.shared.model.Icon
28 import com.android.systemui.log.table.Diffable
29 import com.android.systemui.log.table.TableRowLogger
30 import com.android.systemui.res.R
31 import com.android.systemui.statusbar.connectivity.WifiIcons
32 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
33 
34 /** Represents the various states of the wifi icon. */
35 sealed interface WifiIcon : Diffable<WifiIcon> {
36     /** Represents a wifi icon that should be hidden (not visible). */
37     object Hidden : WifiIcon {
toStringnull38         override fun toString() = "hidden"
39     }
40 
41     /**
42      * Represents a visible wifi icon that uses [res] as its image and [contentDescription] as its
43      * description.
44      */
45     class Visible(
46         @DrawableRes val res: Int,
47         val contentDescription: ContentDescription.Loaded,
48     ) : WifiIcon {
49         val icon = Icon.Resource(res, contentDescription)
50 
51         override fun toString() = contentDescription.description.toString()
52     }
53 
logDiffsnull54     override fun logDiffs(prevVal: WifiIcon, row: TableRowLogger) {
55         if (prevVal.toString() != toString()) {
56             row.logChange(COL_ICON, toString())
57         }
58     }
59 
logFullnull60     override fun logFull(row: TableRowLogger) {
61         row.logChange(COL_ICON, toString())
62     }
63 
64     companion object {
65         @StringRes
66         @VisibleForTesting
67         internal val NO_INTERNET = R.string.data_connection_no_internet
68 
69         /**
70          * Mapping from a [WifiNetworkModel] to the appropriate [WifiIcon].
71          *
72          * @param showHotspotInfo true if the wifi icon should represent the hotspot device (if it
73          *   exists) and false if the wifi icon should only ever show the wifi level and *not* the
74          *   hotspot device.
75          */
fromModelnull76         fun fromModel(
77             model: WifiNetworkModel,
78             context: Context,
79             showHotspotInfo: Boolean,
80         ): WifiIcon =
81             when (model) {
82                 is WifiNetworkModel.Unavailable -> Hidden
83                 is WifiNetworkModel.Invalid -> Hidden
84                 is WifiNetworkModel.CarrierMerged -> Hidden
85                 is WifiNetworkModel.Inactive ->
86                     Visible(
87                         res = WifiIcons.WIFI_NO_NETWORK,
88                         ContentDescription.Loaded(
89                             "${context.getString(WIFI_NO_CONNECTION)},${context.getString(
90                                 NO_INTERNET
91                             )}"
92                         )
93                     )
94                 is WifiNetworkModel.Active -> model.toIcon(showHotspotInfo, context)
95             }
96 
toIconnull97         private fun WifiNetworkModel.Active.toIcon(
98             showHotspotInfo: Boolean,
99             context: Context,
100         ): Visible {
101             return if (
102                 !showHotspotInfo ||
103                     this.hotspotDeviceType == WifiNetworkModel.HotspotDeviceType.NONE
104             ) {
105                 this.toBasicIcon(context)
106             } else {
107                 val icon =
108                     when (this.hotspotDeviceType) {
109                         WifiNetworkModel.HotspotDeviceType.TABLET ->
110                             com.android.settingslib.R.drawable.ic_hotspot_tablet
111                         WifiNetworkModel.HotspotDeviceType.LAPTOP ->
112                             com.android.settingslib.R.drawable.ic_hotspot_laptop
113                         WifiNetworkModel.HotspotDeviceType.WATCH ->
114                             com.android.settingslib.R.drawable.ic_hotspot_watch
115                         WifiNetworkModel.HotspotDeviceType.AUTO ->
116                             com.android.settingslib.R.drawable.ic_hotspot_auto
117                         // Use phone as the default drawable
118                         WifiNetworkModel.HotspotDeviceType.PHONE,
119                         WifiNetworkModel.HotspotDeviceType.UNKNOWN,
120                         WifiNetworkModel.HotspotDeviceType.INVALID ->
121                             com.android.settingslib.R.drawable.ic_hotspot_phone
122                         WifiNetworkModel.HotspotDeviceType.NONE ->
123                             throw IllegalStateException("NONE checked earlier")
124                     }
125                 Visible(
126                     icon,
127                     ContentDescription.Loaded(context.getString(WIFI_OTHER_DEVICE_CONNECTION)),
128                 )
129             }
130         }
131 
toBasicIconnull132         private fun WifiNetworkModel.Active.toBasicIcon(context: Context): Visible {
133             val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
134             return if (this.isValidated) {
135                 Visible(
136                     WifiIcons.WIFI_FULL_ICONS[this.level],
137                     ContentDescription.Loaded(levelDesc),
138                 )
139             } else {
140                 Visible(
141                     WifiIcons.WIFI_NO_INTERNET_ICONS[this.level],
142                     ContentDescription.Loaded("$levelDesc,${context.getString(NO_INTERNET)}"),
143                 )
144             }
145         }
146     }
147 }
148 
149 private const val COL_ICON = "icon"
150