Skip to content

Conversation

@arkivanov
Copy link
Owner

@arkivanov arkivanov commented Dec 26, 2025

Summary by CodeRabbit

  • New Features
    • Enhanced Android deep link handling with greater control over activity restart behavior when receiving deep links.
    • New customizable predicate mechanism for determining restart behavior with sensible defaults.
    • Improved deep link processing lifecycle management to prevent duplicate handling after restoration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 26, 2025

📝 Walkthrough

Walkthrough

This PR refactors the deep link handling API in Decompose's Android module, introducing a new HandleDeepLinkDefaults class and adding an overloaded handleDeepLink function with a configurable restart predicate. The original single-step API now delegates to a more flexible approach supporting generic deep link types and controlled Activity restarts.

Changes

Cohort / File(s) Summary
Public API Surface
decompose/api/android/decompose.api
New public class HandleDeepLinkDefaults with singleton INSTANCE and shouldRestartInNewTask(Activity): Boolean function; overloaded handleDeepLink variants added to DeeplinkUtilsKt with synthetic defaults.
Deep Link Handling Implementation
decompose/src/androidMain/kotlin/com/arkivanov/decompose/DeeplinkUtils.kt
Refactored handleDeepLink API from Uri-based single entry to two-step approach with generic deep link parameter and predicate-driven restart logic; original API now delegates to new overload; new private restart() function manages Activity restart with task stack flags; added HandleDeepLinkDefaults object with default restart predicate.

Sequence Diagram(s)

sequenceDiagram
    participant Activity
    participant SavedStateRegistry as SavedState<br/>Registry
    participant Predicate as Restart<br/>Predicate
    participant Restart as TaskStack<br/>Builder
    
    Activity->>Activity: handleDeepLink(deepLink, predicate, block)
    Activity->>SavedStateRegistry: Check if deepLink already handled
    alt deepLink handled previously
        Activity-->>Activity: Return null (skip processing)
    else deepLink not handled
        Activity->>Predicate: shouldRestartInNewTask(deepLink)
        alt Predicate returns true
            rect rgb(255, 200, 150)
            Note over Activity,Restart: Restart Flow (New)
            Activity->>Activity: Set flags on intent<br/>(NEW_TASK, CLEAR_TASK)
            Activity->>Restart: TaskStackBuilder.create()<br/>.addNextIntent()
            Restart->>Activity: finish()
            Activity->>Activity: Suppress animation
            Activity-->>Activity: Return null
            end
        else Predicate returns false
            rect rgb(200, 220, 255)
            Note over Activity,SavedStateRegistry: Normal Flow
            Activity->>Activity: Invoke block(deepLink)
            Activity->>SavedStateRegistry: Mark deepLink as handled
            Activity-->>Activity: Return result
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A deeper path now guides the way,
With predicates to check and stay,
New tasks restart when deemed so right,
Deep links handle with delight! 🎯

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a new handleDeepLink function with additional parameters (deepLink, shouldRestartInNewTask) alongside the existing API.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch handleDeepLink-with-parseDeepLink

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

@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: 0

🧹 Nitpick comments (1)
decompose/src/androidMain/kotlin/com/arkivanov/decompose/DeeplinkUtils.kt (1)

106-124: Consider clarifying the default parameter's unused lambda parameter.

The default value for shouldRestartInNewTask on line 108 has the signature (D) -> Boolean but the default implementation ignores the D parameter and only checks Activity intent flags:

shouldRestartInNewTask: (D) -> Boolean = { HandleDeepLinkDefaults.shouldRestartInNewTask(this) }

While this is functionally correct (allowing users to provide custom predicates that DO use the deep link value), it might be slightly confusing. The logic is sound, but adding a KDoc note explaining why the default ignores the deep link parameter could improve clarity.

The implementation itself is correct:

  • Restart logic properly checks both deep link nullability and the predicate
  • State management prevents re-processing after configuration changes
  • The takeUnless on line 123 correctly filters already-handled deep links
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d39ef3 and db8976b.

📒 Files selected for processing (2)
  • decompose/api/android/decompose.api
  • decompose/src/androidMain/kotlin/com/arkivanov/decompose/DeeplinkUtils.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build on Linux
  • GitHub Check: Build on macOS
🔇 Additional comments (8)
decompose/api/android/decompose.api (2)

96-98: LGTM! New API surface additions are correct.

The new handleDeepLink overload and its synthetic default variant are properly declared, matching the implementation in DeeplinkUtils.kt and following Kotlin/Java interop conventions.


133-137: LGTM! HandleDeepLinkDefaults properly declared.

The new HandleDeepLinkDefaults object is correctly represented in the API file with its singleton INSTANCE field and shouldRestartInNewTask method.

decompose/src/androidMain/kotlin/com/arkivanov/decompose/DeeplinkUtils.kt (6)

5-6: LGTM! Intent flag imports are appropriate.

Direct imports of FLAG_ACTIVITY_CLEAR_TASK and FLAG_ACTIVITY_NEW_TASK improve code readability throughout the file.


56-62: LGTM! Backward-compatible delegation pattern.

The original handleDeepLink function cleanly delegates to the new overload while maintaining backward compatibility. The refactoring preserves existing behavior by passing intent.data as the deep link.


126-138: LGTM! Flag checking logic is correct.

The shouldRestartInNewTask implementation properly checks Android intent flags using bitwise operations:

  • Returns true when FLAG_ACTIVITY_NEW_TASK is set AND FLAG_ACTIVITY_CLEAR_TASK is not set
  • This correctly identifies when an Activity restart with CLEAR_TASK is needed to ensure a clean task stack

The logic aligns with Android deep linking best practices.


140-157: LGTM! Activity restart implementation is robust.

The restart() function follows Android best practices and is derived from AndroidX Navigation source:

  • Correctly adds FLAG_ACTIVITY_CLEAR_TASK to ensure clean task stack
  • Uses TaskStackBuilder to rebuild the entire activity stack for predictable state
  • Disables transition animation to prevent visual glitches
  • Properly wrapped with StrictMode handling

The implementation aligns with Android's deep link handling recommendations.


159-175: LGTM! Proper StrictMode handling with version compatibility.

The StrictMode helper functions are well-implemented:

  • Temporarily permits unsafe intent launch for TaskStackBuilder.startActivities()
  • Properly restores original policy in finally block
  • Includes API level check for permitUnsafeIntentLaunch() (Android S+)
  • inline modifier ensures zero-overhead abstraction

177-178: LGTM! Well-defined state keys.

Private constants for SavedStateRegistry keys prevent magic strings and improve maintainability.

@arkivanov arkivanov merged commit b908e9e into master Dec 26, 2025
3 checks passed
@arkivanov arkivanov deleted the handleDeepLink-with-parseDeepLink branch December 26, 2025 18:19
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.

2 participants