Skip to content

feat: add Firebase telemetry tracking for android client#1067

Open
DELTA-45-G wants to merge 11 commits into
mosip:masterfrom
DELTA-45-G:feat/719-telemetry-android-client
Open

feat: add Firebase telemetry tracking for android client#1067
DELTA-45-G wants to merge 11 commits into
mosip:masterfrom
DELTA-45-G:feat/719-telemetry-android-client

Conversation

@DELTA-45-G
Copy link
Copy Markdown

@DELTA-45-G DELTA-45-G commented May 19, 2026

Summary

Added Firebase telemetry integration for the Android Registration Client.

Changes

  • Added telemetry service and manager
  • Added telemetry event tracking
  • Added navigation telemetry support
  • Added telemetry configuration files
  • Integrated telemetry into app startup and login flow

Notes

  • Removed temporary mock login changes before commit
  • Excluded generated desktop plugin files from commit

Summary by CodeRabbit

  • New Features

    • Added a telemetry system (screen/navigation tracking, events, performance) with opt-in control and device info collection.
    • Integrated Firebase analytics and crash reporting.
  • Bug Fixes

    • Fixed login state handling and default fallbacks.
    • Telemetry now records network failures and improved error reporting.
    • Improved widget lifecycle to avoid localization/init ordering issues.
  • Chores

    • Updated Android build/tooling targets and Gradle wrapper.
    • Expanded ignore rules for generated Flutter/Dart artifacts; added Firebase setup docs.
  • Tests

    • Updated widget tests and test setup.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Firebase-backed telemetry (core types, service, manager), collects device info, tracks screens/navigation, instruments login and network flows, updates app startup to initialize Firebase and telemetry, modernizes Android build to API 34, updates dependencies/gitignore, and adjusts widget tests.

Changes

Telemetry System Implementation

Layer / File(s) Summary
Android build modernization and Firebase setup
.gitignore, android/.gitignore, android/app/build.gradle, android/build.gradle, android/clientmanager/build.gradle, android/gradle/wrapper/gradle-wrapper.properties, android/jacoco.gradle, android/keymanager/build.gradle, android/packetmanager/build.gradle, android/transliterationmanager/build.gradle, pubspec.yaml
Android SDK levels and build tooling are upgraded to API 34, Gradle/Kotlin/AGP versions bumped, Google Services/Firebase BOM and analytics added, Jacoco wrapper/settings updated, Gradle wrapper bumped, and gitignore rules and pubspec deps extended.
Telemetry event and configuration layer
lib/telemetry/telemetry_config.dart, lib/telemetry/telemetry_event.dart, lib/telemetry/telemetry_logger.dart, lib/telemetry/telemetry_manager.dart
Adds TelemetryConfig toggle, TelemetryEvent model (timestamp + toJson), TelemetryLogger (stdout mock), and TelemetryManager that persists enabled state and forwards events to Firebase Analytics.
Telemetry service and device info collection
lib/telemetry/telemetry_service.dart
TelemetryService collects Android device/app metadata on init, records app-start performance, and exposes trackEvent/trackScreen/logError/trackPerformance wrappers that merge device info with event data.
Screen and navigation telemetry
lib/telemetry/telemetry_navigation.dart, lib/telemetry/telemetry_screen_wrapper.dart, lib/app_router.dart
Adds TelemetryNavigationObserver to emit screen_view on route push/pop, TelemetryScreenWrapper triggers screen tracking on init, and AppRouter currently contains the wrapper as commented examples; active routes return pages directly.
Firebase and telemetry app initialization
lib/main.dart
main() awaits Firebase.initializeApp() first, then initializes TelemetryService and TelemetryManager, and registers TelemetryNavigationObserver in navigatorObservers.
Login flow telemetry integration
lib/ui/login_page.dart
LoginPage logs login_clicked, login_attempt (with username presence), login_failed (with error details), and login_success; provider initialization updated to use context.read().
Network and auth service improvements
lib/platform_android/auth_service_impl.dart, lib/platform_android/network_service_impl.dart, lib/provider/auth_provider.dart, lib/ui/machine_keys.dart
AuthServiceImpl methods default return values to "0" instead of uninitialized late vars. NetworkServiceImpl logs network_failure telemetry and errors. AuthProvider.setIsLoggingIn uses the provided value. MachineKeys defers localization init to didChangeDependencies().
Test adjustments for new architecture
test/widget_test.dart
Adds SyncProvider to test wrapper and simplifies/reworks multiple widget tests to rely on presence checks rather than exact layout counts.

Sequence Diagram(s)

sequenceDiagram
  participant AppStart as App Startup
  participant Firebase as Firebase
  participant TelemetryService as TelemetryService
  participant TelemetryManager as TelemetryManager
  participant DeviceInfo as Device Info
  participant FirebaseAnalytics as Firebase Analytics

  AppStart->>Firebase: Firebase.initializeApp()
  AppStart->>TelemetryService: TelemetryService.init()
  TelemetryService->>DeviceInfo: collect device metadata
  TelemetryService->>TelemetryManager: logEvent(app_start_time)
  TelemetryManager->>FirebaseAnalytics: logEvent(app_start_time)
  AppStart->>TelemetryManager: TelemetryManager.initialize()
  TelemetryManager->>FirebaseAnalytics: setAnalyticsCollectionEnabled(telemetry_enabled)
  AppStart->>AppStart: Register TelemetryNavigationObserver
