Skip to content

Commit b49f706

Browse files
authored
Merge pull request #83 from TelemetryDeck/feat/extend-duration-signals
Extend duration signals
2 parents 0f89b33 + 5371642 commit b49f706

File tree

5 files changed

+123
-34
lines changed

5 files changed

+123
-34
lines changed

lib/src/androidTest/java/com/telemetrydeck/sdk/DurationSignalTrackerProviderTest.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class DurationSignalTrackerProviderTest {
3939
@Test
4040
fun tracks_a_signal_duration() {
4141
val sut = createSut()
42-
sut.startTracking("signal1", emptyMap())
42+
sut.startTracking("signal1", emptyMap(), false)
4343
// sleep for 5 seconds
4444
Thread.sleep(5000)
4545
val params = sut.stopTracking("signal1", emptyMap())
@@ -60,7 +60,7 @@ class DurationSignalTrackerProviderTest {
6060
@Test
6161
fun tracks_a_signal_duration_with_starting_and_endingparams() {
6262
val sut = createSut()
63-
sut.startTracking("signal1", mapOf("param1" to "value1"))
63+
sut.startTracking("signal1", mapOf("param1" to "value1"), false)
6464
// sleep for 5 seconds
6565
Thread.sleep(5000)
6666
val params = sut.stopTracking("signal1", mapOf("param2" to "value3"))
@@ -86,7 +86,7 @@ class DurationSignalTrackerProviderTest {
8686
val twoHoursAgo = Date(now.time - 7200000)
8787
val hourAgo = Date(now.time - 3600000)
8888
val state = DurationSignalTrackerProvider.TrackerState(
89-
signals = mapOf("signal1" to DurationSignalTrackerProvider.CachedData(startTime = twoHoursAgo, parameters = mapOf("param1" to "value1"))),
89+
signals = mapOf("signal1" to DurationSignalTrackerProvider.CachedData(startTime = twoHoursAgo, parameters = mapOf("param1" to "value1"), false)),
9090
lastEnteredBackground = hourAgo
9191
)
9292
prepareState(state)
@@ -114,13 +114,13 @@ class DurationSignalTrackerProviderTest {
114114
val twoHoursAgo = Date(now.time - 7200000)
115115
val hourAgo = Date(now.time - 3700000)
116116
val state = DurationSignalTrackerProvider.TrackerState(
117-
signals = mapOf("signal1" to DurationSignalTrackerProvider.CachedData(startTime = twoHoursAgo, parameters = mapOf("param1" to "value1"))),
117+
signals = mapOf("signal1" to DurationSignalTrackerProvider.CachedData(startTime = twoHoursAgo, parameters = mapOf("param1" to "value1"), false)),
118118
lastEnteredBackground = hourAgo
119119
)
120120
prepareState(state)
121121
val sut = createSut()
122122

123-
sut.handleOnStart()
123+
sut.handleOnForeground()
124124
val params = sut.stopTracking("signal1", mapOf("param2" to "value3"))
125125

126126
assertEquals("value1", params?.get("param1"))

lib/src/androidTest/java/com/telemetrydeck/sdk/TelemetryDeckTest.kt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.lifecycle.LifecycleOwner
77
import androidx.test.annotation.UiThreadTest
88
import androidx.test.core.app.ApplicationProvider
99
import androidx.test.ext.junit.runners.AndroidJUnit4
10+
import com.telemetrydeck.sdk.providers.DurationSignalTrackerProvider
1011
import com.telemetrydeck.sdk.providers.SessionTrackingSignalProvider
1112
import com.telemetrydeck.sdk.signals.Acquisition
1213
import com.telemetrydeck.sdk.signals.Session
@@ -24,6 +25,8 @@ import java.io.File
2425
import java.net.URL
2526
import java.util.Date
2627
import java.util.UUID
28+
import kotlin.collections.find
29+
import kotlin.text.startsWith
2730

2831

2932
@RunWith(AndroidJUnit4::class)
@@ -315,6 +318,74 @@ class TelemetryDeckTest {
315318
}
316319
}
317320

321+
@UiThreadTest
322+
@Test
323+
fun allows_for_duration_tracking_with_floatvalue_customer_id() {
324+
val signalCache = startTelemetryDeck(
325+
prepareBuilder()
326+
)
327+
328+
// act
329+
TelemetryDeck.startDurationSignal("type")
330+
TelemetryDeck.stopAndSendDurationSignal("type", floatValue = 10.0, customUserID = "user")
331+
332+
333+
verify {
334+
signalCache.add(withArg {
335+
assertEquals("type", it.type)
336+
val duration =
337+
it.payload.find { it.startsWith("TelemetryDeck.Signal.durationInSeconds:") }
338+
assertNotNull(duration)
339+
assertEquals(10.0, it.floatValue)
340+
assertEquals(
341+
"04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb",
342+
it.clientUser
343+
)
344+
})
345+
}
346+
}
347+
348+
@UiThreadTest
349+
@Test
350+
fun duration_tracking_with_and_without_background_time() {
351+
startTelemetryDeck(
352+
prepareBuilder()
353+
.testMode(false)
354+
)
355+
356+
val sut =
357+
(TelemetryDeck.instance!!.providers.find { it is DurationSignalTrackerProvider } as DurationSignalTrackerProvider)
358+
359+
val now = Date()
360+
sut.handleOnForeground(now)
361+
362+
sut.startTracking("foreground", emptyMap(), includeBackgroundTime = false, now)
363+
sut.startTracking("foreground_and_background", emptyMap(), includeBackgroundTime = true, now)
364+
365+
// +600seconds, simulate going into the background 10 minutes later
366+
val time1 = Date(now.time + 1000 * 10 * 60)
367+
sut.handleOnBackground(
368+
Date(now.time + 1000 * 10 * 60)
369+
)
370+
371+
// +3600seconds, and back to foreground an hour later
372+
val endTime = Date(time1.time + (1000 * 60 * 60))
373+
374+
sut.handleOnForeground(
375+
endTime
376+
)
377+
378+
val paramsForeground = sut.stopTracking("foreground", emptyMap(), endTime)
379+
val paramsForeAndBackground =
380+
sut.stopTracking("foreground_and_background", emptyMap(), endTime)
381+
382+
assertNotNull(paramsForeground)
383+
assertNotNull(paramsForeAndBackground)
384+
385+
assertEquals("600.000", paramsForeground?.get("TelemetryDeck.Signal.durationInSeconds"))
386+
assertEquals("4200.000", paramsForeAndBackground?.get("TelemetryDeck.Signal.durationInSeconds"))
387+
}
388+
318389

319390
private fun prepareBuilder(): TelemetryDeck.Builder {
320391
val httpClient = mockk<TelemetryApiClient>()

lib/src/main/java/com/telemetrydeck/sdk/TelemetryDeck.kt

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,24 +155,29 @@ class TelemetryDeck(
155155
)
156156
}
157157

158-
override fun startDurationSignal(signalName: String, parameters: Map<String, String>) {
158+
override fun startDurationSignal(signalName: String, parameters: Map<String, String>, includeBackgroundTime: Boolean) {
159159
val trackingProvider = this.providers.find { it is DurationSignalTrackerProvider } as? DurationSignalTrackerProvider
160160
if (trackingProvider == null) {
161161
this.logger?.error("startDurationSignal requires the DurationSignalTrackerProvider to be registered")
162162
return
163163
}
164-
trackingProvider.startTracking(signalName, parameters)
164+
trackingProvider.startTracking(signalName, parameters, includeBackgroundTime)
165165
}
166166

167-
override fun stopAndSendDurationSignal(signalName: String, parameters: Map<String, String>) {
167+
override fun stopAndSendDurationSignal(signalName: String, parameters: Map<String, String>, floatValue: Double?, customUserID: String?) {
168168
val trackingProvider = this.providers.find { it is DurationSignalTrackerProvider } as? DurationSignalTrackerProvider
169169
if (trackingProvider == null) {
170170
this.logger?.error("stopAndSendDurationSignal requires the DurationSignalTrackerProvider to be registered")
171171
return
172172
}
173173
val params = trackingProvider.stopTracking(signalName, parameters)
174174
if (params != null) {
175-
processSignal(signalName, params = params)
175+
processSignal(
176+
signalName,
177+
params = params,
178+
floatValue = floatValue,
179+
customUserID = customUserID
180+
)
176181
}
177182
}
178183

@@ -422,15 +427,17 @@ class TelemetryDeck(
422427
)
423428
}
424429

425-
override fun startDurationSignal(signalName: String, parameters: Map<String, String>) {
426-
getInstance()?.startDurationSignal(signalName, parameters)
430+
override fun startDurationSignal(signalName: String, parameters: Map<String, String>, includeBackgroundTime: Boolean) {
431+
getInstance()?.startDurationSignal(signalName, parameters, includeBackgroundTime)
427432
}
428433

429434
override fun stopAndSendDurationSignal(
430435
signalName: String,
431-
parameters: Map<String, String>
436+
parameters: Map<String, String>,
437+
floatValue: Double?,
438+
customUserID: String?
432439
) {
433-
getInstance()?.stopAndSendDurationSignal(signalName, parameters)
440+
getInstance()?.stopAndSendDurationSignal(signalName, parameters, floatValue, customUserID)
434441
}
435442

436443
override val signalCache: SignalCache?

lib/src/main/java/com/telemetrydeck/sdk/TelemetryDeckClient.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,13 @@ interface TelemetryDeckClient {
121121
*
122122
* @param signalName The name of the signal to track. This will be used to identify and stop the duration tracking later.
123123
* @param parameters A dictionary of additional string key-value pairs that will be included when the duration signal is eventually sent.
124+
* @param includeBackgroundTime Indicates if the duration tracked will include the time spent in the background.
124125
*/
125-
fun startDurationSignal(signalName: String, parameters: Map<String, String> = emptyMap())
126+
fun startDurationSignal(
127+
signalName: String,
128+
parameters: Map<String, String> = emptyMap(),
129+
includeBackgroundTime: Boolean = false
130+
)
126131

127132
/** Stops tracking the duration of a signal and sends it with the total duration.
128133
*
@@ -138,9 +143,11 @@ interface TelemetryDeckClient {
138143
*
139144
* @param signalName The name of the signal that was previously started with [startDurationSignal]
140145
* @param parameters Additional parameters to include with the signal. These will be merged with the parameters provided at the start.
146+
* @param floatValue An optional floating-point number that can be used to provide numerical data about the signal.
147+
* @param customUserID An optional string specifying a custom user identifier. If provided, it will override the default user identifier from the configuration.
141148
*
142149
*/
143-
fun stopAndSendDurationSignal(signalName: String, parameters: Map<String, String> = emptyMap())
150+
fun stopAndSendDurationSignal(signalName: String, parameters: Map<String, String> = emptyMap(), floatValue: Double? = null, customUserID: String? = null)
144151

145152
val configuration: TelemetryManagerConfiguration?
146153
}

lib/src/main/java/com/telemetrydeck/sdk/providers/DurationSignalTrackerProvider.kt

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ class DurationSignalTrackerProvider : TelemetryDeckProvider, DefaultLifecycleObs
3838
}
3939

4040
override fun onStart(owner: LifecycleOwner) {
41-
handleOnStart()
41+
handleOnForeground()
4242
}
4343

4444
override fun onStop(owner: LifecycleOwner) {
45-
handleOnStop()
45+
handleOnBackground()
4646
}
4747

48-
fun handleOnStart() {
48+
fun handleOnForeground(now: Date = Date()) {
4949
this.manager?.get()?.debugLogger?.debug("Commencing signal duration tracking")
5050

5151
val preRestoreState = this.state
@@ -65,14 +65,17 @@ class DurationSignalTrackerProvider : TelemetryDeckProvider, DefaultLifecycleObs
6565
val lastEnteredBackground = currentState.lastEnteredBackground
6666
if (lastEnteredBackground != null) {
6767
// subtracts background time from all signals by moving their start time forward
68-
val now = Date()
6968
val backgroundDuration = now.time - lastEnteredBackground.time
7069
this.manager?.get()?.debugLogger?.debug("Adapting signal duration with -$backgroundDuration ms")
7170
currentState = currentState.copy(
7271
signals = currentState.signals.mapValues {
73-
it.value.copy(
74-
startTime = Date(it.value.startTime.time + backgroundDuration)
75-
)
72+
if (it.value.includeBackgroundTime == true) {
73+
it.value.copy()
74+
} else {
75+
it.value.copy(
76+
startTime = Date(it.value.startTime.time + backgroundDuration)
77+
)
78+
}
7679
}
7780
)
7881
}
@@ -81,31 +84,31 @@ class DurationSignalTrackerProvider : TelemetryDeckProvider, DefaultLifecycleObs
8184
this.state = currentState
8285
}
8386

84-
fun handleOnStop() {
87+
fun handleOnBackground(now: Date = Date()) {
8588
this.manager?.get()?.debugLogger?.debug("Signal duration tracking is shutting down")
86-
val currentState = this.state
89+
val currentState = this.state?.copy(
90+
lastEnteredBackground = now
91+
)
8792
if (currentState != null) {
88-
val updatedState = currentState.copy(
89-
lastEnteredBackground = Date()
90-
)
91-
writeStateToDisk(updatedState, this.appContext?.get(), this.fileName, this.fileEncoding, this.manager?.get()?.debugLogger)
93+
this.state = currentState
94+
writeStateToDisk(currentState, this.appContext?.get(), this.fileName, this.fileEncoding, this.manager?.get()?.debugLogger)
9295
}
9396
}
9497

9598
@Synchronized
96-
fun startTracking(signalName: String, parameters: Map<String, String>) {
99+
fun startTracking(signalName: String, parameters: Map<String, String>, includeBackgroundTime: Boolean, now: Date = Date()) {
97100
val currentState = state ?: throw Exception("startTracking called before register")
98-
val now = Date()
99101
this.state = currentState.copy(
100102
signals = currentState.signals + (signalName to CachedData(
101103
now,
102-
parameters
104+
parameters,
105+
includeBackgroundTime
103106
))
104107
)
105108
}
106109

107110
@Synchronized
108-
fun stopTracking(signalName: String, parameters: Map<String, String>): Map<String, String>? {
111+
fun stopTracking(signalName: String, parameters: Map<String, String>, now: Date = Date()): Map<String, String>? {
109112
val currentState = state ?: throw Exception("stopTracking called before register")
110113
val signalTracking = currentState.signals[signalName]
111114
if (signalTracking == null) {
@@ -116,7 +119,7 @@ class DurationSignalTrackerProvider : TelemetryDeckProvider, DefaultLifecycleObs
116119
this.state = currentState.copy(signals = currentState.signals - signalName)
117120

118121
// queue a duration signal for sending
119-
val trackingDurationMs = Date().time - signalTracking.startTime.time
122+
val trackingDurationMs = now.time - signalTracking.startTime.time
120123
val trackingDurationSec = trackingDurationMs / 1000.0
121124

122125
val mergedParameters = mutableMapOf<String, String>()
@@ -145,6 +148,7 @@ class DurationSignalTrackerProvider : TelemetryDeckProvider, DefaultLifecycleObs
145148
data class CachedData(
146149
@Serializable(with = DateSerializer::class)
147150
val startTime: Date,
148-
val parameters: Map<String, String>
151+
val parameters: Map<String, String>,
152+
val includeBackgroundTime: Boolean?
149153
)
150154
}

0 commit comments

Comments
 (0)