Skip to content

Commit 4839eee

Browse files
committed
connect ping test to UI with flow
1 parent 844c58a commit 4839eee

File tree

10 files changed

+349
-104
lines changed

10 files changed

+349
-104
lines changed

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

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,32 @@ package com.lcl.lclmeasurementtool
22

33
import android.content.Context
44
import android.util.Log
5+
import androidx.compose.runtime.MutableState
6+
import androidx.compose.ui.graphics.Color
57
import androidx.lifecycle.ViewModel
68
import androidx.lifecycle.viewModelScope
79
import com.google.protobuf.ByteString
810
import com.jsoniter.JsonIterator
911
import com.jsoniter.spi.JsonException
1012
import com.kongzue.dialogx.dialogs.TipDialog
11-
import com.kongzue.dialogx.dialogs.WaitDialog
1213
import com.lcl.lclmeasurementtool.Utils.ECDSA
1314
import com.lcl.lclmeasurementtool.Utils.Hex
1415
import com.lcl.lclmeasurementtool.Utils.SecurityUtils
15-
import com.lcl.lclmeasurementtool.features.iperf.runIperf
16+
import com.lcl.lclmeasurementtool.constants.NetworkConstants
17+
import com.lcl.lclmeasurementtool.features.iperf.IperfRunner
18+
import com.lcl.lclmeasurementtool.features.iperf.IperfStatus
19+
import com.lcl.lclmeasurementtool.features.ping.Ping
20+
import com.lcl.lclmeasurementtool.features.ping.PingError
21+
import com.lcl.lclmeasurementtool.features.ping.PingErrorCase
22+
import com.lcl.lclmeasurementtool.features.ping.PingResult
1623
import com.lcl.lclmeasurementtool.model.datamodel.QRCodeKeysModel
1724
import com.lcl.lclmeasurementtool.model.datamodel.RegistrationModel
1825
import com.lcl.lclmeasurementtool.model.datamodel.UserData
1926
import com.lcl.lclmeasurementtool.model.repository.NetworkApiRepository
2027
import com.lcl.lclmeasurementtool.model.repository.UserDataRepository
2128
import dagger.hilt.android.lifecycle.HiltViewModel
22-
import dagger.hilt.android.qualifiers.ApplicationContext
23-
import kotlinx.coroutines.Dispatchers
24-
import kotlinx.coroutines.async
25-
import kotlinx.coroutines.flow.SharingStarted
26-
import kotlinx.coroutines.flow.StateFlow
27-
import kotlinx.coroutines.flow.map
28-
import kotlinx.coroutines.flow.stateIn
29-
import kotlinx.coroutines.launch
30-
import kotlinx.coroutines.withContext
29+
import kotlinx.coroutines.*
30+
import kotlinx.coroutines.flow.*
3131
import java.io.ByteArrayOutputStream
3232
import java.security.SecureRandom
3333
import java.security.interfaces.ECPrivateKey
@@ -37,8 +37,14 @@ import javax.inject.Inject
3737
@HiltViewModel
3838
class MainActivityViewModel @Inject constructor(
3939
private val userDataRepository: UserDataRepository,
40-
private val networkApi: NetworkApiRepository,
40+
private val networkApi: NetworkApiRepository
4141
) : ViewModel() {
42+
43+
companion object {
44+
const val TAG = "MainActivityViewModel"
45+
}
46+
47+
// UI
4248
val uiState: StateFlow<MainActivityUiState> = userDataRepository.userData.map {
4349
if (it.loggedIn) MainActivityUiState.Success(it) else MainActivityUiState.Login
4450
}.stateIn(
@@ -47,6 +53,7 @@ class MainActivityViewModel @Inject constructor(
4753
started = SharingStarted.WhileSubscribed(5_000)
4854
)
4955

56+
// Authentication
5057
fun login(hPKR: ByteString, skT: ByteString) = viewModelScope.launch {
5158
userDataRepository.setKeys(hPKR, skT)
5259
}
@@ -71,7 +78,7 @@ class MainActivityViewModel @Inject constructor(
7178
)
7279
} catch (e: JsonException) {
7380
// TipDialog.show("The QR Code is invalid. Please rescan the code or contact the administrator at [email protected].", WaitDialog.TYPE.ERROR)
74-
Log.d("MainViewModel", "The QR Code is invalid. Please rescan the code or contact the administrator at [email protected].")
81+
Log.d(TAG, "The QR Code is invalid. Please rescan the code or contact the administrator at [email protected].")
7582
// val reasons =
7683
// AnalyticsUtils.formatProperties(e.message, Arrays.toString(e.stackTrace))
7784
// Analytics.trackEvent(AnalyticsUtils.QR_CODE_PARSING_FAILED, reasons)
@@ -179,9 +186,82 @@ class MainActivityViewModel @Inject constructor(
179186

180187
return LoginStatus.ScanSuccess(sigmaTHex, pkAHex, skTHex)
181188
}
189+
190+
191+
// Network Testing
192+
var uploadResult: ConnectivityTestResult.Result? = null
193+
var downloadResult: ConnectivityTestResult.Result? = null
194+
private var _pingResult = MutableStateFlow(PingResultState())
195+
val pingResult: StateFlow<PingResultState> = _pingResult.asStateFlow()
196+
private val _isTestActive = MutableStateFlow(false)
197+
val isTestActive = _isTestActive.asStateFlow()
198+
199+
fun doPing() = viewModelScope.launch {
200+
try {
201+
Ping.cancellableStart(address = NetworkConstants.PING_TEST_ADDRESS, timeout = 1000)
202+
.onStart {
203+
Log.d(TAG, "isActive = true")
204+
_isTestActive.value = true
205+
}
206+
.onCompletion {
207+
Log.d(TAG, "isActive = false")
208+
_pingResult.value = PingResultState.Error(PingError(PingErrorCase.CANCELLED, it?.message))
209+
_isTestActive.value = false
210+
}
211+
.collect {
212+
ensureActive()
213+
Log.d(TAG, "Test is still active")
214+
when(it.error.code) {
215+
PingErrorCase.OK -> _pingResult.value = PingResultState.Success(it)
216+
else -> _pingResult.value = PingResultState.Error(it.error)
217+
}
218+
}
219+
} catch (e: IllegalArgumentException) {
220+
_pingResult.value = PingResultState.Error(PingError(PingErrorCase.OTHER, e.message))
221+
Log.e(TAG, "Ping Config error")
222+
}
223+
}
224+
225+
fun getUploadResult(context: Context) = viewModelScope.launch {
226+
IperfRunner().getTestResult(IperfRunner.iperfUploadConfig, context.cacheDir).collect { result ->
227+
uploadResult = when(result.status) {
228+
IperfStatus.RUNNING -> {
229+
ConnectivityTestResult.Result(result.bandWidth, Color.LightGray)
230+
}
231+
IperfStatus.FINISHED -> {
232+
ConnectivityTestResult.Result(result.bandWidth, Color.Black)
233+
}
234+
IperfStatus.ERROR -> TODO()
235+
}
236+
}
237+
}
238+
239+
240+
fun getDownloadResult(context: Context) = viewModelScope.launch {
241+
IperfRunner().getTestResult(IperfRunner.iperfDownloadConfig, context.cacheDir).collect { result ->
242+
downloadResult = when(result.status) {
243+
IperfStatus.RUNNING -> {
244+
ConnectivityTestResult.Result(result.bandWidth, Color.LightGray)
245+
}
246+
IperfStatus.FINISHED -> {
247+
ConnectivityTestResult.Result(result.bandWidth, Color.Black)
248+
}
249+
IperfStatus.ERROR -> TODO()
250+
}
251+
}
252+
}
182253
}
183254

184255
sealed interface MainActivityUiState {
185256
object Login : MainActivityUiState
186257
data class Success(val userData: UserData) : MainActivityUiState
258+
}
259+
260+
sealed interface ConnectivityTestResult {
261+
data class Result (val result: String, val color: Color): ConnectivityTestResult
262+
}
263+
264+
open class PingResultState {
265+
data class Success(val result: PingResult): PingResultState()
266+
data class Error(val error: PingError): PingResultState()
187267
}

app/src/main/java/com/lcl/lclmeasurementtool/Managers/KeyStoreManager.java renamed to app/src/main/java/com/lcl/lclmeasurementtool/Managers/DeprecatedKeyStoreManager.java

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

3-
import android.os.Build;
43
import android.security.keystore.KeyGenParameterSpec;
54
import android.security.keystore.KeyProperties;
65
import android.util.Log;
76

8-
import androidx.annotation.RequiresApi;
9-
107
import java.io.IOException;
118
import java.security.InvalidAlgorithmParameterException;
129
import java.security.KeyPair;
@@ -25,9 +22,9 @@
2522
* A key store manager responsible for generating and maintaining private/public keys
2623
* @deprecated will not be used in the measurement application
2724
*/
28-
public class KeyStoreManager {
25+
public class DeprecatedKeyStoreManager {
2926

30-
private static KeyStoreManager instance;
27+
private static DeprecatedKeyStoreManager instance;
3128

3229
private static final String TAG = "KeyStoreManager";
3330

@@ -36,17 +33,17 @@ public class KeyStoreManager {
3633

3734
private final KeyStore ks;
3835

39-
private KeyStoreManager()
36+
private DeprecatedKeyStoreManager()
4037
throws NoSuchProviderException,
4138
NoSuchAlgorithmException,
4239
InvalidAlgorithmParameterException, KeyStoreException, CertificateException, IOException {
4340
ks = KeyStore.getInstance(provider);
4441
ks.load(null);
4542
}
4643

47-
public static KeyStoreManager getInstance() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException, CertificateException, IOException {
44+
public static DeprecatedKeyStoreManager getInstance() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException, CertificateException, IOException {
4845
if (instance == null) {
49-
instance = new KeyStoreManager();
46+
instance = new DeprecatedKeyStoreManager();
5047
}
5148

5249
return instance;

app/src/main/java/com/lcl/lclmeasurementtool/features/iperf/Iperf.kt

Lines changed: 0 additions & 47 deletions
This file was deleted.

app/src/main/java/com/lcl/lclmeasurementtool/features/iperf/IperfResult.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.lcl.lclmeasurementtool.features.iperf
22

33
data class IperfResult(
4-
val timeStart: Float?,
5-
val timeEnd: Float?,
6-
val sendBytes: String?,
7-
val bandWidth: String?,
8-
val isDownMode: Boolean?,
4+
val timeStart: Float,
5+
val timeEnd: Float,
6+
val sendBytes: String,
7+
val bandWidth: String,
8+
val isDownMode: Boolean,
99
val errorMSg: String?,
1010
val status: IperfStatus
1111
)

0 commit comments

Comments
 (0)