Loading
sequenceDiagram
  participant User as User
  participant LoginPage as LoginPage
  participant AuthProvider as AuthProvider
  participant TelemetryService as TelemetryService
  participant FirebaseAnalytics as Firebase Analytics

  User->>LoginPage: Clicks login
  LoginPage->>TelemetryService: trackEvent(login_clicked)
  LoginPage->>TelemetryService: trackEvent(login_attempt, {has_username})
  LoginPage->>AuthProvider: Authenticate
  alt Authentication succeeds
    AuthProvider-->>LoginPage: Success
    LoginPage->>TelemetryService: trackEvent(login_success)
    LoginPage->>FirebaseAnalytics: Navigate
  else Authentication fails
    AuthProvider-->>LoginPage: Error
    LoginPage->>TelemetryService: trackEvent(login_failed, {error})
    TelemetryService->>FirebaseAnalytics: logEvent(login_failed)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • SachinPremkumar
  • anushasunkada

Poem

🐰
I hopped into code on a telemetry quest,
Firebase listens as events find their nest.
Screens now sing when routes arrive and part,
Errors and metrics penned with a rabbit's heart.
Carrots for builds, and tests that pass with art!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Firebase telemetry tracking for android client' directly and clearly describes the main change—adding Firebase telemetry integration to the Android client with comprehensive implementation across services, configuration, and app startup/login flows.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/platform_android/auth_service_impl.dart (1)

115-121: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix incorrect failure log message in getAutoLogoutPopupTimeout().

Line 120 logs "getIdleTime call failed!", which does not match the method and makes debugging noisy.

