1 /*
2  * Copyright (C) 2021 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.connectivity
18 
19 import android.telephony.ServiceState
20 import android.telephony.SignalStrength
21 import android.telephony.TelephonyDisplayInfo
22 import android.telephony.TelephonyManager
23 import com.android.settingslib.Utils
24 import com.android.settingslib.mobile.MobileStatusTracker.MobileStatus
25 import com.android.settingslib.mobile.TelephonyIcons
26 import java.lang.IllegalArgumentException
27 
28 /**
29  * Box for all policy-related state used in [MobileSignalController]
30  */
31 internal class MobileState(
32     @JvmField var networkName: String? = null,
33     @JvmField var networkNameData: String? = null,
34     @JvmField var dataSim: Boolean = false,
35     @JvmField var dataConnected: Boolean = false,
36     @JvmField var isEmergency: Boolean = false,
37     @JvmField var airplaneMode: Boolean = false,
38     @JvmField var carrierNetworkChangeMode: Boolean = false,
39     @JvmField var isDefault: Boolean = false,
40     @JvmField var userSetup: Boolean = false,
41     @JvmField var roaming: Boolean = false,
42     @JvmField var dataState: Int = TelephonyManager.DATA_DISCONNECTED,
43     // Tracks the on/off state of the defaultDataSubscription
44     @JvmField var defaultDataOff: Boolean = false
45 ) : ConnectivityState() {
46 
47     @JvmField var telephonyDisplayInfo = TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
48             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)
49     @JvmField var serviceState: ServiceState? = null
50     @JvmField var signalStrength: SignalStrength? = null
51 
52     /** @return true if this state is disabled or not default data */
53     val isDataDisabledOrNotDefault: Boolean
54         get() = (iconGroup === TelephonyIcons.DATA_DISABLED ||
55                 iconGroup === TelephonyIcons.NOT_DEFAULT_DATA) && userSetup
56 
57     /** @return if this state is considered to have inbound activity */
58     fun hasActivityIn(): Boolean {
59         return dataConnected && !carrierNetworkChangeMode && activityIn
60     }
61 
62     /** @return if this state is considered to have outbound activity */
63     fun hasActivityOut(): Boolean {
64         return dataConnected && !carrierNetworkChangeMode && activityOut
65     }
66 
67     /** @return true if this state should show a RAT icon in quick settings */
68     fun showQuickSettingsRatIcon(): Boolean {
69         return dataConnected || isDataDisabledOrNotDefault
70     }
71 
72     override fun copyFrom(other: ConnectivityState) {
73         val o = other as? MobileState ?: throw IllegalArgumentException(
74                 "MobileState can only update from another MobileState")
75 
76         super.copyFrom(o)
77         networkName = o.networkName
78         networkNameData = o.networkNameData
79         dataSim = o.dataSim
80         dataConnected = o.dataConnected
81         isEmergency = o.isEmergency
82         airplaneMode = o.airplaneMode
83         carrierNetworkChangeMode = o.carrierNetworkChangeMode
84         isDefault = o.isDefault
85         userSetup = o.userSetup
86         roaming = o.roaming
87         dataState = o.dataState
88         defaultDataOff = o.defaultDataOff
89 
90         telephonyDisplayInfo = o.telephonyDisplayInfo
91         serviceState = o.serviceState
92         signalStrength = o.signalStrength
93     }
94 
95     fun isDataConnected(): Boolean {
96         return connected && dataState == TelephonyManager.DATA_CONNECTED
97     }
98 
99     /** @return the current voice service state, or -1 if null */
100     fun getVoiceServiceState(): Int {
101         return serviceState?.state ?: -1
102     }
103 
104     fun isNoCalling(): Boolean {
105         return serviceState?.state != ServiceState.STATE_IN_SERVICE
106     }
107 
108     fun getOperatorAlphaShort(): String {
109         return serviceState?.operatorAlphaShort ?: ""
110     }
111 
112     fun isCdma(): Boolean {
113         return signalStrength != null && !signalStrength!!.isGsm
114     }
115 
116     fun isEmergencyOnly(): Boolean {
117         return serviceState != null && serviceState!!.isEmergencyOnly
118     }
119 
120     fun isInService(): Boolean {
121         return Utils.isInService(serviceState)
122     }
123 
124     fun isRoaming(): Boolean {
125         return serviceState != null && serviceState!!.roaming
126     }
127 
128     fun setFromMobileStatus(mobileStatus: MobileStatus) {
129         activityIn = mobileStatus.activityIn
130         activityOut = mobileStatus.activityOut
131         dataSim = mobileStatus.dataSim
132         carrierNetworkChangeMode = mobileStatus.carrierNetworkChangeMode
133         dataState = mobileStatus.dataState
134         signalStrength = mobileStatus.signalStrength
135         telephonyDisplayInfo = mobileStatus.telephonyDisplayInfo
136         serviceState = mobileStatus.serviceState
137     }
138 
139     override fun toString(builder: StringBuilder) {
140         super.toString(builder)
141         builder.append(',')
142         builder.append("dataSim=$dataSim,")
143         builder.append("networkName=$networkName,")
144         builder.append("networkNameData=$networkNameData,")
145         builder.append("dataConnected=$dataConnected,")
146         builder.append("roaming=$roaming,")
147         builder.append("isDefault=$isDefault,")
148         builder.append("isEmergency=$isEmergency,")
149         builder.append("airplaneMode=$airplaneMode,")
150         builder.append("carrierNetworkChangeMode=$carrierNetworkChangeMode,")
151         builder.append("userSetup=$userSetup,")
152         builder.append("dataState=$dataState,")
153         builder.append("defaultDataOff=$defaultDataOff,")
154 
155         // Computed properties
156         builder.append("showQuickSettingsRatIcon=${showQuickSettingsRatIcon()},")
157         builder.append("voiceServiceState=${getVoiceServiceState()},")
158         builder.append("isInService=${isInService()},")
159 
160         builder.append("serviceState=${serviceState?.minLog() ?: "(null)"},")
161         builder.append("signalStrength=${signalStrength?.minLog() ?: "(null)"},")
162         builder.append("displayInfo=$telephonyDisplayInfo")
163     }
164 
165     override fun equals(other: Any?): Boolean {
166         if (this === other) return true
167         if (javaClass != other?.javaClass) return false
168         if (!super.equals(other)) return false
169 
170         other as MobileState
171 
172         if (networkName != other.networkName) return false
173         if (networkNameData != other.networkNameData) return false
174         if (dataSim != other.dataSim) return false
175         if (dataConnected != other.dataConnected) return false
176         if (isEmergency != other.isEmergency) return false
177         if (airplaneMode != other.airplaneMode) return false
178         if (carrierNetworkChangeMode != other.carrierNetworkChangeMode) return false
179         if (isDefault != other.isDefault) return false
180         if (userSetup != other.userSetup) return false
181         if (roaming != other.roaming) return false
182         if (dataState != other.dataState) return false
183         if (defaultDataOff != other.defaultDataOff) return false
184         if (telephonyDisplayInfo != other.telephonyDisplayInfo) return false
185         if (serviceState != other.serviceState) return false
186         if (signalStrength != other.signalStrength) return false
187 
188         return true
189     }
190 
191     override fun hashCode(): Int {
192         var result = super.hashCode()
193         result = 31 * result + (networkName?.hashCode() ?: 0)
194         result = 31 * result + (networkNameData?.hashCode() ?: 0)
195         result = 31 * result + dataSim.hashCode()
196         result = 31 * result + dataConnected.hashCode()
197         result = 31 * result + isEmergency.hashCode()
198         result = 31 * result + airplaneMode.hashCode()
199         result = 31 * result + carrierNetworkChangeMode.hashCode()
200         result = 31 * result + isDefault.hashCode()
201         result = 31 * result + userSetup.hashCode()
202         result = 31 * result + roaming.hashCode()
203         result = 31 * result + dataState
204         result = 31 * result + defaultDataOff.hashCode()
205         result = 31 * result + telephonyDisplayInfo.hashCode()
206         result = 31 * result + (serviceState?.hashCode() ?: 0)
207         result = 31 * result + (signalStrength?.hashCode() ?: 0)
208         return result
209     }
210 }
211 
212 /** toString() is a little more verbose than we need. Just log the fields we read */
213 private fun ServiceState.minLog(): String {
214     return "serviceState={" +
215             "state=$state," +
216             "isEmergencyOnly=$isEmergencyOnly," +
217             "roaming=$roaming," +
218             "operatorNameAlphaShort=$operatorAlphaShort}"
219 }
220 
221 private fun SignalStrength.minLog(): String {
222     return "signalStrength={" +
223             "isGsm=$isGsm," +
224             "level=$level}"
225 }
226