summaryrefslogtreecommitdiffstats
path: root/app/src/main/java
diff options
context:
space:
mode:
authorbt <bt@rctt.net>2026-05-26 23:13:08 +0200
committerbt <bt@rctt.net>2026-05-26 23:19:53 +0200
commite787e83e781c999c0555e1db5e99ac5685a84536 (patch)
treeaceb345ceb4db66c9f1db99085f215b7a3021ef2 /app/src/main/java
parente81ce6af3d97a51e51f676f32e739d0f174323c7 (diff)
downloadnetmon-e787e83e781c999c0555e1db5e99ac5685a84536.tar.gz
netmon-e787e83e781c999c0555e1db5e99ac5685a84536.zip
Load netmonitor CSV database and show cells descriptions
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/net/rctt/netmon/CellDbItem.kt31
-rw-r--r--app/src/main/java/net/rctt/netmon/CellView.kt9
-rw-r--r--app/src/main/java/net/rctt/netmon/MainActivity.kt93
3 files changed, 121 insertions, 12 deletions
diff --git a/app/src/main/java/net/rctt/netmon/CellDbItem.kt b/app/src/main/java/net/rctt/netmon/CellDbItem.kt
new file mode 100644
index 0000000..2922bb1
--- /dev/null
+++ b/app/src/main/java/net/rctt/netmon/CellDbItem.kt
@@ -0,0 +1,31 @@
+package net.rctt.netmon
+
+// NETWORK_TYPE;MCC;MNC;LAC;CID;PSC;CHANNEL;LATITUDE;LONGITUDE;ACCURACY;DESCRIPTION
+
+/*
+NETWORK_TYPE String C (CDMA), G (GSM), W (WCDMA), T (TDSCDMA), L (LTE), N (5G NR) Mandatory for CDMA
+MCC String 3 digits Mandatory
+MNC String 2 or 3 digits Mandatory
+LAC Int NID (CDMA), LAC (GSM, WCDMA, TDSCDMA), TAC (LTE, 5G NR) Mandatory
+CID Long BID (CDMA), CID (GSM, WCDMA, TDSCDMA), CI (LTE), NCI (5G NR) Mandatory
+PSC Int SID (CDMA), BSIC (GSM), PSC (WCDMA), CPID (TDSCDMA), PCI (LTE, 5G NR) Mandatory for CDMA
+CHANNEL Int ARFCN (GSM, 5G NR), UARFCN (WCDMA, TDSCDMA), EARFCN (LTE)
+LATITUDE Double [-90;90], . as separator
+LONGITUDE Double [-180;180], . as separator
+ACCURACY Int in meters
+DESCRIPTION String text
+*/
+
+class CellDbItem {
+ var Type: String = ""
+ var MCC: String = ""
+ var MNC: String = ""
+ var LAC: Int = 0
+ var CID: Long = 0
+ var PSC: Int = 0
+ var Channel: Int = 0
+ var Latitude: Double = 0.0
+ var Longitude: Double = 0.0
+ var Accuracy: Int = 0
+ var Description: String = ""
+} \ No newline at end of file
diff --git a/app/src/main/java/net/rctt/netmon/CellView.kt b/app/src/main/java/net/rctt/netmon/CellView.kt
index d991d48..051f05a 100644
--- a/app/src/main/java/net/rctt/netmon/CellView.kt
+++ b/app/src/main/java/net/rctt/netmon/CellView.kt
@@ -23,6 +23,8 @@ class CellView : ConstraintLayout{
var typeView: TextView
var idView: TextView
var powerView: TextView
+ var descView: TextView
+
var powerChartView: XYPlot
var powerChartSeries: SimpleXYSeries
@@ -34,6 +36,7 @@ class CellView : ConstraintLayout{
typeView = findViewById(R.id.type)
idView = findViewById(R.id.id)
powerView = findViewById(R.id.power)
+ descView = findViewById(R.id.desc)
powerChartView = findViewById(R.id.power_chart)
powerHistory = mutableListOf()
powerChartSeries= SimpleXYSeries(
@@ -76,6 +79,10 @@ class CellView : ConstraintLayout{
powerView.text = power.toString()
}
+ fun setDesc(desc: String) {
+ descView.text = desc
+ }
+
fun refresh() {
powerChartView.removeSeries(powerChartSeries)
@@ -96,8 +103,6 @@ class CellView : ConstraintLayout{
val series1Format = LineAndPointFormatter(Color.RED, Color.GREEN, Color.BLUE, null)
- Log.d("ASD", seriesData.toString())
-
powerChartView.addSeries(powerChartSeries, series1Format)
}
diff --git a/app/src/main/java/net/rctt/netmon/MainActivity.kt b/app/src/main/java/net/rctt/netmon/MainActivity.kt
index bc0f136..66d77c6 100644
--- a/app/src/main/java/net/rctt/netmon/MainActivity.kt
+++ b/app/src/main/java/net/rctt/netmon/MainActivity.kt
@@ -14,6 +14,7 @@ import android.telephony.CellInfoTdscdma
import android.telephony.CellInfoWcdma
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.CellInfoCallback
+import android.util.Log
import android.widget.LinearLayout
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
@@ -22,6 +23,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import com.jsoizo.kotlincsv.CsvDialect
+import com.jsoizo.kotlincsv.csvReader
+import com.jsoizo.kotlincsv.reader.readFromFile
+import java.io.File
+import java.io.IOException
+import java.lang.reflect.Type
import java.text.SimpleDateFormat
import java.util.Date
@@ -29,6 +36,7 @@ class MainActivity : AppCompatActivity() {
lateinit var cellsListView: LinearLayout
lateinit var tel: TelephonyManager
lateinit var cellsList: HashMap<Number, CellView>
+ val cellDb = HashMap<Int, HashMap<Long, CellDbItem>>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -40,6 +48,8 @@ class MainActivity : AppCompatActivity() {
insets
}
+ loadDb()
+
cellsList = HashMap()
cellsListView = findViewById(R.id.cellsList)
@@ -56,13 +66,53 @@ class MainActivity : AppCompatActivity() {
})
}
+ fun loadDb() {
+ val reader = csvReader {
+ dialect = CsvDialect(delimiter = ';')
+ }
+
+ reader.readFromFile(File("/storage/emulated/0/cells.csv")) { rows ->
+ rows.forEach {
+ val item = CellDbItem()
+ item.Type = it.elementAt(0)
+ item.MCC = it.elementAt(1)
+ item.MNC = it.elementAt(2)
+ item.LAC = it.elementAt(3).toInt()
+ item.CID = it.elementAt(4).toLong()
+ if (it.elementAt(5) != "") {
+ item.PSC = it.elementAt(5).toInt()
+ }
+ if (it.elementAt(6) != "") {
+ item.Channel = it.elementAt(6).toInt()
+ }
+ item.Latitude = it.elementAt(7).toDouble()
+ item.Longitude = it.elementAt(8).toDouble()
+ if (it.elementAt(9) != "") {
+ item.Accuracy = it.elementAt(9).toInt()
+ }
+ item.Description = it.elementAt(10)
+
+ var lac = cellDb[item.LAC]
+ if (lac == null) {
+ cellDb[item.LAC] = HashMap()
+ lac = cellDb[item.LAC]
+ }
+
+ lac?.set(item.CID, item)
+ }
+ }
+ }
+
+ fun findInDb(lac: Int, cid: Long): CellDbItem? {
+ return cellDb[lac]?.get(cid)
+ }
+
@RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
fun refresh() {
tel.requestCellInfoUpdate(mainExecutor, object : CellInfoCallback() {
@RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
override fun onCellInfo(cellList: List<CellInfo?>) {
cellsListView.removeAllViews()
-
for (cell in cellList) {
if (cell == null) {
continue
@@ -74,35 +124,58 @@ class MainActivity : AppCompatActivity() {
}
@SuppressLint("SetTextI18n")
- fun addCellView(cell :CellInfo){
+ fun addCellView(cell: CellInfo) {
val id = getCellId(cell)
+ if (id == 65535 || id == 2147483647) {
+ return
+ }
+
+ val lac = getCellLac(cell)
+ val findInDb = findInDb(lac.toInt(), id.toLong())
+ val desc = findInDb?.Description ?: ""
+
var cellView = cellsList[id]
if (cellView == null) {
cellView = CellView(this, id)
cellsList[id] = cellView
+ } else {
+ cellsListView.removeView(cellView)
}
when (cell) {
is CellInfoGsm -> cellView.set(cell)
- is CellInfoLte -> cellView.set(cell)
- is CellInfoNr -> cellView.set(cell)
- is CellInfoTdscdma -> cellView.set(cell)
- is CellInfoWcdma -> cellView.set(cell)
+ is CellInfoLte -> cellView.set(cell)
+ is CellInfoNr -> cellView.set(cell)
+ is CellInfoTdscdma -> cellView.set(cell)
+ is CellInfoWcdma -> cellView.set(cell)
}
cellView.refresh()
+ cellView.setDesc(desc)
cellsListView.addView(cellView)
}
}
-fun getCellId(cell: CellInfo) : Number {
+fun getCellId(cell: CellInfo): Number {
when (cell) {
is CellInfoGsm -> return cell.cellIdentity.cid
- is CellInfoLte -> return cell.cellIdentity.ci
- is CellInfoNr -> return (cell.cellIdentity as CellIdentityNr).nci
- is CellInfoTdscdma -> return cell.cellIdentity.cid
+ is CellInfoLte -> return cell.cellIdentity.ci
+ is CellInfoNr -> return (cell.cellIdentity as CellIdentityNr).nci
+ is CellInfoTdscdma -> return cell.cellIdentity.cid
is CellInfoWcdma -> return cell.cellIdentity.cid
}
return 0
+}
+
+fun getCellLac(cell: CellInfo): Number {
+ when (cell) {
+ is CellInfoGsm -> return cell.cellIdentity.lac
+ is CellInfoLte -> return cell.cellIdentity.tac
+ is CellInfoNr -> return (cell.cellIdentity as CellIdentityNr).tac
+ is CellInfoTdscdma -> return cell.cellIdentity.lac
+ is CellInfoWcdma -> return cell.cellIdentity.lac
+ }
+
+ return 0
} \ No newline at end of file