summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.idea/deploymentTargetSelector.xml2
-rw-r--r--app/build.gradle.kts1
-rw-r--r--app/src/main/AndroidManifest.xml4
-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
-rw-r--r--app/src/main/res/layout/cell_view.xml111
7 files changed, 188 insertions, 63 deletions
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index df74897..d8efab0 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -4,7 +4,7 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
- <DropdownSelection timestamp="2026-05-03T01:02:55.812002Z">
+ <DropdownSelection timestamp="2026-05-26T17:28:03.850871Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=47111JEKB06200" />
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index a5348d6..c04b900 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -51,4 +51,5 @@ dependencies {
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation("com.androidplot:androidplot-core:1.5.11")
+ implementation("com.jsoizo:kotlin-csv:2.0.0")
} \ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f8bbdd0..32d8332 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,8 +5,12 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
+ android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
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
diff --git a/app/src/main/res/layout/cell_view.xml b/app/src/main/res/layout/cell_view.xml
index 7361930..916f8cc 100644
--- a/app/src/main/res/layout/cell_view.xml
+++ b/app/src/main/res/layout/cell_view.xml
@@ -13,73 +13,84 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<LinearLayout
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginEnd="10dp"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Type" />
+ android:orientation="horizontal">
- <TextView
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Id" />
+ android:layout_marginEnd="10dp"
+ android:orientation="vertical">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Power" />
-
- </LinearLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Type" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Id" />
- <TextView
- android:id="@+id/type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="type" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Power" />
- <TextView
- android:id="@+id/id"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="id" />
+ </LinearLayout>
- <TextView
- android:id="@+id/power"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="power" />
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="type" />
+
+ <TextView
+ android:id="@+id/id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="id" />
+
+ <TextView
+ android:id="@+id/power"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="power" />
+
+ </LinearLayout>
+
+ <com.androidplot.xy.XYPlot
+ android:id="@+id/power_chart"
+ style="@style/APDefacto.Dark"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="10dp"
+ ap:graphHeightMode="fill"
+ ap:graphMarginBottom="-20dp"
+ ap:graphMarginLeft="-20dp"
+ ap:graphMarginRight="10dp"
+ ap:graphMarginTop="0dp"
+ ap:graphWidthMode="fill"
+ ap:legendVisible="false"
+ ap:lineLabels="" />
</LinearLayout>
- <com.androidplot.xy.XYPlot
- style="@style/APDefacto.Dark"
- android:id="@+id/power_chart"
+ <TextView
+ android:id="@+id/desc"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginHorizontal="10dp"
- ap:graphHeightMode="fill"
- ap:graphWidthMode="fill"
- ap:legendVisible="false"
- ap:graphMarginTop="0dp"
- ap:graphMarginBottom="-20dp"
- ap:graphMarginLeft="-20dp"
- ap:graphMarginRight="10dp"
- ap:lineLabels=""
- />
-
+ android:layout_height="wrap_content"
+ android:text="desc" />
</LinearLayout>
<View