Skip to content

Commit 96ad964

Browse files
committed
add signal strength monitor
1 parent 83deb79 commit 96ad964

File tree

7 files changed

+108
-16
lines changed

7 files changed

+108
-16
lines changed

app/src/main/java/com/lcl/lclmeasurementtool/MainActivityViewModel.kt

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.lcl.lclmeasurementtool
22

33
import android.content.Context
4+
import android.os.Build
5+
import android.telephony.CellSignalStrength
46
import android.util.Log
5-
import androidx.compose.runtime.MutableState
67
import androidx.compose.ui.graphics.Color
78
import androidx.lifecycle.ViewModel
89
import androidx.lifecycle.viewModelScope
@@ -13,8 +14,8 @@ import com.kongzue.dialogx.dialogs.TipDialog
1314
import com.lcl.lclmeasurementtool.Utils.ECDSA
1415
import com.lcl.lclmeasurementtool.Utils.Hex
1516
import com.lcl.lclmeasurementtool.Utils.SecurityUtils
17+
import com.lcl.lclmeasurementtool.Utils.SignalStrengthLevel
1618
import com.lcl.lclmeasurementtool.constants.NetworkConstants
17-
import com.lcl.lclmeasurementtool.datasource.LocationDataSource
1819
import com.lcl.lclmeasurementtool.features.iperf.IperfRunner
1920
import com.lcl.lclmeasurementtool.features.iperf.IperfStatus
2021
import com.lcl.lclmeasurementtool.features.ping.Ping
@@ -27,8 +28,9 @@ import com.lcl.lclmeasurementtool.model.datamodel.RegistrationModel
2728
import com.lcl.lclmeasurementtool.model.datamodel.UserData
2829
import com.lcl.lclmeasurementtool.model.repository.NetworkApiRepository
2930
import com.lcl.lclmeasurementtool.model.repository.UserDataRepository
31+
import com.lcl.lclmeasurementtool.telephony.SignalStrengthLevelEnum
32+
import com.lcl.lclmeasurementtool.telephony.SignalStrengthMonitor
3033
import dagger.hilt.android.lifecycle.HiltViewModel
31-
import dagger.hilt.android.qualifiers.ApplicationContext
3234
import kotlinx.coroutines.*
3335
import kotlinx.coroutines.flow.*
3436
import java.io.ByteArrayOutputStream
@@ -41,7 +43,8 @@ import javax.inject.Inject
4143
class MainActivityViewModel @Inject constructor(
4244
private val userDataRepository: UserDataRepository,
4345
private val networkApi: NetworkApiRepository,
44-
private val locationService: LocationService
46+
private val locationService: LocationService,
47+
private val signalStrengthMonitor: SignalStrengthMonitor
4548
) : ViewModel() {
4649

4750
companion object {
@@ -199,7 +202,7 @@ class MainActivityViewModel @Inject constructor(
199202

200203

201204
// Network Testing
202-
private val jobs = mutableListOf<Job>()
205+
private val _jobs = mutableListOf<Job>()
203206
private var _pingResult = MutableStateFlow(PingResultState())
204207
private var _downloadResult = MutableStateFlow(ConnectivityTestResult())
205208
private var _uploadResult = MutableStateFlow(ConnectivityTestResult())
@@ -209,7 +212,25 @@ class MainActivityViewModel @Inject constructor(
209212
val pingResult: StateFlow<PingResultState> = _pingResult.asStateFlow()
210213
var downloadResult: StateFlow<ConnectivityTestResult> = _downloadResult.asStateFlow()
211214
var uploadResult: StateFlow<ConnectivityTestResult> = _uploadResult.asStateFlow()
212-
215+
var signalStrengthResult = signalStrengthMonitor.signalStrength.map {s ->
216+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
217+
val report = s.getCellSignalStrengths(CellSignalStrength::class.java)
218+
if (report.isEmpty()) {
219+
SignalStrengthResult(0, SignalStrengthLevelEnum.POOR)
220+
} else {
221+
val data = report[0]
222+
SignalStrengthResult(data.dbm, SignalStrengthLevelEnum.init(data.level))
223+
}
224+
} else {
225+
val dBm = s.getGsmSignalStrength()
226+
val level = SignalStrengthLevelEnum.init(s.level)
227+
SignalStrengthResult(dBm, level)
228+
}
229+
}.stateIn(
230+
scope = viewModelScope,
231+
initialValue = SignalStrengthResult(0, SignalStrengthLevelEnum.POOR),
232+
started = SharingStarted.WhileSubscribed(5_000)
233+
)
213234

214235
val isTestActive = _isTestActive.asStateFlow()
215236

@@ -269,10 +290,10 @@ class MainActivityViewModel @Inject constructor(
269290

270291
fun doIperf(context: Context) = viewModelScope.launch {
271292
val uploadJob = getUploadResult(context = context)
272-
jobs.add(uploadJob)
293+
_jobs.add(uploadJob)
273294
uploadJob.join()
274295
val downloadJob = getDownloadResult(context = context)
275-
jobs.add(downloadJob)
296+
_jobs.add(downloadJob)
276297
}
277298
}
278299

@@ -289,4 +310,6 @@ open class ConnectivityTestResult {
289310
open class PingResultState {
290311
data class Success(val result: PingResult): PingResultState()
291312
data class Error(val error: PingError): PingResultState()
292-
}
313+
}
314+
315+
data class SignalStrengthResult(val dbm: Int, val level: SignalStrengthLevelEnum)

app/src/main/java/com/lcl/lclmeasurementtool/Managers/CellularManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
299299
dBm = report.getDbm();
300300
} else {
301301
level = SignalStrengthLevel.POOR;
302-
dBm = level.getLevelCode();
302+
dBm = report.getDbm();
303303
}
304304
} else {
305305
dBm = signalStrength.getGsmSignalStrength();

app/src/main/java/com/lcl/lclmeasurementtool/datasource/SignalStrengthDataSource.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.telephony.TelephonyCallback
99
import android.telephony.TelephonyManager
1010
import androidx.annotation.RequiresApi
1111
import androidx.core.content.getSystemService
12+
import com.lcl.lclmeasurementtool.telephony.SignalStrengthMonitor
1213
import dagger.hilt.android.qualifiers.ApplicationContext
1314
import kotlinx.coroutines.FlowPreview
1415
import kotlinx.coroutines.channels.awaitClose
@@ -19,9 +20,9 @@ import javax.inject.Inject
1920

2021
class SignalStrengthDataSource @Inject constructor(
2122
@ApplicationContext private val context: Context
22-
) {
23+
): SignalStrengthMonitor {
2324
@OptIn(FlowPreview::class)
24-
val signalStrength = callbackFlow {
25+
override val signalStrength = callbackFlow<SignalStrength> {
2526
val telephonyManager = context.getSystemService<TelephonyManager>()
2627
val executor = Executors.newSingleThreadExecutor()
2728

@@ -41,7 +42,7 @@ class SignalStrengthDataSource @Inject constructor(
4142
} else {
4243
@Suppress("OVERRIDE_DEPRECATION")
4344
val callback = object : PhoneStateListener(executor) {
44-
override fun onSignalStrengthsChanged(s: SignalStrength?) {
45+
override fun onSignalStrengthsChanged(s: SignalStrength) {
4546
super.onSignalStrengthsChanged(s)
4647
channel.trySend(s)
4748
}

app/src/main/java/com/lcl/lclmeasurementtool/modules/DataModule.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package com.lcl.lclmeasurementtool.modules
22

33
import com.lcl.lclmeasurementtool.datasource.ConnectivityMonitorDataSource
44
import com.lcl.lclmeasurementtool.datasource.LocationDataSource
5+
import com.lcl.lclmeasurementtool.datasource.SignalStrengthDataSource
56
import com.lcl.lclmeasurementtool.datasource.SimStateMonitorDataSource
67
import com.lcl.lclmeasurementtool.location.LocationService
78
import com.lcl.lclmeasurementtool.model.datamodel.ConnectivityReportModel
89
import com.lcl.lclmeasurementtool.model.datamodel.SignalStrengthReportModel
910
import com.lcl.lclmeasurementtool.model.repository.*
1011
import com.lcl.lclmeasurementtool.networking.NetworkMonitor
1112
import com.lcl.lclmeasurementtool.networking.SimStateMonitor
13+
import com.lcl.lclmeasurementtool.telephony.SignalStrengthMonitor
1214
import dagger.Binds
1315
import dagger.Module
1416
import dagger.hilt.InstallIn
@@ -37,6 +39,11 @@ interface DataModule {
3739
locationService: LocationDataSource
3840
): LocationService
3941

42+
@Binds
43+
fun bindsSignalStrengthMonitor(
44+
signalStrengthDataSource: SignalStrengthDataSource
45+
): SignalStrengthMonitor
46+
4047
@Binds
4148
fun bindsNetworkAPI(
4249
lclApiRepository: LCLApiRepository
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.lcl.lclmeasurementtool.telephony
2+
3+
import androidx.compose.ui.graphics.Color
4+
5+
6+
enum class SignalStrengthLevelEnum(val level: Int) {
7+
8+
NONE(0) {
9+
override fun color(): Color {
10+
return Color.LightGray
11+
}
12+
},
13+
14+
// the signal strength is poor or unknown
15+
POOR(1) {
16+
override fun color(): Color {
17+
return Color.Red
18+
}
19+
},
20+
21+
// the signal strength is weak
22+
MODERATE(2) {
23+
override fun color(): Color {
24+
return Color(0xFFF47E4C) // orange
25+
}
26+
},
27+
28+
// the signal strength is moderate
29+
GOOD(3) {
30+
override fun color(): Color {
31+
return Color(0xFF81FF50) // light green
32+
}
33+
},
34+
35+
// the signal strength is good
36+
GREAT(4) {
37+
override fun color(): Color {
38+
return Color.Green
39+
}
40+
};
41+
42+
abstract fun color(): Color
43+
44+
companion object {
45+
fun init(value: Int): SignalStrengthLevelEnum {
46+
return SignalStrengthLevelEnum.values().first { it.level == value }
47+
}
48+
}
49+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.lcl.lclmeasurementtool.telephony
2+
3+
import android.telephony.SignalStrength
4+
import kotlinx.coroutines.flow.Flow
5+
6+
interface SignalStrengthMonitor {
7+
val signalStrength: Flow<SignalStrength>
8+
}

app/src/main/java/com/lcl/lclmeasurementtool/ui/HomeScreen.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.lcl.lclmeasurementtool.ConnectivityTestResult
3030
import com.lcl.lclmeasurementtool.MainActivityViewModel
3131
import com.lcl.lclmeasurementtool.MainActivityViewModel.Companion.TAG
3232
import com.lcl.lclmeasurementtool.PingResultState
33+
import com.lcl.lclmeasurementtool.SignalStrengthResult
3334
import kotlinx.coroutines.Job
3435
import kotlinx.coroutines.cancelAndJoin
3536

@@ -47,13 +48,14 @@ fun HomeScreen(modifier: Modifier = Modifier, isOffline: Boolean, mainActivityVi
4748
val pingResult = mainActivityViewModel.pingResult.collectAsStateWithLifecycle()
4849
val uploadResult = mainActivityViewModel.uploadResult.collectAsStateWithLifecycle()
4950
val downloadResult = mainActivityViewModel.downloadResult.collectAsStateWithLifecycle()
51+
val signalStrength = mainActivityViewModel.signalStrengthResult.collectAsStateWithLifecycle()
5052

5153
val jobs = mutableListOf<Job>()
5254
val context = LocalContext.current
5355

5456
Box(modifier = Modifier.fillMaxSize()) {
5557
Column(modifier = modifier.fillMaxHeight()) {
56-
SignalStrengthCard(modifier = modifier)
58+
SignalStrengthCard(modifier = modifier, signalStrengthResult = signalStrength.value)
5759
ConnectivityCard(
5860
modifier = modifier,
5961
pingResult = pingResult.value,
@@ -95,9 +97,11 @@ fun ShowMessage(isOffline: Boolean, msg: String, snackbarHostState: SnackbarHost
9597
@Composable
9698
private fun SignalStrengthCard(
9799
modifier: Modifier = Modifier,
100+
signalStrengthResult: SignalStrengthResult
98101
) {
99102
val fontSize = 18.sp
100103

104+
val (dbm, level) = signalStrengthResult
101105

102106
Card(colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surfaceVariant),
103107
modifier = Modifier
@@ -115,7 +119,7 @@ private fun SignalStrengthCard(
115119
Spacer(modifier = Modifier.width(12.dp))
116120
Text(text = "Signal Strength:", fontSize = fontSize)
117121
Spacer(modifier = Modifier.width(4.dp))
118-
Text(text = "val", fontWeight = FontWeight.Bold, fontSize = fontSize)
122+
Text(text = "$dbm", fontWeight = FontWeight.Bold, fontSize = fontSize)
119123
Spacer(modifier = Modifier.width(4.dp))
120124
Text(text = "dBm", fontSize = fontSize)
121125
Spacer(modifier = Modifier.width(20.dp))
@@ -124,7 +128,7 @@ private fun SignalStrengthCard(
124128
.clip(
125129
CircleShape
126130
)
127-
.background(Color.Green))
131+
.background(level.color()))
128132
}
129133
}
130134
}

0 commit comments

Comments
 (0)