Skip to content

Implement SessionInitiator and hook it up to lifecycle events #4723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 28, 2023

Conversation

mrober
Copy link
Contributor

@mrober mrober commented Feb 28, 2023

Implement SessionInitiator and hook it up to lifecycle events.

This is responsible for calling the initiateSessionStart callback whenever a session starts.

Used Longs for time, not go/goodtime, to keep the SDK light on older android api levels. Put the unit on every time variable.

Added unit tests. Used fakes, not mocks or stubs frameworks, similar to the iOS SDK.

@google-oss-bot
Copy link
Contributor

1 Warning
⚠️ Did you forget to add a changelog entry? (Add the 'no-changelog' label to the PR to silence this warning.)

Generated by 🚫 Danger

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 28, 2023

Coverage Report 1

Affected Products

  • firebase-sessions

    Overall coverage changed from ? (402c686) to 0.00% (76c2eab) by ?.

    FilenameBase (402c686)Merge (76c2eab)Diff
    FirebaseSessions.kt?0.00%?
    FirebaseSessionsRegistrar.kt?0.00%?
    SessionInitiator.kt?0.00%?

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/QKu7xEbWGN.html

@mrober mrober requested a review from visumickey February 28, 2023 15:48
@github-actions
Copy link
Contributor

github-actions bot commented Feb 28, 2023

Unit Test Results

0 tests   0 ✔️  0s ⏱️
0 suites  0 💤
0 files    0

Results for commit c65a3ba.

♻️ This comment has been updated with latest results.

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 28, 2023

Size Report 1

Affected Products

  • base

    TypeBase (402c686)Merge (76c2eab)Diff
    apk (aggressive)?8.39 kB? (?)
    apk (release)?8.65 kB? (?)
  • firebase-annotations

    TypeBase (402c686)Merge (76c2eab)Diff
    apk (aggressive)?8.39 kB? (?)
    apk (release)?9.46 kB? (?)
  • firebase-common

    TypeBase (402c686)Merge (76c2eab)Diff
    aar?67.6 kB? (?)
    apk (aggressive)?111 kB? (?)
    apk (release)?1.26 MB? (?)
  • firebase-common-ktx

    TypeBase (402c686)Merge (76c2eab)Diff
    aar?13.2 kB? (?)
    apk (aggressive)?123 kB? (?)
    apk (release)?1.64 MB? (?)
  • firebase-components

    TypeBase (402c686)Merge (76c2eab)Diff
    aar?44.9 kB? (?)
    apk (aggressive)?23.1 kB? (?)
    apk (release)?596 kB? (?)
  • firebase-sessions

    TypeBase (402c686)Merge (76c2eab)Diff
    aar?12.5 kB? (?)
    apk (aggressive)?130 kB? (?)
    apk (release)?1.64 MB? (?)

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/6KqykGoB0x.html

val sessionInitiator = SessionInitiator(System::currentTimeMillis, this::initiateSessionStart)
val context = firebaseApp.applicationContext.applicationContext
if (context is Application) {
context.registerActivityLifecycleCallbacks(sessionInitiator.activityLifecycleCallbacks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Make this part of the constructor for SessionInitiator instead of exposing the activityLifecycleCallbacks property

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way so the SessionInitiator outer class wouldn't have any Context or Activity in the ctor to make the tests simpler.

private const val SMALL_INTERVAL_MS = 3 * 1000L // not enough time to initiate a new session
private const val LARGE_INTERVAL_MS = 90 * 60 * 1000L // enough to initiate another session
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are great 👍

Copy link
Contributor

@samedson samedson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple suggestions, but otherwise looks good!

@mrober mrober merged commit e12458f into firebase-sessions Feb 28, 2023
@mrober mrober deleted the sessions-callback branch February 28, 2023 23:04
Copy link
Contributor

@visumickey visumickey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making these changes. Since these are merged now - we can make these changes (if any) in a separate PR.

val sessionInitiator = SessionInitiator(System::currentTimeMillis, this::initiateSessionStart)
val context = firebaseApp.applicationContext.applicationContext
if (context is Application) {
context.registerActivityLifecycleCallbacks(sessionInitiator.activityLifecycleCallbacks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check if the context is already registered for lifecycle callbacks? This is to ensure that we are not registering multiple times.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sam suggested moving this to the SessionInitiator ctor. If we do that, then that instance can only get registered once. Would that be enough to ensure this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends on if the SessionInitator constructor will be called just once or more than once. Also, would the loss of a SessionInitiator object cause a deRegister to be called automatically? If so, this refactor should be fine.

.factory { FirebaseSessions() }
.add(Dependency.required(FirebaseApp::class.java))
.factory { container -> FirebaseSessions(container.get(FirebaseApp::class.java)) }
.eagerInDefaultApp()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why eager initialization? Should we go with lazy? Thoughts @davidmotson

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set eager because I want the first session to start at app launch. Would lazy still be good enough for that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think lazy should be fine. With eager my concern is that we might impact the startup time of the application. Especially since we would be dependent on libraries like Installations and Firelog.

The only caveat here would be the start time of a session. I think the start time of a session and the application start time are different from each other. So, I think lazy should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I make it lazy, it never initiates on my test app if I never access the SDK. Are we sure that's what we want? When Crashlytics and Fireperf depend on it, will they always access it on every launch?


override fun onActivityPaused(activity: Activity) = appBackgrounded()

override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious if this will be the place to kick start a session event?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean onActivityCreated? We call initiateSessionStart() when the class is constructed for the cold boot case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was my question. I get that part now. Will the code to start a new session be called in a later PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The init { ... } block gets called as part of the ctor, and that calls initiateSessionStart() already. So we start a new session when this object is constructed, representing the cold boot. And we also call it on foreground after the session timeout elapsed.

@firebase firebase locked and limited conversation to collaborators Mar 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants