Skip to content

Commit

Permalink
Added sample app
Browse files Browse the repository at this point in the history
  • Loading branch information
mroczis committed Dec 12, 2019
1 parent 5f2efd8 commit 80ecf69
Show file tree
Hide file tree
Showing 31 changed files with 496 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
34 changes: 34 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29

defaultConfig {
applicationId "cz.mroczis.netmonster.sample"
minSdkVersion 14
targetSdkVersion 29
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

}

dependencies {
implementation project(":library")
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.1.0-beta02'
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
26 changes: 26 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="cz.mroczis.netmonster.sample">

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/NetMonster"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
79 changes: 79 additions & 0 deletions app/src/main/java/cz/mroczis/netmonster/sample/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cz.mroczis.netmonster.sample

import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.os.postDelayed
import androidx.recyclerview.widget.LinearLayoutManager
import cz.mroczis.netmonster.core.factory.NetMonsterFactory
import cz.mroczis.netmonster.core.feature.detect.DetectorAosp
import cz.mroczis.netmonster.core.feature.detect.DetectorHspaDc
import cz.mroczis.netmonster.core.feature.detect.DetectorLteAdvancedCellInfo
import cz.mroczis.netmonster.core.feature.detect.DetectorLteAdvancedServiceState
import cz.mroczis.netmonster.core.feature.merge.CellSource
import kotlinx.android.synthetic.main.activity_main.*

/**
* Activity periodically updates data (once in [REFRESH_RATIO] ms) when it's on foreground.
*/
class MainActivity : AppCompatActivity() {

companion object {
private const val REFRESH_RATIO = 5_000L
}

private val handler = Handler()
private val adapter = MainAdapter()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

recycler.adapter = adapter
recycler.layoutManager = LinearLayoutManager(this)
}

override fun onResume() {
super.onResume()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED
) {
loop()
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_PHONE_STATE
), 0)
}
}

override fun onPause() {
super.onPause()
handler.removeCallbacksAndMessages(null)
}

private fun loop() {
updateData()
handler.postDelayed(REFRESH_RATIO) { loop() }
}

@SuppressLint("MissingPermission")
private fun updateData() {
NetMonsterFactory.get(this).apply {
val merged = getCells()
adapter.data = merged

Log.d("NTM-RES", " \n${merged.joinToString(separator = "\n")}")
}
}

}
19 changes: 19 additions & 0 deletions app/src/main/java/cz/mroczis/netmonster/sample/MainAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cz.mroczis.netmonster.sample

import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import cz.mroczis.netmonster.core.model.cell.ICell

class MainAdapter : RecyclerView.Adapter<MainVH>() {

var data: List<ICell> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MainVH.create(parent)
override fun onBindViewHolder(holder: MainVH, position: Int) = holder.bind(data[position])
override fun getItemCount() = data.size

}
21 changes: 21 additions & 0 deletions app/src/main/java/cz/mroczis/netmonster/sample/MainVH.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cz.mroczis.netmonster.sample

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import cz.mroczis.netmonster.core.model.cell.*
import kotlinx.android.synthetic.main.view_cell.view.*

