Skip to content

Commit

Permalink
Create annotation to opt into activity open tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
bidetofevil committed Sep 17, 2024
1 parent 4768784 commit 19a8def
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.embrace.android.embracesdk.annotation

import java.lang.annotation.Inherited

@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Inherited
@Retention(AnnotationRetention.RUNTIME)
public annotation class ObservedActivity
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Build
import android.os.Bundle
import io.embrace.android.embracesdk.annotation.ObservedActivity
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.utils.VersionChecker
Expand All @@ -25,47 +26,59 @@ class OpenEventEmitter(
) : ActivityLifecycleListener {

override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) {
create(activity)
if (activity.observeOpening()) {
create(activity)
}
}

override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
if (!versionChecker.firePrePostEvents()) {
if (activity.observeOpening() && !versionChecker.firePrePostEvents()) {
create(activity)
}
}

override fun onActivityPostCreated(activity: Activity, savedInstanceState: Bundle?) {
createEnd(activity)
if (activity.observeOpening()) {
createEnd(activity)
}
}

override fun onActivityPreStarted(activity: Activity) {
start(activity)
if (activity.observeOpening()) {
start(activity)
}
}

override fun onActivityStarted(activity: Activity) {
if (!versionChecker.firePrePostEvents()) {
if (activity.observeOpening() && !versionChecker.firePrePostEvents()) {
createEnd(activity)
start(activity)
}
}

override fun onActivityPostStarted(activity: Activity) {
startEnd(activity)
if (activity.observeOpening()) {
startEnd(activity)
}
}

override fun onActivityPreResumed(activity: Activity) {
resume(activity)
if (activity.observeOpening()) {
resume(activity)
}
}

override fun onActivityResumed(activity: Activity) {
if (!versionChecker.firePrePostEvents()) {
if (activity.observeOpening() && !versionChecker.firePrePostEvents()) {
startEnd(activity)
resume(activity)
}
}

override fun onActivityPostResumed(activity: Activity) {
resumeEnd(activity)
if (activity.observeOpening()) {
resumeEnd(activity)
}
}

override fun onActivityPrePaused(activity: Activity) {
Expand Down Expand Up @@ -148,4 +161,6 @@ class OpenEventEmitter(
private fun traceInstanceId(activity: Activity): Int = activity.hashCode()

private fun nowMs(): Long = clock.now().nanosToMillis()

private fun Activity.observeOpening() = javaClass.isAnnotationPresent(ObservedActivity::class.java)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Activity
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeObservedActivity
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.POST_DURATION
Expand All @@ -19,6 +20,7 @@ import org.robolectric.Robolectric
import org.robolectric.RuntimeEnvironment
import org.robolectric.android.controller.ActivityController
import org.robolectric.annotation.Config
import kotlin.reflect.KClass

@RunWith(AndroidJUnit4::class)
internal class OpenEventEmitterTest {
Expand All @@ -41,14 +43,12 @@ internal class OpenEventEmitterTest {
clock = initModule.openTelemetryModule.openTelemetryClock,
versionChecker = BuildVersionChecker,
)
activityController = Robolectric.buildActivity(Activity::class.java)
RuntimeEnvironment.getApplication().registerActivityLifecycleCallbacks(
ClockTickingActivityLifecycleCallbacks(clock)
)
RuntimeEnvironment.getApplication().registerActivityLifecycleCallbacks(eventEmitter)
startTimeMs = clock.now()
instanceId = activityController.get().hashCode()
activityName = activityController.get().localClassName
setupActivityController(FakeObservedActivity::class)
}

@Config(sdk = [Build.VERSION_CODES.UPSIDE_DOWN_CAKE])
Expand Down Expand Up @@ -199,6 +199,50 @@ internal class OpenEventEmitterTest {
)
}

@Config(sdk = [Build.VERSION_CODES.UPSIDE_DOWN_CAKE])
@Test
fun `unobserved activities will not emit open events in U`() {
setupActivityController(Activity::class)
stepThroughActivityLifecycle()
openEvents.events.assertEventData(
listOf(
createEvent(
stage = "resetTrace",
timestampMs = startTimeMs + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3 + PRE_DURATION
),
createEvent(
stage = "hibernate",
timestampMs = startTimeMs + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 4 + STATE_DURATION
),
)
)
}

@Config(sdk = [Build.VERSION_CODES.LOLLIPOP])
@Test
fun `unobserved activities will not emit open events in L`() {
setupActivityController(Activity::class)
stepThroughActivityLifecycle()
openEvents.events.assertEventData(
listOf(
createEvent(
stage = "resetTrace",
timestampMs = startTimeMs + STATE_DURATION * 4
),
createEvent(
stage = "hibernate",
timestampMs = startTimeMs + STATE_DURATION * 5
),
)
)
}

private fun <T : Activity> setupActivityController(activityClass: KClass<T>) {
activityController = Robolectric.buildActivity(activityClass.java)
instanceId = activityController.get().hashCode()
activityName = activityController.get().localClassName
}

private fun stepThroughActivityLifecycle(
isColdOpen: Boolean = true
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.embrace.android.embracesdk.fakes

import android.app.Activity
import io.embrace.android.embracesdk.annotation.ObservedActivity

@ObservedActivity
class FakeObservedActivity : Activity()

0 comments on commit 19a8def

Please sign in to comment.