Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mobile network cell sensor #4380

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ import android.net.NetworkCapabilities
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.os.Build
import android.telephony.CellIdentityNr
import android.telephony.CellInfoCdma
import android.telephony.CellInfoGsm
import android.telephony.CellInfoLte
import android.telephony.CellInfoNr
import android.telephony.CellInfoTdscdma
import android.telephony.CellInfoWcdma
import android.telephony.TelephonyManager
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
Expand Down Expand Up @@ -141,6 +149,16 @@ class NetworkSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)
val cellConnection = SensorManager.BasicSensor(
"cell_connection",
"sensor",
commonR.string.basic_sensor_name_cell,
commonR.string.sensor_description_cell,
"mdi:radio-tower",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.WORKER
)

private const val SETTING_GET_CURRENT_BSSID = "network_get_current_bssid"
}

Expand All @@ -159,7 +177,7 @@ class NetworkSensorManager : SensorManager {
wifiFrequency,
wifiSignalStrength
)
val list = if (hasWifi(context)) {
val listWithWifi = if (hasWifi(context)) {
val withPublicIp = wifiSensors.plus(publicIp)
if (hasHotspot(context)) {
withPublicIp.plus(hotspotState)
Expand All @@ -169,6 +187,13 @@ class NetworkSensorManager : SensorManager {
} else {
listOf(publicIp)
}

val list = if (hasTelephony(context)) {
listWithWifi.plus(cellConnection)
} else {
listWithWifi
}

return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
list.plus(networkType).plus(ip6Addresses)
} else {
Expand Down Expand Up @@ -205,12 +230,17 @@ class NetworkSensorManager : SensorManager {
updateWifiFrequencySensor(context)
updateWifiSignalStrengthSensor(context)
updatePublicIpSensor(context)
updateCellConnectionSensor(context)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
updateNetworkType(context)
updateIP6Sensor(context)
}
}

private fun hasTelephony(context: Context): Boolean =
context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)

private fun hasWifi(context: Context): Boolean =
context.applicationContext.getSystemService<WifiManager>() != null

Expand Down Expand Up @@ -570,6 +600,97 @@ class NetworkSensorManager : SensorManager {
})
}

@SuppressLint("MissingPermission")
private fun updateCellConnectionSensor(context: Context) {
if (!isEnabled(context, cellConnection) || !hasTelephony(context)) {
return
}

val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

val cell = telephonyManager.getAllCellInfo().findLast { cell -> cell.isRegistered }

if (cell == null) {
onSensorUpdated(
context,
cellConnection,
STATE_UNAVAILABLE,
cellConnection.statelessIcon,
mapOf()
)
return
}

val radio: String
val mcc = telephonyManager.networkOperator.substring(0, 3) // extracting mcc and mnc from the networkOperator https://developer.android.com/reference/android/telephony/TelephonyManager#getNetworkOperator()
val mnc = telephonyManager.networkOperator.substring(3).toInt().toString()
val lac: String
val cid: String

val signalStrengthLevel: Int
val signalStrengthDbm: Int

if (cell is CellInfoGsm) {
radio = "GSM"
lac = cell.cellIdentity.lac.toString()
cid = cell.cellIdentity.cid.toString()
signalStrengthLevel = cell.cellSignalStrength.level
signalStrengthDbm = cell.cellSignalStrength.dbm
} else if (cell is CellInfoCdma) {
radio = "CDMA"
lac = cell.cellIdentity.networkId.toString()
cid = cell.cellIdentity.basestationId.toString()
signalStrengthLevel = cell.cellSignalStrength.level
signalStrengthDbm = cell.cellSignalStrength.dbm
} else if (cell is CellInfoWcdma) {
radio = "UMTS"
lac = cell.cellIdentity.lac.toString()
cid = cell.cellIdentity.cid.toString()
signalStrengthLevel = cell.cellSignalStrength.level
signalStrengthDbm = cell.cellSignalStrength.dbm
} else if (cell is CellInfoLte) {
radio = "LTE"
lac = cell.cellIdentity.tac.toString()
cid = cell.cellIdentity.ci.toString()
signalStrengthLevel = cell.cellSignalStrength.level
signalStrengthDbm = cell.cellSignalStrength.dbm
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && cell is CellInfoTdscdma) {
radio = "UTMS"
lac = cell.cellIdentity.lac.toString()
cid = cell.cellIdentity.cid.toString()
signalStrengthLevel = cell.cellSignalStrength.level
signalStrengthDbm = cell.cellSignalStrength.dbm
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && cell is CellInfoNr) {
radio = "NR"
lac = (cell.cellIdentity as CellIdentityNr).tac.toString()
cid = (cell.cellIdentity as CellIdentityNr).nci.toString()
signalStrengthLevel = cell.cellSignalStrength.level
signalStrengthDbm = cell.cellSignalStrength.dbm
} else {
onSensorUpdated(
context,
cellConnection,
STATE_UNKNOWN,
cellConnection.statelessIcon,
mapOf()
)
return
}

val cellId = "$radio:$mcc:$mnc:$lac:$cid"

onSensorUpdated(
context,
cellConnection,
cellId,
cellConnection.statelessIcon,
mapOf(
"signal_strength_dbm" to signalStrengthDbm,
"signal_strength_level" to signalStrengthLevel
)
)
}

@SuppressLint("MissingPermission")
@RequiresApi(Build.VERSION_CODES.M)
private fun updateNetworkType(context: Context) {
Expand Down
2 changes: 2 additions & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,8 @@
<string name="undo">Undo</string>
<string name="basic_sensor_name_network_type">Network type</string>
<string name="sensor_description_network_type">The type of transport the current active network is using</string>
<string name="basic_sensor_name_cell">Cell connection</string>
<string name="sensor_description_cell">The id of the mobile network cell the device is currently connected to</string>
<string name="sensor_name_volume_notification">Volume level notification</string>
<string name="sensor_description_volume_notification">Volume level for notifications on the device</string>
<string name="sensor_name_volume_system">Volume level system</string>
Expand Down