Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -303,14 +303,20 @@ internal class LoggerImpl(
.toString()

override val deviceId: String
get() = CaptureJniLibrary.getDeviceId(this.loggerId) ?: "unknown"
// Log to console the value before returning it to caller
get() {
val deviceId = CaptureJniLibrary.getDeviceId(this.loggerId) ?: "unknown"
Log.d("miguel-capture", "LoggerImpl.deviceId=$deviceId")
return deviceId
}

override fun startNewSession() {
CaptureJniLibrary.startNewSession(this.loggerId)
}

override fun createTemporaryDeviceCode(completion: (CaptureResult<String>) -> Unit) {
CaptureJniLibrary.getDeviceId(this.loggerId)?.let { deviceId ->
Log.d("miguel-capture", "LoggerImpl.createTmpDeviceCode()-deviceId=$deviceId")
/**
* Access the `deviceId` when it is needed for creating the device code, rather than
* at Logger's initialization time. Accessing it later almost guarantees that the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package io.bitdrift.capture
import android.annotation.SuppressLint
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.util.Log

/**
* Convenience wrapper for working with `SharedPreferences`.
Expand All @@ -33,14 +34,19 @@ internal class Preferences(
underlyingPreferences.edit().putLong(key, value).apply()
}

override fun getString(key: String): String? = underlyingPreferences.getString(key, null)
override fun getString(key: String): String? {
val value = underlyingPreferences.getString(key, null)
Log.d("miguel-capture", "Preferences.getString($key)=$value")
return value
}

@SuppressLint("ApplySharedPref")
override fun setString(
key: String,
value: String?,
blocking: Boolean,
) {
Log.d("miguel-capture", "Preferences.setString($key, $value, $blocking)")
val edit =
if (value == null) {
underlyingPreferences.edit().remove(key)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package io.bitdrift.capture

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

@RunWith(RobolectricTestRunner::class)
@Config(sdk = [24])
class PreferencesTest {
private lateinit var context: Context
private lateinit var preferences: Preferences

@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
preferences = Preferences(context)
// Clear preferences before each test
val sharedPrefs = context.getSharedPreferences("io.bitdrift.storage", Context.MODE_PRIVATE)
sharedPrefs.edit().clear().commit()
}

@Test
fun `getLong returns value when key exists`() {
val key = "test_key_long"
val expectedValue = 123L
preferences.setLong(key, expectedValue)

val result = preferences.getLong(key)

assertThat(result).isEqualTo(expectedValue)
}

@Test
fun `getLong returns null when key does not exist`() {
val key = "non_existent_key"
val result = preferences.getLong(key)

assertThat(result).isNull()
}

@Test
fun `setLong saves the value`() {
val key = "test_key_long_save"
val value = 456L

preferences.setLong(key, value)
val savedValue = preferences.getLong(key)

assertThat(savedValue).isEqualTo(value)
}

@Test
fun `getString returns value when key exists`() {
val key = "test_key_string"
val expectedValue = "test_value"
preferences.setString(key, expectedValue, blocking = false)

val result = preferences.getString(key)

assertThat(result).isEqualTo(expectedValue)
}

@Test
fun `getString returns null when key does not exist`() {
val key = "non_existent_string_key"

val result = preferences.getString(key)

assertThat(result).isNull()
}

@Test
fun `setString saves non-null value with blocking`() {
val key = "test_key_string_blocking"
val value = "test_value_blocking"

preferences.setString(key, value, blocking = true)
val savedValue = preferences.getString(key)

assertThat(savedValue).isEqualTo(value)
}

@Test
fun `setString saves non-null value without blocking`() {
val key = "test_key_string_non_blocking"
val value = "test_value_non_blocking"

preferences.setString(key, value, blocking = false)

val savedValue = preferences.getString(key)

assertThat(savedValue).isEqualTo(value)
}

@Test
fun `setString removes value when null with blocking`() {
val key = "test_key_to_remove_blocking"
preferences.setString(key, "some_value", blocking = true)

preferences.setString(key, null, blocking = true)
val savedValue = preferences.getString(key)

assertThat(savedValue).isNull()
}

@Test
fun `setString removes value when null without blocking`() {
val key = "test_key_to_remove_non_blocking"
preferences.setString(key, "some_value", blocking = false)

preferences.setString(key, null, blocking = false)

val savedValue = preferences.getString(key)

assertThat(savedValue).isNull()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ sealed class SessionAction : AppAction {

object GenerateDeviceCode : SessionAction()

object QueryDeviceId : SessionAction()

object CopySessionUrl : SessionAction()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ data class SessionState(
val sessionId: String? = null,
val sessionUrl: String? = null,
val deviceCode: String? = null,
val deviceId: String? = null,
val isDeviceCodeValid: Boolean = false,
val deviceCodeError: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ class SdkRepository(
*/
fun getSessionId(): String? = Logger.sessionId

/**
* Get current device ID (reads Shared Preference in-memory value)
*/
fun getDeviceId(): String? = Logger.deviceId

/**
* Check if SDK is initialized (combines in-memory state with cached prefs)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,29 @@
package io.bitdrift.gradletestapp.ui.compose

import android.widget.Toast
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
Expand All @@ -35,11 +53,11 @@ import io.bitdrift.gradletestapp.data.model.NetworkTestAction
import io.bitdrift.gradletestapp.data.model.SessionAction
import io.bitdrift.gradletestapp.ui.compose.components.FeatureFlagsTestingCard
import io.bitdrift.gradletestapp.ui.compose.components.NavigationCard
import io.bitdrift.gradletestapp.ui.compose.components.StressTestCard
import io.bitdrift.gradletestapp.ui.compose.components.NetworkTestingCard
import io.bitdrift.gradletestapp.ui.compose.components.SdkStatusCard
import io.bitdrift.gradletestapp.ui.compose.components.SessionManagementCard
import io.bitdrift.gradletestapp.ui.compose.components.SleepModeCard
import io.bitdrift.gradletestapp.ui.compose.components.StressTestCard
import io.bitdrift.gradletestapp.ui.compose.components.TestingToolsCard
import io.bitdrift.gradletestapp.ui.theme.BitdriftColors

Expand Down Expand Up @@ -151,6 +169,7 @@ fun MainScreen(
uiState = uiState,
onStartNewSession = { onAction(SessionAction.StartNewSession) },
onGenerateDeviceCode = { onAction(SessionAction.GenerateDeviceCode) },
onQueryDeviceId = { onAction(SessionAction.QueryDeviceId) },
onCopySessionUrl = {
onAction(SessionAction.CopySessionUrl)
uiState.session.sessionUrl?.let { url ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@
package io.bitdrift.gradletestapp.ui.compose.components

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import io.bitdrift.gradletestapp.data.model.AppState
Expand All @@ -25,6 +37,7 @@ fun SessionManagementCard(
onStartNewSession: () -> Unit,
onGenerateDeviceCode: () -> Unit,
onCopySessionUrl: () -> Unit,
onQueryDeviceId: () -> Unit,
modifier: Modifier = Modifier,
) {
Card(
Expand Down Expand Up @@ -78,6 +91,20 @@ fun SessionManagementCard(
color = BitdriftColors.TextTertiary,
)
}

QueryDeviceIdButton(
onClick = onQueryDeviceId,
)

if (uiState.session.deviceId != null) {
DeviceIdField(deviceId = uiState.session.deviceId)
} else {
Text(
text = "No Device ID Queried",
style = MaterialTheme.typography.bodySmall,
color = BitdriftColors.TextTertiary,
)
}
}
}
}
Expand Down Expand Up @@ -200,3 +227,38 @@ private fun DeviceCodeField(deviceCode: String) {
),
)
}

@Composable
private fun QueryDeviceIdButton(onClick: () -> Unit) {
OutlinedButton(
onClick = onClick,
modifier = Modifier.fillMaxWidth(),
colors =
ButtonDefaults.outlinedButtonColors(
contentColor = BitdriftColors.TextPrimary,
),
) {
Text("Query Device Id")
}
}

@Composable
private fun DeviceIdField(deviceId: String) {
OutlinedTextField(
value = deviceId,
onValueChange = {},
label = { Text("Device ID", color = BitdriftColors.TextSecondary) },
modifier = Modifier.fillMaxWidth(),
readOnly = true,
colors =
OutlinedTextFieldDefaults.colors(
focusedTextColor = BitdriftColors.TextBright,
unfocusedTextColor = BitdriftColors.TextBright,
focusedBorderColor = BitdriftColors.Primary,
unfocusedBorderColor = BitdriftColors.Border,
focusedLabelColor = BitdriftColors.Primary,
unfocusedLabelColor = BitdriftColors.TextSecondary,
cursorColor = BitdriftColors.TextBright,
),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class MainViewModel(

is SessionAction.StartNewSession -> startNewSession()
is SessionAction.GenerateDeviceCode -> generateDeviceCode()
is SessionAction.QueryDeviceId -> queryDeviceId()
is SessionAction.CopySessionUrl -> copySessionUrl()

is DiagnosticsAction.LogMessage -> logMessage()
Expand Down Expand Up @@ -237,6 +238,17 @@ class MainViewModel(
}
}

private fun queryDeviceId() {
viewModelScope.launch {
val deviceId = sdkRepository.getDeviceId()
_uiState.update {
it.copy(
session = it.session.copy(deviceId = deviceId),
)
}
}
}

private fun copySessionUrl() {
val sessionUrl = sdkRepository.getSessionUrl()
if (sessionUrl != null) {
Expand Down Expand Up @@ -321,6 +333,7 @@ class MainViewModel(
isSdkInitialized = sdkRepository.isSdkInitialized(),
sessionId = sdkRepository.getSessionId(),
sessionUrl = sdkRepository.getSessionUrl(),
deviceId = sdkRepository.getDeviceId(),
deviceCode = _uiState.value.session.deviceCode,
)

Expand Down
Loading