Skip to content

Conversation

@weitingsun
Copy link
Contributor

@weitingsun weitingsun commented Dec 18, 2025

Description

Implement OTA Update modal

Changelog

CHANGELOG entry: Added OTA updates modal

Related issues

Fixes: #24110

Manual testing steps

Feature: OTA update modal
  In order to keep the app up to date without reinstalling
  As a user
  I want to be prompted to reload when a new OTA update is available

  Background:
    Given the app has launched
    And OTA updates are enabled

  Scenario: Display OTA update modal when a new update is available
    Given a new OTA update has been downloaded in the background
    When I am on the home screen
    Then I see the OTA update modal
    And the modal explains that a new version is ready to use

  Scenario: User chooses to update now
    Given the OTA update modal is visible
    When I tap the "Update now" button
    Then the app reloads to apply the new OTA update

  Scenario: User chooses to update later
    Given the OTA update modal is visible
    When drawer is dismissed
    Then the modal closes
    And the app continues using the current version without reloading

Screenshots/Recordings

Before

After

OTA modal

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Introduces an OTA Updates modal and refactors the OTA update flow to navigate to this modal when a new update is fetched, adding routes, analytics events, and tests.

  • UI/Flow:
    • Add OTAUpdatesModal bottom sheet (app/components/UI/OTAUpdatesModal/*) with Reload action (calls expo-updates.reloadAsync).
    • Refactor useOTAUpdates to check/fetch on app start and navigate to OTAUpdatesModal when fetchUpdateAsync().isNew is true; removes blocking FoxLoader flow in App.
  • Navigation:
    • Register new route Routes.MODAL.OTA_UPDATES_MODAL and screen in RootModalFlow (app/components/Nav/App/App.tsx, app/constants/navigation/Routes.ts).
  • Analytics/Localization:
    • Add MetaMetrics events OTA_UPDATES_MODAL_VIEWED and OTA_UPDATES_MODAL_PRIMARY_ACTION_CLICKED (app/core/Analytics/MetaMetrics.events.ts).
    • Add locale strings under ota_update_modal (locales/languages/en.json).
  • Tests:
    • Add tests for OTAUpdatesModal and useOTAUpdates behavior.
    • Update App tests to mock useOTAUpdates and remove FoxLoader/OTA gating test.

Written by Cursor Bugbot for commit b7c04fc. This will update automatically on new commits. Configure here.

@github-actions
Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot metamaskbot added the team-mobile-platform Mobile Platform team label Dec 18, 2025
@weitingsun weitingsun self-assigned this Dec 18, 2025
@weitingsun weitingsun marked this pull request as ready for review December 19, 2025 00:24
@github-project-automation github-project-automation bot moved this to Needs dev review in PR review queue Dec 19, 2025
@weitingsun weitingsun requested a review from a team as a code owner December 19, 2025 18:33
return {
isCheckingUpdates,
};
}, [navigation, otaUpdatesEnabled]);
Copy link

Choose a reason for hiding this comment

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

Bug: Missing cleanup for InteractionManager callback on unmount

The useEffect in useOTAUpdates schedules a navigation callback via InteractionManager.runAfterInteractions but doesn't return a cleanup function to cancel it. If the Main component unmounts (e.g., user logs out) while the callback is pending, the navigation to OTAUpdatesModal will still be attempted against a potentially stale navigation context. The runAfterInteractions returns a cancellable handle that could be stored and cancelled in a cleanup function returned from the effect.

Fix in Cursor Fix in Web

return {
isCheckingUpdates,
};
}, [navigation, otaUpdatesEnabled]);
Copy link

Choose a reason for hiding this comment

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

Effect may run multiple times despite documentation

The hook's documentation states it "Runs once when the app initially opens," but the useEffect includes navigation in its dependency array. The navigation object from useNavigation() may change identity between renders, causing the effect to re-run. Without a guard (like a useRef to track if the check already ran), this could trigger multiple checkForUpdateAsync calls and multiple navigations to the OTA modal when the navigation object changes.

Fix in Cursor Fix in Web

@github-actions
Copy link
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeCore
  • Risk Level: low
  • AI Confidence: 85%
click to see 🤖 AI reasoning details

This PR introduces a new OTA Updates Modal feature that displays when an over-the-air update is available. The changes include:

  1. New OTAUpdatesModal component - A new bottom sheet modal that prompts users to reload the app when an update is available
  2. Modified useOTAUpdates hook - Changed from blocking app rendering to running in background and navigating to the modal
  3. App.tsx modifications - Removed blocking FoxLoader behavior, added new modal to navigation stack, moved hook call location
  4. New analytics events - Added OTA_UPDATES_MODAL_VIEWED and OTA_UPDATES_MODAL_PRIMARY_ACTION_CLICKED events
  5. New navigation route - Added OTA_UPDATES_MODAL to Routes.ts
  6. Localization strings - Added new strings for the modal

Risk Assessment:

  • The feature is gated by a feature flag (otaUpdatesEnabled), limiting exposure
  • Changes are primarily additive - new modal component and modified hook behavior
  • No existing E2E tests for OTA updates functionality
  • The App.tsx changes are structural but don't fundamentally alter core navigation
  • Comprehensive unit tests are included for the new components

Tag Selection Rationale:

  • SmokeCore is selected because the changes touch the main App.tsx component which is the root of the application navigation. While the changes are low-risk, running core smoke tests ensures the app still loads and navigates correctly after these modifications.

No other tags are needed because:

  • The OTA update feature doesn't affect wallet operations, accounts, transactions, swaps, staking, or any other specific feature areas
  • There are no existing E2E tests for OTA updates to run
  • The changes don't modify any controllers or core engine functionality

View GitHub Actions results

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size-L team-mobile-platform Mobile Platform team

Projects

Status: Needs dev review

Development

Successfully merging this pull request may close these issues.

OTA modal when we receive OTA updates

3 participants