class MainVH(view: View) : RecyclerView.ViewHolder(view) {

companion object {
fun create(parent: ViewGroup): MainVH {
val v = LayoutInflater.from(parent.context).inflate(R.layout.view_cell, parent, false)
return MainVH(v)
}
}

fun bind(cell: ICell) = itemView.root.bind(cell)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cz.mroczis.netmonster.sample.view

import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import cz.mroczis.netmonster.sample.R
import kotlinx.android.synthetic.main.view_cell_item_simple.view.*

class CellItemSimple @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {

init {
View.inflate(context, R.layout.view_cell_item_simple, this)
}

fun bind(
title: String,
message: String
) {
this.title.text = title
this.message.text = message
}



}
148 changes: 148 additions & 0 deletions app/src/main/java/cz/mroczis/netmonster/sample/view/CellView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package cz.mroczis.netmonster.sample.view

import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
import cz.mroczis.netmonster.core.model.cell.*

class CellView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {

init {
orientation = VERTICAL
}

private val transformer = object : ICellProcessor<Unit> {

override fun processLte(cell: CellLte) {
cell.network?.let { addView("NET", "LTE ${it.mcc} ${it.mnc} (${it.iso}) ${cell.connectionStatus.javaClass.simpleName}") }
cell.band?.let { band ->
band.channelNumber.let { addView("FREQ", "$it (#${band.number}, ${band.name})") }
}

cell.eci?.let { addView("ECI", it) }
cell.enb?.let { addView("eNb", it) }
cell.cid?.let { addView("CID", it) }
cell.tac?.let { addView("TAC", it) }
cell.pci?.let { addView("PCI", it) }
cell.bandwidth?.let { addView("BW", it) }

cell.signal.let { signal ->
signal.rssi?.let { addView("RSSI", it) }
signal.rsrp?.let { addView("RSSI", it) }
signal.rsrq?.let { addView("RSRQ", it) }
signal.cqi?.let { addView("CQI", it) }
signal.timingAdvance?.let { addView("TA", it) }
signal.snr?.let { addView("SNR", it) }
}
}

override fun processCdma(cell: CellCdma) {
addView("SID", cell.sid)
cell.nid?.let { addView("NID", it) }
cell.bid?.let { addView("BID", it) }
cell.lat?.let { addView("LAT", it) }
cell.lon?.let { addView("LON", it) }

cell.signal.let { signal ->
signal.cdmaEcio?.let { addView("CD EC/IO", it) }
signal.cdmaRssi?.let { addView("CD RSSI", it) }
signal.evdoEcio?.let { addView("EV EC/IO", it) }
signal.evdoRssi?.let { addView("EV RSSI", it) }
signal.evdoSnr?.let { addView("EV SNR", it) }
}
}

override fun processGsm(cell: CellGsm) {
cell.network?.let { addView("NET", "GSM ${it.mcc} ${it.mnc} (${it.iso}) ${cell.connectionStatus.javaClass.simpleName}") }
cell.band?.let { band ->
band.channelNumber.let { addView("FREQ", "$it (#${band.number}, ${band.name})") }
}

cell.cid?.let { addView("CID", it) }
cell.lac?.let { addView("LAC", it) }
cell.bsic?.let { addView("BSIC", it) }

cell.signal.let { signal ->
signal.rssi?.let { addView("RSSI", it) }
signal.bitErrorRate?.let { addView("BER", it) }
signal.timingAdvance?.let { addView("TA", it) }
}
}

override fun processNr(cell: CellNr) {
cell.network?.let { addView("NET", "NR ${it.mcc} ${it.mnc} (${it.iso}) ${cell.connectionStatus.javaClass.simpleName}") }
cell.band?.let { band ->
band.channelNumber.let { addView("FREQ", "$it (#${band.number}, ${band.name})") }
}

cell.nci?.let { addView("NCI", it) }
cell.tac?.let { addView("TAC", it) }
cell.pci?.let { addView("PCI", it) }

cell.signal.let { signal ->
signal.csiRsrp?.let { addView("CSI RSRP", it) }
signal.csiRsrq?.let { addView("CSI RSRQ", it) }
signal.csiSinr?.let { addView("CSI SINR", it) }
signal.ssRsrp?.let { addView("SS RSRP", it) }
signal.ssRsrq?.let { addView("SS RSRQ", it) }
signal.ssSinr?.let { addView("SS SINR", it) }
}
}

override fun processTdscdma(cell: CellTdscdma) {
cell.network?.let { addView("NET", "TDS-CDMA ${it.mcc} ${it.mnc} (${it.iso}) ${cell.connectionStatus.javaClass.simpleName}") }
cell.band?.let { band ->
band.channelNumber.let { addView("FREQ", "$it (#${band.number}, ${band.name})") }
}

cell.ci?.let { addView("CI", it) }
cell.rnc?.let { addView("RNC", it) }
cell.cid?.let { addView("CID", it) }
cell.lac?.let { addView("LAC", it) }
cell.cpid?.let { addView("CPID", it) }

cell.signal.let { signal ->
signal.rssi?.let { addView("RSSI", it) }
signal.bitErrorRate?.let { addView("BER", it) }
signal.rscp?.let { addView("RSCP", it) }
}
}

override fun processWcdma(cell: CellWcdma) {
cell.network?.let { addView("NET", "WCDMA ${it.mcc} ${it.mnc} (${it.iso}) ${cell.connectionStatus.javaClass.simpleName}") }
cell.band?.let { band ->
band.channelNumber.let { addView("FREQ", "$it (#${band.number}, ${band.name})") }
}

cell.ci?.let { addView("CI", it) }
cell.rnc?.let { addView("RNC", it) }
cell.cid?.let { addView("CID", it) }
cell.lac?.let { addView("LAC", it) }
cell.psc?.let { addView("PSC", it) }

cell.signal.let { signal ->
signal.rssi?.let { addView("RSSI", it) }
signal.bitErrorRate?.let { addView("BER", it) }
signal.rscp?.let { addView("RSCP", it) }
signal.ecio?.let { addView("ECIO", it) }
signal.ecno?.let { addView("ECNO", it) }
}
}

}

fun bind (cell: ICell) {
removeAllViews()
cell.let(transformer)
}

private fun addView(title: String, message: Any) {
val view = CellItemSimple(context).apply {
bind(title, message.toString())
}

addView(view)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 80ecf69

Please sign in to comment.