Skip to content

feat: [SDK-5369] session model and sessions v2 feature flag - #2774

Merged
fadi-george merged 8 commits into
new-session-eventsfrom
fadi/sdk-5369
Oct 9, 2026
Merged

fadi-george merged 8 commits into
new-session-eventsfrom
fadi/sdk-5369

Conversation

@fadi-george

@fadi-george fadi-george commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Description

One Line Summary

Capture the sdk_sessions_v2_api_cutover flag and pinned user/subscription IDs on SessionModel at session start, and measure v2 session duration with a monotonic clock.

Details

Motivation

First Android PR in the SDK Sessions stack (SDK-5368). Later PRs need a persisted per-session record that knows which path the session is on and which user/subscription it belongs to, even after login.

Scope

  • Bumps the OneSignal-KMP-SDK submodule to add FeatureFlag.SDK_SESSIONS_V2_API_CUTOVER (feat: [SDK-5369] add sdk_sessions_v2_api_cutover feature flag OneSignal-KMP-SDK#27). Bump to the merged commit before this lands.
  • ITime.elapsedRealtimeMillis backed by SystemClock.elapsedRealtime().
  • SessionModel adds usesSessionsApi, onesignalId, subscriptionId, serverSessionId, focusElapsedRealtime.
  • SessionService on new session: sets usesSessionsApi from the flag once, pins the current OneSignal ID and push subscription ID, and clears serverSessionId. The choice stays fixed for the session, so a session ended in a new process (e.g. from SyncJobService) still takes the same path.
  • When the flag is on, activeDuration uses the monotonic clock; an interval spanning a reboot counts as 0.
  • Flag off: duration still uses the wall clock and nothing reads the new fields, so behavior is unchanged.
  • No network calls.

Other

A session that starts before the user is created pins local IDs. When the backend replaces a local OneSignal ID or push subscription ID in place, SessionService carries the backend ID over to the pinned copy. Logins, user switches, and local-to-local changes leave pinned IDs alone. The operation repo's ID translation does not cover this, since it only rewrites operations queued at response time.

Testing

Unit testing

New SessionServiceTests: flag capture on/off, flag fixed mid-session, IDs pinned after login, local IDs replaced by backend IDs (and not by later or other local IDs), monotonic duration, reboot interval, and all model fields surviving a reload from preferences. Full core unit suite, spotlessCheck, detekt, and assembleRelease pass.

Manual testing

Not tested on a device. No user-facing behavior changes with the flag off.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

🤖 Generated with Claude Code

fadi-george and others added 2 commits October 6, 2026 10:50
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@fadi-george
fadi-george requested a review from a team as a code owner October 6, 2026 19:00
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

📊 Diff Coverage Report

Diff Coverage Report (Changed Lines Only)

Gate: aggregate coverage on changed executable lines must be ≥ 80% (JaCoCo line data for lines touched in the diff).

Changed Files Coverage

  • Time.kt: 0/1 touched executable lines (0.0%) (2 touched lines in diff)
    • 1 uncovered touched lines in this file
  • OneSignalImp.kt: 1/1 touched executable lines (100.0%) (2 touched lines in diff)
  • SessionModel.kt: 15/15 touched executable lines (100.0%) (50 touched lines in diff)
  • SessionService.kt: 49/50 touched executable lines (98.0%) (87 touched lines in diff)
  • AppIdResolution.kt: 5/5 touched executable lines (100.0%) (15 touched lines in diff)
  • ⚠️ MockHelper.kt: Not in coverage report (may not be compiled/tested)

Overall (aggregate gate)

70/72 touched executable lines covered (97.2% — requires ≥ 80%)

Per-file detail (informational; gate is aggregate above):

  • Time.kt: 0.0% (1 uncovered touched lines)

📥 View workflow run

fadi-george and others added 4 commits October 6, 2026 12:53
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…essions API sessions

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@fadi-george
fadi-george added this pull request to stack #2776 October 6, 2026 22:45

@abdulraqeeb33 abdulraqeeb33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two blockers.

Login before the anonymous user is created can retarget the subscription pin while the OneSignal pin stays on the anonymous local ID. The KMP gitlink is still the unmerged PR branch.

Comment thread OneSignal-KMP-SDK Outdated

@abdulraqeeb33 abdulraqeeb33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed on top of new-session-events.

No change requested. The flag is still captured once per new session, and v2 duration still uses the monotonic clock.

Threading looks sound. Focus, unfocus, and the local-to-backend pin update all apply on the serial IO queue. The clocks are captured on the caller thread before that hop, same as the existing focus timestamp. featureManager.isEnabled is safe to call from that queue. endSession from backgroundRun still runs off the queue and does not read the new fields. The hasProperty check and the onesignalId read take the model lock separately, but a replace holds that lock across the clear and the refill, and the replacement always includes onesignal_id, so the getter does not observe a missing key.

SessionModel.kt: the serverSessionId note restates the property name.

- Point the KMP submodule at the merged commit on new-session-events
- Skip pinned subscription ID updates once the session's user is no longer current
- Drop cached remote feature flags when the appId changes
- Cover the sessions API resume path

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@abdulraqeeb33 abdulraqeeb33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All three findings from my last pass are fixed and verified at this head. Thanks.

Nit, non-blocking: the AppIdResolution KDoc reads as if every flag switches with the app. APP_STARTUP flags keep the previous app's value until next launch, so worth saying that, and a OneSignalImp level test for the app id change path would lock it in.

@fadi-george
fadi-george merged commit 99688f4 into new-session-events Oct 9, 2026
5 checks passed
@fadi-george
fadi-george deleted the fadi/sdk-5369 branch October 9, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants