Skip to content

Commit 082edcb

Browse files
committed
added AppStartMetrics automatically unregister lifecycle callback
added foreground check to SentryAndroid.init
1 parent 9b09e73 commit 082edcb

File tree

4 files changed

+59
-0
lines changed

4 files changed

+59
-0
lines changed

sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.sentry.android.core;
22

33
import android.annotation.SuppressLint;
4+
import android.app.Application;
45
import android.content.Context;
56
import android.os.Process;
67
import android.os.SystemClock;
@@ -135,6 +136,10 @@ public static synchronized void init(
135136
appStartTimeSpan.setStartedAt(Process.getStartUptimeMillis());
136137
}
137138
}
139+
if (context.getApplicationContext() instanceof Application) {
140+
appStartMetrics.registerApplicationForegroundCheck(
141+
(Application) context.getApplicationContext());
142+
}
138143
final @NotNull TimeSpan sdkInitTimeSpan = appStartMetrics.getSdkInitTimeSpan();
139144
if (sdkInitTimeSpan.hasNotStarted()) {
140145
sdkInitTimeSpan.setStartedAt(sdkInitMillis);

sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ public void registerApplicationForegroundCheck(final @NotNull Application applic
243243
if (onCreateTime == null) {
244244
appLaunchedInForeground = false;
245245
}
246+
application.unregisterActivityLifecycleCallbacks(instance);
246247
});
247248
}
248249

sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,15 @@ class SentryAndroidTest {
331331
verify(client, times(1)).captureSession(any(), any())
332332
}
333333

334+
@Test
335+
fun `When initializing Sentry a callback is added to application by appStartMetrics`() {
336+
val mockContext = ContextUtilsTestHelper.createMockContext(true)
337+
SentryAndroid.init(mockContext) {
338+
it.dsn = "https://key@sentry.io/123"
339+
}
340+
verify(mockContext.applicationContext as Application).registerActivityLifecycleCallbacks(eq(AppStartMetrics.getInstance()))
341+
}
342+
334343
private fun initSentryWithForegroundImportance(
335344
inForeground: Boolean,
336345
optionsConfig: (SentryAndroidOptions) -> Unit = {},

sentry-android-core/src/test/java/io/sentry/android/core/performance/AppStartMetricsTest.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import io.sentry.android.core.SentryAndroidOptions
99
import io.sentry.android.core.SentryShadowProcess
1010
import org.junit.Before
1111
import org.junit.runner.RunWith
12+
import org.mockito.kotlin.eq
1213
import org.mockito.kotlin.mock
14+
import org.mockito.kotlin.never
15+
import org.mockito.kotlin.verify
1316
import org.robolectric.Shadows
1417
import org.robolectric.annotation.Config
1518
import java.util.concurrent.TimeUnit
@@ -201,4 +204,45 @@ class AppStartMetricsTest {
201204
val timeSpan = AppStartMetrics.getInstance().getAppStartTimeSpanWithFallback(options)
202205
assertFalse(timeSpan.hasStarted())
203206
}
207+
208+
@Test
209+
fun `when registerApplicationForegroundCheck, a callback is registered to application`() {
210+
val application = mock<Application>()
211+
AppStartMetrics.getInstance().registerApplicationForegroundCheck(application)
212+
verify(application).registerActivityLifecycleCallbacks(eq(AppStartMetrics.getInstance()))
213+
}
214+
215+
@Test
216+
fun `when registerApplicationForegroundCheck, a job is posted on main thread to unregistered the callback`() {
217+
val application = mock<Application>()
218+
AppStartMetrics.getInstance().registerApplicationForegroundCheck(application)
219+
verify(application).registerActivityLifecycleCallbacks(eq(AppStartMetrics.getInstance()))
220+
verify(application, never()).unregisterActivityLifecycleCallbacks(eq(AppStartMetrics.getInstance()))
221+
Shadows.shadowOf(Looper.getMainLooper()).idle()
222+
verify(application).unregisterActivityLifecycleCallbacks(eq(AppStartMetrics.getInstance()))
223+
}
224+
225+
@Test
226+
fun `registerApplicationForegroundCheck set foreground state to false if no activity is running`() {
227+
val application = mock<Application>()
228+
AppStartMetrics.getInstance().isAppLaunchedInForeground = true
229+
AppStartMetrics.getInstance().registerApplicationForegroundCheck(application)
230+
assertTrue(AppStartMetrics.getInstance().isAppLaunchedInForeground)
231+
// Main thread performs the check and sets the flag to false if no activity was created
232+
Shadows.shadowOf(Looper.getMainLooper()).idle()
233+
assertFalse(AppStartMetrics.getInstance().isAppLaunchedInForeground)
234+
}
235+
236+
@Test
237+
fun `registerApplicationForegroundCheck keeps foreground state to true if an activity is running`() {
238+
val application = mock<Application>()
239+
AppStartMetrics.getInstance().isAppLaunchedInForeground = true
240+
AppStartMetrics.getInstance().registerApplicationForegroundCheck(application)
241+
assertTrue(AppStartMetrics.getInstance().isAppLaunchedInForeground)
242+
// An activity was created
243+
AppStartMetrics.getInstance().onActivityCreated(mock(), null)
244+
// Main thread performs the check and keeps the flag to true
245+
Shadows.shadowOf(Looper.getMainLooper()).idle()
246+
assertTrue(AppStartMetrics.getInstance().isAppLaunchedInForeground)
247+
}
204248
}

0 commit comments

Comments
 (0)