Suggested fix
-    } on PlatformException {
-      debugPrint('getIdleTime call failed!');
+    } on PlatformException {
+      debugPrint('getAutoLogoutPopupTimeout call failed!');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 115 - 121, Update
the failure log in getAutoLogoutPopupTimeout(): when catching PlatformException
(and/or general errors) replace the incorrect message "getIdleTime call failed!"
with a message that accurately references getAutoLogoutPopupTimeout (e.g.,
"getAutoLogoutPopupTimeout call failed!") so logs match the method; locate the
method Future<String> getAutoLogoutPopupTimeout() and the PlatformException
catch block where debugPrint is called and change the string accordingly to
reflect the correct function name (and do the same for other catch branches if
they use the same wrong message).
lib/ui/login_page.dart (1)

353-362: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Emit login_success for all successful login flows.

login_success is only tracked in the non-auto-sync branch, so successful logins that trigger _autoSyncHandler() are missed in telemetry.

Suggested fix
-    if (authProvider.isLoggedIn &&
-        (syncProvider.lastSuccessfulSyncTime == "LastSyncTimeIsNull")) {
+    TelemetryService.trackEvent("login_success");
+    if (authProvider.isLoggedIn &&
+        (syncProvider.lastSuccessfulSyncTime == "LastSyncTimeIsNull")) {
       log("sync time: ${syncProvider.lastSuccessfulSyncTime}");
       syncProvider.setIsGlobalSyncInProgress(true);
       await _autoSyncHandler();
     } else {
       authProvider.setIsSyncing(false);
-      TelemetryService.trackEvent("login_success");
       await _navigateToHomePage();
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/ui/login_page.dart` around lines 353 - 362, The telemetry event
"login_success" is only emitted in the else branch and is missed when the code
enters the auto-sync branch; update the logic around authProvider.isLoggedIn /
syncProvider.lastSuccessfulSyncTime so that
TelemetryService.trackEvent("login_success") is called for all successful login
flows (either move the call before the if/else or add the call inside the
auto-sync branch), and ensure existing behavior (calling _autoSyncHandler(),
authProvider.setIsSyncing(false), and _navigateToHomePage()) remains unchanged;
reference authProvider.isLoggedIn, syncProvider.lastSuccessfulSyncTime,
_autoSyncHandler(), and _navigateToHomePage() when making the change.
🧹 Nitpick comments (3)
lib/telemetry/telemetry_navigation.dart (1)

8-17: ⚡ Quick win

Track only PageRoute instances for screen telemetry.

Line 8 and Line 13 currently track every route type; that includes dialog/popup routes and can pollute screen_view metrics. Gate tracking to PageRoute.

Proposed change
   `@override`
   void didPush(Route route, Route? previousRoute) {
-    _trackScreen(route);
+    if (route is PageRoute) {
+      _trackScreen(route);
+    }
   }

   `@override`
   void didPop(Route route, Route? previousRoute) {
-    if (previousRoute != null) {
+    if (previousRoute is PageRoute) {
       _trackScreen(previousRoute);
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/telemetry/telemetry_navigation.dart` around lines 8 - 17, The telemetry
currently tracks every Route in didPush and didPop which can include
dialogs/popups; update didPush(Route route, ...) and didPop(Route route, ...) to
only call _trackScreen when the route (or previousRoute) is an instance of
PageRoute (e.g., use an is PageRoute check or cast before calling _trackScreen).
Specifically, guard the calls to _trackScreen in both the didPush and didPop
handlers so only PageRoute instances are passed to _trackScreen.
android/app/build.gradle (1)

140-324: ⚡ Quick win

Remove duplicate dependency declarations.

The dependencies block contains numerous duplicate entries (e.g., Dagger, Room, Retrofit, OkHttp appear 2-3 times). This increases maintenance burden and risks version conflicts.

♻️ Consolidate dependencies

Review and deduplicate all dependency declarations. Keep only one declaration per library. For example:

 dependencies {
     def fragment_version = "1.4.1"
     def room_version = "2.4.0"
 
     implementation 'javax.inject:javax.inject:1'
     implementation 'com.google.dagger:dagger:2.41'
     implementation 'com.google.dagger:dagger-android-support:2.41'
     annotationProcessor 'com.google.dagger:dagger-compiler:2.41'
     annotationProcessor 'com.google.dagger:dagger-android-processor:2.41'
-    // ... remove duplicate dagger entries below ...

Run this script to identify all duplicates:

#!/bin/bash
# Find duplicate dependencies in build.gradle
echo "Duplicate dependency check:"
rg -oP "^\s*(implementation|api|testImplementation|androidTestImplementation|annotationProcessor)\s+['\"]([^'\"]+)" android/app/build.gradle | \
  awk '{print $2}' | sort | uniq -d
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@android/app/build.gradle` around lines 140 - 324, The dependencies block
contains many duplicated entries (e.g., com.google.dagger:dagger:2.41,
androidx.room:room-runtime, com.squareup.retrofit2:retrofit:2.9.0,
com.auth0.android:jwtdecode:2.0.1, okhttp/okio, junit/mocking libs) which should
be consolidated; open the dependencies block and remove repeated declarations so
each artifact (identify by its Maven coordinates like
com.google.dagger:dagger:2.41, androidx.room:room-runtime:2.4.2,
com.squareup.retrofit2:retrofit:2.9.0, com.squareup.okhttp3:okhttp:4.9.2,
com.auth0.android:jwtdecode:2.0.1, etc.) appears only once, keep the desired
version you want to standardize on, merge any test vs androidTest duplicates
appropriately (preserve test-specific scopes), and ensure annotationProcessor
entries for dagger/room/lombok remain singular and match the runtime entries.
lib/telemetry/telemetry_manager.dart (1)

55-85: ⚡ Quick win

Remove the commented legacy implementation block.

The old queue-based implementation in comments is dead code and makes the class harder to maintain.

Proposed cleanup
-// import 'telemetry_event.dart';
-// import 'telemetry_logger.dart';
-...
-// }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/telemetry/telemetry_manager.dart` around lines 55 - 85, Remove the entire
commented-out legacy queue implementation block for TelemetryManager (the
commented imports and the commented class containing
TelemetryEvent/_queue/logEvent/addEvent/_flush) — keep only the active
implementation files and references; ensure any usages still rely on the real
TelemetryManager API (e.g., TelemetryManager.logEvent,
TelemetryManager.addEvent) and that TelemetryEvent and TelemetryLogger imports
used elsewhere are intact, but delete the dead commented code to clean up the
file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@android/app/build.gradle`:
- Line 51: Replace hard-coded SDK version literals by using the Flutter-provided
fallbacks: update the compileSdkVersion and targetSdkVersion occurrences to use
flutter.compileSdkVersion ?: 34 and flutter.targetSdkVersion ?: 34 respectively
(so they defer to Flutter values when present), and ensure the Gradle script
still has the Flutter plugin/config exposing the flutter object; if you
intentionally must pin versions, add a brief comment explaining why the override
is required.
- Around line 161-162: Add README instructions for Firebase setup: explain how
to obtain google-services.json from the Firebase console, instruct developers to
place that file in android/app/ so the build.gradle dependencies
(platform('com.google.firebase:firebase-bom:34.12.0') and
'com.google.firebase:firebase-analytics') can pick it up, and document CI/CD
handling (store the file as a secret in your CI provider and inject it into
android/app/ at build time or use environment-variable based Gradle replacement)
along with a brief note that google-services.json is gitignored and must be
provisioned per-developer or via pipeline.

In `@lib/app_router.dart`:
- Around line 22-55: Routes currently wrap pages with TelemetryScreenWrapper
which duplicates screen events already emitted by TelemetryNavigationObserver;
remove the wrapper and return the page widgets directly in the route map (e.g.,
replace occurrences of TelemetryScreenWrapper(screenName: "...", child: Xyz())
with just Xyz() or const Xyz()) so navigation observer is the single source of
truth for screen tracking; update all routes referencing TelemetryScreenWrapper
(examples: LoginPage.route, OnboardLandingPage.route, HomePage.route and
GenericProcess routes) to return their child widgets unwrapped.

In `@lib/telemetry/telemetry_manager.dart`:
- Around line 9-17: The telemetry flag _isEnabled in telemetry_manager.dart
currently defaults to true, allowing telemetry to be active before
SharedPreferences is loaded; change the default to false (or make _isEnabled
nullable and treat null as disabled) and ensure initialize() reads prefs and
then calls _analytics.setAnalyticsCollectionEnabled(_isEnabled) before any code
can log events; update any telemetry-entry points to check _isEnabled (or await
initialize) so no events are sent prior to consent, referencing the static field
_isEnabled and the initialize() method and the
_analytics.setAnalyticsCollectionEnabled call.

In `@lib/telemetry/telemetry_service.dart`:
- Around line 54-56: The logError method in telemetry_service.dart currently
sends raw exception text by calling error.toString() to trackEvent("error"),
which can leak sensitive data; change logError (and any callers) to send only
non-sensitive identifiers such as error.runtimeType.toString(), a short
non-reversible fingerprint (e.g. a SHA-256 hash) of the full message if you need
deduplication, and optional sanitized/whitelisted fields rather than the raw
message; update the call site to pass a data map like {"type": errorType,
"fingerprint": fingerprint} to trackEvent and remove/error-redact any direct use
of error.toString() while keeping trackEvent usage intact.

In `@lib/ui/machine_keys.dart`:
- Around line 44-47: Replace the hardcoded fallback "Not initialized" with the
localized string from appLocalizations.not_initialized where machineDetails is
set (e.g., inside the map.isEmpty branch and the similar block at lines 54-58);
locate the assignments to machineDetails in machine_keys.dart (the map.isEmpty
check and the other fallback) and use appLocalizations.not_initialized instead
of the literal so the UI uses localization once dependencies are available.

---

Outside diff comments:
In `@lib/platform_android/auth_service_impl.dart`:
- Around line 115-121: Update the failure log in getAutoLogoutPopupTimeout():
when catching PlatformException (and/or general errors) replace the incorrect
message "getIdleTime call failed!" with a message that accurately references
getAutoLogoutPopupTimeout (e.g., "getAutoLogoutPopupTimeout call failed!") so
logs match the method; locate the method Future<String>
getAutoLogoutPopupTimeout() and the PlatformException catch block where
debugPrint is called and change the string accordingly to reflect the correct
function name (and do the same for other catch branches if they use the same
wrong message).

In `@lib/ui/login_page.dart`:
- Around line 353-362: The telemetry event "login_success" is only emitted in
the else branch and is missed when the code enters the auto-sync branch; update
the logic around authProvider.isLoggedIn / syncProvider.lastSuccessfulSyncTime
so that TelemetryService.trackEvent("login_success") is called for all
successful login flows (either move the call before the if/else or add the call
inside the auto-sync branch), and ensure existing behavior (calling
_autoSyncHandler(), authProvider.setIsSyncing(false), and _navigateToHomePage())
remains unchanged; reference authProvider.isLoggedIn,
syncProvider.lastSuccessfulSyncTime, _autoSyncHandler(), and
_navigateToHomePage() when making the change.

---

Nitpick comments:
In `@android/app/build.gradle`:
- Around line 140-324: The dependencies block contains many duplicated entries
(e.g., com.google.dagger:dagger:2.41, androidx.room:room-runtime,
com.squareup.retrofit2:retrofit:2.9.0, com.auth0.android:jwtdecode:2.0.1,
okhttp/okio, junit/mocking libs) which should be consolidated; open the
dependencies block and remove repeated declarations so each artifact (identify
by its Maven coordinates like com.google.dagger:dagger:2.41,
androidx.room:room-runtime:2.4.2, com.squareup.retrofit2:retrofit:2.9.0,
com.squareup.okhttp3:okhttp:4.9.2, com.auth0.android:jwtdecode:2.0.1, etc.)
appears only once, keep the desired version you want to standardize on, merge
any test vs androidTest duplicates appropriately (preserve test-specific
scopes), and ensure annotationProcessor entries for dagger/room/lombok remain
singular and match the runtime entries.

In `@lib/telemetry/telemetry_manager.dart`:
- Around line 55-85: Remove the entire commented-out legacy queue implementation
block for TelemetryManager (the commented imports and the commented class
containing TelemetryEvent/_queue/logEvent/addEvent/_flush) — keep only the
active implementation files and references; ensure any usages still rely on the
real TelemetryManager API (e.g., TelemetryManager.logEvent,
TelemetryManager.addEvent) and that TelemetryEvent and TelemetryLogger imports
used elsewhere are intact, but delete the dead commented code to clean up the
file.

In `@lib/telemetry/telemetry_navigation.dart`:
- Around line 8-17: The telemetry currently tracks every Route in didPush and
didPop which can include dialogs/popups; update didPush(Route route, ...) and
didPop(Route route, ...) to only call _trackScreen when the route (or
previousRoute) is an instance of PageRoute (e.g., use an is PageRoute check or
cast before calling _trackScreen). Specifically, guard the calls to _trackScreen
in both the didPush and didPop handlers so only PageRoute instances are passed
to _trackScreen.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 587a9170-b86b-4b76-9b5b-9455f80bbb7e

📥 Commits

Reviewing files that changed from the base of the PR and between aef4fb6 and b5719fe.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (26)
  • .gitignore
  • android/.gitignore
  • android/app/build.gradle
  • android/build.gradle
  • android/clientmanager/build.gradle
  • android/gradle/wrapper/gradle-wrapper.properties
  • android/jacoco.gradle
  • android/keymanager/build.gradle
  • android/packetmanager/build.gradle
  • android/transliterationmanager/build.gradle
  • lib/app_router.dart
  • lib/main.dart
  • lib/platform_android/auth_service_impl.dart
  • lib/platform_android/network_service_impl.dart
  • lib/provider/auth_provider.dart
  • lib/telemetry/telemetry_config.dart
  • lib/telemetry/telemetry_event.dart
  • lib/telemetry/telemetry_logger.dart
  • lib/telemetry/telemetry_manager.dart
  • lib/telemetry/telemetry_navigation.dart
  • lib/telemetry/telemetry_screen_wrapper.dart
  • lib/telemetry/telemetry_service.dart
  • lib/ui/login_page.dart
  • lib/ui/machine_keys.dart
  • pubspec.yaml
  • test/widget_test.dart

Comment thread android/app/build.gradle
Comment thread android/app/build.gradle
Comment thread lib/app_router.dart Outdated
Comment thread lib/telemetry/telemetry_manager.dart Outdated
Comment thread lib/telemetry/telemetry_service.dart Outdated
Comment thread lib/ui/machine_keys.dart Outdated
@DELTA-45-G DELTA-45-G force-pushed the feat/719-telemetry-android-client branch from b5719fe to 1931385 Compare May 22, 2026 05:44
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (3)
lib/app_router.dart (1)

22-55: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a single source of truth for screen tracking.

These route wrappers emit screen telemetry in addition to the navigation observer, causing duplicate screen_view events.

Proposed fix (keep observer-based tracking)
-    LoginPage.route: (context) => const TelemetryScreenWrapper(
-        screenName: "LoginPage",
-        child: LoginPage(),
-      ),
+    LoginPage.route: (context) => const LoginPage(),

-  '/new_process': (context) => const TelemetryScreenWrapper(
-        screenName: "NewProcess",
-        child: GenericProcess(processType: ProcessType.newProcess),
-      ),
+  '/new_process': (context) => const GenericProcess(processType: ProcessType.newProcess),

-  '/update_process': (context) => const TelemetryScreenWrapper(
-        screenName: "UpdateProcess",
-        child: GenericProcess(processType: ProcessType.updateProcess),
-      ),
+  '/update_process': (context) => const GenericProcess(processType: ProcessType.updateProcess),

-  '/lost_process': (context) => const TelemetryScreenWrapper(
-        screenName: "LostProcess",
-        child: GenericProcess(processType: ProcessType.lostProcess),
-      ),
+  '/lost_process': (context) => const GenericProcess(processType: ProcessType.lostProcess),

-  '/correction_process': (context) => const TelemetryScreenWrapper(
-        screenName: "CorrectionProcess",
-        child: GenericProcess(processType: ProcessType.correctionProcess),
-      ),
+  '/correction_process': (context) => const GenericProcess(processType: ProcessType.correctionProcess),

-  OnboardLandingPage.route: (context) => const TelemetryScreenWrapper(
-        screenName: "OnboardLandingPage",
-        child: OnboardLandingPage(),
-      ),
+  OnboardLandingPage.route: (context) => const OnboardLandingPage(),

-  HomePage.route: (context) => const TelemetryScreenWrapper(
-        screenName: "HomePage",
-        child: HomePage(),
-      ),
+  HomePage.route: (context) => const HomePage(),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/app_router.dart` around lines 22 - 55, The route map currently wraps
pages with TelemetryScreenWrapper (e.g., LoginPage.route,
OnboardLandingPage.route, HomePage.route and the '/new_process',
'/update_process', '/lost_process', '/correction_process' entries) which
duplicates screen_view events when you also have a navigation observer; remove
the TelemetryScreenWrapper wrappers from these route entries and return the
pages directly (e.g., child: LoginPage(), GenericProcess(...),
OnboardLandingPage(), HomePage()) so the observer is the single source of truth
for screen tracking.
lib/telemetry/telemetry_manager.dart (1)

9-17: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail closed before consent is loaded.

Line 9 defaults telemetry to enabled. Any event emitted before initialize() completes can bypass persisted consent.

Proposed fix
-  static bool _isEnabled = true;// This should be loaded from user consent (e.g., SharedPreferences) in initialize()
+  static bool _isEnabled = false; // fail-closed until persisted consent is loaded
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/telemetry/telemetry_manager.dart` around lines 9 - 17, The telemetry flag
currently defaults to true causing events to leak before persisted consent is
read; change the default of _isEnabled to false (fail-closed) and ensure
initialize() calls _analytics.setAnalyticsCollectionEnabled(_isEnabled)
immediately after reading prefs so analytics are disabled until consent is
confirmed; also add guards in any event-emitting methods (e.g., any
trackEvent/record* functions) to check _isEnabled before sending events.
lib/telemetry/telemetry_service.dart (1)

54-56: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid sending raw exception messages in telemetry.

Line 55 forwards error.toString() directly, which can leak sensitive operational or user data.

Proposed mitigation
   static void logError(Object error) {
-    trackEvent("error", data: {"message": error.toString()});
+    trackEvent("error", data: {
+      "type": error.runtimeType.toString(),
+      "message": "redacted",
+    });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/telemetry/telemetry_service.dart` around lines 54 - 56, The logError
method in telemetry_service.dart currently forwards error.toString() to
trackEvent("error", data: {"message": ...}), which can leak sensitive data;
change logError to avoid sending raw exception messages by sending a generic
message (e.g., "Unhandled error") and a non-sensitive fingerprint instead — for
example include only the error's runtimeType or an error code plus a hashed
fingerprint (SHA256) of error.toString() or stack trace for correlation; update
references in logError and the payload passed to trackEvent("error", ...)
accordingly so telemetry contains no raw exception text but still allows
grouping via the fingerprint.
🧹 Nitpick comments (2)
lib/app_router.dart (1)

57-63: ⚡ Quick win

Drop commented-out route code.

Please remove the stale commented mappings to keep the route table maintainable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/app_router.dart` around lines 57 - 63, Remove the stale commented-out
route mappings in lib/app_router.dart: delete the lines referencing
LoginPage.route, the GenericProcess entries (with ProcessType.newProcess,
ProcessType.updateProcess, ProcessType.lostProcess,
ProcessType.correctionProcess), OnboardLandingPage.route, and HomePage.route so
the route table contains only active mappings and no commented legacy routes.
lib/telemetry/telemetry_manager.dart (1)

55-85: ⚡ Quick win

Remove the commented-out legacy TelemetryManager block.

Keeping the old implementation commented in production code adds noise and makes future edits riskier.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/telemetry/telemetry_manager.dart` around lines 55 - 85, Remove the entire
commented-out legacy TelemetryManager block to eliminate dead code and noise;
delete the commented imports ('telemetry_event.dart', 'telemetry_logger.dart')
and the commented class TelemetryManager including its methods logEvent,
addEvent, and _flush along with related TelemetryEvent/TelemetryLogger
references so only the active implementation remains in
lib/telemetry/telemetry_manager.dart.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/main.dart`:
- Line 244: The app is double-counting screen_view events because
TelemetryNavigationObserver() is registered while screens/routes are also
wrapped with telemetry tracking; either choose a single strategy or add
deduplication: remove TelemetryNavigationObserver from navigatorObservers if you
prefer the route wrapper approach, or if keeping TelemetryNavigationObserver
implement dedupe logic (in the TelemetryNavigationObserver class) that ignores
events for the same route/screen within a short timeframe (e.g., track
lastSeenScreen+timestamp and drop duplicates), or add a guard in the route
wrapper to skip emitting if TelemetryNavigationObserver already emitted for that
route; update TelemetryNavigationObserver and/or the route wrapper to use a
shared dedupe key (route name/screen id + timestamp) so screen_view events are
emitted only once.
- Around line 47-48: TelemetryService.init() is being called before
TelemetryManager.initialize(), which risks emitting startup telemetry before
consent/config is applied; swap the calls so TelemetryManager.initialize() runs
first (load/restore consent and configure Firebase), then call
TelemetryService.init(), or alternatively make TelemetryService.init() wait for
TelemetryManager.isInitialized/isConsentLoaded (use the
TelemetryManager.initialize() future) before bootstrapping any startup events.

In `@lib/platform_android/auth_service_impl.dart`:
- Line 116: The variable declaration for refreshLoginTime has an extra
semicolon; locate the declaration "String refreshLoginTime = \"0\";;" in
auth_service_impl.dart (look for the refreshLoginTime symbol) and remove the
duplicate semicolon so it becomes a single-terminated declaration "String
refreshLoginTime = \"0\";".

In `@lib/platform_android/network_service_impl.dart`:
- Around line 31-37: The telemetry calls in the catch block of
checkInternetConnection (TelemetryService.trackEvent and
TelemetryService.logError) must be guarded so failures in telemetry do not
rethrow and break the method's fallback behavior; wrap those telemetry
invocations in their own try/catch (or check TelemetryService availability) and
swallow/log telemetry errors locally so the original network error handling
continues and checkInternetConnection still returns the intended fallback
result.

---

Duplicate comments:
In `@lib/app_router.dart`:
- Around line 22-55: The route map currently wraps pages with
TelemetryScreenWrapper (e.g., LoginPage.route, OnboardLandingPage.route,
HomePage.route and the '/new_process', '/update_process', '/lost_process',
'/correction_process' entries) which duplicates screen_view events when you also
have a navigation observer; remove the TelemetryScreenWrapper wrappers from
these route entries and return the pages directly (e.g., child: LoginPage(),
GenericProcess(...), OnboardLandingPage(), HomePage()) so the observer is the
single source of truth for screen tracking.

In `@lib/telemetry/telemetry_manager.dart`:
- Around line 9-17: The telemetry flag currently defaults to true causing events
to leak before persisted consent is read; change the default of _isEnabled to
false (fail-closed) and ensure initialize() calls
_analytics.setAnalyticsCollectionEnabled(_isEnabled) immediately after reading
prefs so analytics are disabled until consent is confirmed; also add guards in
any event-emitting methods (e.g., any trackEvent/record* functions) to check
_isEnabled before sending events.

In `@lib/telemetry/telemetry_service.dart`:
- Around line 54-56: The logError method in telemetry_service.dart currently
forwards error.toString() to trackEvent("error", data: {"message": ...}), which
can leak sensitive data; change logError to avoid sending raw exception messages
by sending a generic message (e.g., "Unhandled error") and a non-sensitive
fingerprint instead — for example include only the error's runtimeType or an
error code plus a hashed fingerprint (SHA256) of error.toString() or stack trace
for correlation; update references in logError and the payload passed to
trackEvent("error", ...) accordingly so telemetry contains no raw exception text
but still allows grouping via the fingerprint.

---

Nitpick comments:
In `@lib/app_router.dart`:
- Around line 57-63: Remove the stale commented-out route mappings in
lib/app_router.dart: delete the lines referencing LoginPage.route, the
GenericProcess entries (with ProcessType.newProcess, ProcessType.updateProcess,
ProcessType.lostProcess, ProcessType.correctionProcess),
OnboardLandingPage.route, and HomePage.route so the route table contains only
active mappings and no commented legacy routes.

In `@lib/telemetry/telemetry_manager.dart`:
- Around line 55-85: Remove the entire commented-out legacy TelemetryManager
block to eliminate dead code and noise; delete the commented imports
('telemetry_event.dart', 'telemetry_logger.dart') and the commented class
TelemetryManager including its methods logEvent, addEvent, and _flush along with
related TelemetryEvent/TelemetryLogger references so only the active
implementation remains in lib/telemetry/telemetry_manager.dart.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 51b0a597-1836-401b-8a4f-fa7a07271e5c

📥 Commits

Reviewing files that changed from the base of the PR and between b5719fe and 1931385.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (26)
  • .gitignore
  • android/.gitignore
  • android/app/build.gradle
  • android/build.gradle
  • android/clientmanager/build.gradle
  • android/gradle/wrapper/gradle-wrapper.properties
  • android/jacoco.gradle
  • android/keymanager/build.gradle
  • android/packetmanager/build.gradle
  • android/transliterationmanager/build.gradle
  • lib/app_router.dart
  • lib/main.dart
  • lib/platform_android/auth_service_impl.dart
  • lib/platform_android/network_service_impl.dart
  • lib/provider/auth_provider.dart
  • lib/telemetry/telemetry_config.dart
  • lib/telemetry/telemetry_event.dart
  • lib/telemetry/telemetry_logger.dart
  • lib/telemetry/telemetry_manager.dart
  • lib/telemetry/telemetry_navigation.dart
  • lib/telemetry/telemetry_screen_wrapper.dart
  • lib/telemetry/telemetry_service.dart
  • lib/ui/login_page.dart
  • lib/ui/machine_keys.dart
  • pubspec.yaml
  • test/widget_test.dart
✅ Files skipped from review due to trivial changes (3)
  • .gitignore
  • android/.gitignore
  • android/transliterationmanager/build.gradle

Comment thread lib/main.dart Outdated
Comment thread lib/main.dart
Comment thread lib/platform_android/auth_service_impl.dart Outdated
Comment thread lib/platform_android/network_service_impl.dart Outdated
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
android/app/build.gradle (1)

140-324: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Consolidate duplicate dependencies and resolve version conflicts.

The dependencies block contains extensive duplication, with many libraries declared 2-3 times identically. More critically, commons-io has a version conflict: 2.14.0 at line 199 versus 2.11.0 at line 304.

Examples of duplication:

  • Dagger dependencies appear 3 times (lines 144-148, 214-217, 264-267)
  • Retrofit appears 3 times (lines 180-181, 242-243, 297-298)
  • Test dependencies repeated 3 times each
  • Many AndroidX libraries duplicated 2-3 times

This creates maintenance burden and risks inconsistencies. Gradle will use the last declaration, but developers may unknowingly update only one instance.

♻️ Recommended refactoring approach
  1. Remove all duplicate declarations
  2. Keep only one instance of each dependency
  3. Resolve the commons-io version conflict by choosing one version (prefer 2.14.0 as it's newer)
  4. Consider grouping related dependencies with comments for clarity
 dependencies {
     def fragment_version = "1.4.1"
     def room_version = "2.4.0"

     implementation 'javax.inject:javax.inject:1'
     implementation 'com.google.dagger:dagger:2.41'
     implementation 'com.google.dagger:dagger-android-support:2.41'
     annotationProcessor 'com.google.dagger:dagger-compiler:2.41'
     annotationProcessor 'com.google.dagger:dagger-android-processor:2.41'
     
     // AndroidX libraries
     implementation 'androidx.appcompat:appcompat:1.4.1'
     // ... (keep first instance, remove duplicates)
     
-    implementation group: 'commons-io', name: 'commons-io', version: '2.11.0'
+    // Use 2.14.0 consistently (already declared at line 199)
     
-    // Remove all duplicate Dagger blocks (lines 214-217, 264-267)
-    // Remove all duplicate Retrofit blocks (lines 242-243, 297-298)
-    // Remove all duplicate test dependency blocks
-    // Remove duplicate AndroidX declarations
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@android/app/build.gradle` around lines 140 - 324, The dependencies block
contains many duplicate entries (e.g., 'com.google.dagger:dagger',
'com.squareup.retrofit2:retrofit', various androidTest/test libs) and a
commons-io version conflict (entries with version '2.14.0' and '2.11.0'); fix by
deduplicating so each artifact appears exactly once, consolidate repeated Dagger
entries ('com.google.dagger:dagger', 'dagger-android-support',
'dagger-compiler', 'dagger-android-processor'), Retrofit
('com.squareup.retrofit2:retrofit', 'converter-gson'), test libs, AndroidX libs,
and choose a single commons-io version (prefer '2.14.0'), then group related
dependencies with comments for clarity and remove the redundant repeated blocks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@android/app/build.gradle`:
- Around line 140-324: The dependencies block contains many duplicate entries
(e.g., 'com.google.dagger:dagger', 'com.squareup.retrofit2:retrofit', various
androidTest/test libs) and a commons-io version conflict (entries with version
'2.14.0' and '2.11.0'); fix by deduplicating so each artifact appears exactly
once, consolidate repeated Dagger entries ('com.google.dagger:dagger',
'dagger-android-support', 'dagger-compiler', 'dagger-android-processor'),
Retrofit ('com.squareup.retrofit2:retrofit', 'converter-gson'), test libs,
AndroidX libs, and choose a single commons-io version (prefer '2.14.0'), then
group related dependencies with comments for clarity and remove the redundant
repeated blocks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 60eacf46-4dc7-4229-aff3-ade59aa32399

📥 Commits

Reviewing files that changed from the base of the PR and between 1931385 and 63448fb.

📒 Files selected for processing (1)
  • android/app/build.gradle

@DELTA-45-G DELTA-45-G force-pushed the feat/719-telemetry-android-client branch from 3ed2c84 to 1051228 Compare May 22, 2026 16:02
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib/app_router.dart (1)

15-15: ⚡ Quick win

Remove the commented-out code.

The commented-out import and route definitions (lines 15, 22-55) are dead code left over from resolving the duplicate screen tracking issue. Since the fix has been confirmed and the active routes (lines 57-63) are now the single source of truth, this commented code serves no purpose and should be removed. Version control preserves the history if needed.

🧹 Proposed cleanup
-// import 'package:registration_client/telemetry/telemetry_screen_wrapper.dart';
-
 class AppRouter {
   AppRouter._();
 
   static Map<String, Widget Function(BuildContext)> routes = {
-    //telementary screen
-  //   LoginPage.route: (context) => const TelemetryScreenWrapper(
-  //       screenName: "LoginPage",
-  //       child: LoginPage(),
-  //     ),
-
-  // '/new_process': (context) => const TelemetryScreenWrapper(
-  //       screenName: "NewProcess",
-  //       child: GenericProcess(processType: ProcessType.newProcess),
-  //     ),
-
-  // '/update_process': (context) => const TelemetryScreenWrapper(
-  //       screenName: "UpdateProcess",
-  //       child: GenericProcess(processType: ProcessType.updateProcess),
-  //     ),
-
-  // '/lost_process': (context) => const TelemetryScreenWrapper(
-  //       screenName: "LostProcess",
-  //       child: GenericProcess(processType: ProcessType.lostProcess),
-  //     ),
-
-  // '/correction_process': (context) => const TelemetryScreenWrapper(
-  //       screenName: "CorrectionProcess",
-  //       child: GenericProcess(processType: ProcessType.correctionProcess),
-  //     ),
-
-  // OnboardLandingPage.route: (context) => const TelemetryScreenWrapper(
-  //       screenName: "OnboardLandingPage",
-  //       child: OnboardLandingPage(),
-  //     ),
-
-  // HomePage.route: (context) => const TelemetryScreenWrapper(
-  //       screenName: "HomePage",
-  //       child: HomePage(),
-  //     ),
-    //
     LoginPage.route: (context) => const LoginPage(),

Also applies to: 22-55

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/app_router.dart` at line 15, Remove the dead commented-out code: delete
the commented import "// import
'package:registration_client/telemetry/telemetry_screen_wrapper.dart';" and the
entire commented route block (the stale commented route definitions between the
earlier duplicate tracking fix and the active routes) so only the active routes
remain (the single-source-of-truth block around lines with the current routes).
Ensure no other comments referencing telemetry_screen_wrapper or the old route
names remain in lib/app_router.dart.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lib/app_router.dart`:
- Line 15: Remove the dead commented-out code: delete the commented import "//
import 'package:registration_client/telemetry/telemetry_screen_wrapper.dart';"
and the entire commented route block (the stale commented route definitions
between the earlier duplicate tracking fix and the active routes) so only the
active routes remain (the single-source-of-truth block around lines with the
current routes). Ensure no other comments referencing telemetry_screen_wrapper
or the old route names remain in lib/app_router.dart.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 90b7b871-1a09-48d1-b9cf-52ba980f3908

📥 Commits

Reviewing files that changed from the base of the PR and between 3ed2c84 and 0d2ce41.

📒 Files selected for processing (3)
  • README.md
  • lib/app_router.dart
  • lib/telemetry/telemetry_manager.dart
✅ Files skipped from review due to trivial changes (1)
  • README.md

Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
Signed-off-by: DELTA-45-G <sagarbirwa80@gmail.com>
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.

1 participant