Skip to content

fix(settings): prevent crash on external URL open (COLUMBA-AV)#1013

Open
sentry[bot] wants to merge 1 commit into
mainfrom
seer/fix/columba-av-url-crash
Open

fix(settings): prevent crash on external URL open (COLUMBA-AV)#1013
sentry[bot] wants to merge 1 commit into
mainfrom
seer/fix/columba-av-url-crash

Conversation

@sentry

@sentry sentry Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

This PR addresses COLUMBA-AV, an ActivityNotFoundException that occurs when the app attempts to open an external URL via Intent.ACTION_VIEW on devices without a default browser or web-capable activity.

The root cause was unguarded calls to context.startActivity(Intent.ACTION_VIEW, url) in AboutCard.kt.

Changes:

  • Replaced direct startActivity calls with the existing safeOpenUrl(context, url) utility function in AboutCard.kt for:
    • The "View License" button.
    • The "View Release" button (for app updates).
    • The generic LinkButton composable.
  • When safeOpenUrl returns false (meaning no handler was found), a Toast message "No app found to open link" is now displayed to the user, providing graceful degradation instead of a crash.
  • Removed unused Intent, Uri, and toUri imports from AboutCard.kt.

Note: While the original issue pointed to MainActivity and the night-shift triage mentioned AboutCard.kt's "View License" button, the stack trace for COLUMBA-AV actually originated from SettingsScreen.kt's "Report a Bug" button. That specific instance was already fixed by PR #958. This PR addresses the remaining unguarded ACTION_VIEW calls in AboutCard.kt that would cause the identical crash, as well as confirming that MessagingScreen.kt and MicronComposables.kt already had appropriate try/catch blocks.

Fixes COLUMBA-AV

@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes an ActivityNotFoundException crash by replacing three bare startActivity(Intent.ACTION_VIEW) calls in AboutCard.kt with the pre-existing safeOpenUrl() helper, which catches both ActivityNotFoundException and SecurityException and returns false when no handler is available. A Toast is now shown on failure instead of crashing.

  • All three affected call sites ("View License", "View Release", LinkButton) are correctly migrated to safeOpenUrl(); the Intent, Uri, and toUri imports that were only used by those calls are removed.
  • The fallback toast message \"No app found to open link\" is a hardcoded literal duplicated across all three sites rather than a string resource, which prevents localization and makes wording changes error-prone.

Confidence Score: 4/5

The crash fix is straightforward and the safeOpenUrl helper is well-implemented with correct exception handling; the only gap is the hardcoded, triplicated toast string.

The underlying fix is correct — safeOpenUrl properly catches both ActivityNotFoundException and SecurityException, and the Toast gives users a graceful error. The one quality issue is the user-facing fallback string being hardcoded in three places rather than coming from a string resource, which would need to be touched individually if the wording ever changes or localization is added.

AboutCard.kt — the three duplicated hardcoded toast strings could use a second look before merging.

Important Files Changed

Filename Overview
app/src/main/java/network/columba/app/ui/screens/settings/cards/AboutCard.kt Replaced three unguarded startActivity(ACTION_VIEW) calls with the existing safeOpenUrl() helper and a Toast fallback; the crash fix is correct, but the fallback string is hardcoded three times instead of using a string resource.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant AboutCard
    participant safeOpenUrl
    participant OS as Android OS

    User->>AboutCard: tap "View License" / "View Release" / LinkButton
    AboutCard->>safeOpenUrl: safeOpenUrl(context, url)
    safeOpenUrl->>OS: startActivity(Intent.ACTION_VIEW)
    alt Browser / handler found
        OS-->>safeOpenUrl: success
        safeOpenUrl-->>AboutCard: true
        AboutCard-->>User: URL opens in browser
    else No handler (ActivityNotFoundException / SecurityException)
        OS-->>safeOpenUrl: throws
        safeOpenUrl-->>AboutCard: false
        AboutCard-->>User: Toast "No app found to open link"
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant AboutCard
    participant safeOpenUrl
    participant OS as Android OS

    User->>AboutCard: tap "View License" / "View Release" / LinkButton
    AboutCard->>safeOpenUrl: safeOpenUrl(context, url)
    safeOpenUrl->>OS: startActivity(Intent.ACTION_VIEW)
    alt Browser / handler found
        OS-->>safeOpenUrl: success
        safeOpenUrl-->>AboutCard: true
        AboutCard-->>User: URL opens in browser
    else No handler (ActivityNotFoundException / SecurityException)
        OS-->>safeOpenUrl: throws
        safeOpenUrl-->>AboutCard: false
        AboutCard-->>User: Toast "No app found to open link"
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
app/src/main/java/network/columba/app/ui/screens/settings/cards/AboutCard.kt:162
**Hardcoded user-visible string repeated in three places**

The literal `"No app found to open link"` appears identically at lines 162, 242, and 349. Android string resources (`res/values/strings.xml`) are the conventional home for UI-facing copy; hardcoding it three times makes future wording changes error-prone and prevents localization. Extract this to a string resource (e.g. `R.string.error_no_app_for_link`) and reference it with `context.getString(R.string.error_no_app_for_link)` in each `Toast.makeText` call.

Reviews (1): Last reviewed commit: "fix(settings): prevent crash on external..." | Re-trigger Greptile

val intent = Intent(Intent.ACTION_VIEW, "https://github.com/torlando-tech/columba/blob/main/LICENSE.md".toUri())
context.startActivity(intent)
if (!safeOpenUrl(context, "https://github.com/torlando-tech/columba/blob/main/LICENSE.md")) {
Toast.makeText(context, "No app found to open link", Toast.LENGTH_SHORT).show()

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.

P2 Hardcoded user-visible string repeated in three places

The literal "No app found to open link" appears identically at lines 162, 242, and 349. Android string resources (res/values/strings.xml) are the conventional home for UI-facing copy; hardcoding it three times makes future wording changes error-prone and prevents localization. Extract this to a string resource (e.g. R.string.error_no_app_for_link) and reference it with context.getString(R.string.error_no_app_for_link) in each Toast.makeText call.

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/network/columba/app/ui/screens/settings/cards/AboutCard.kt
Line: 162

Comment:
**Hardcoded user-visible string repeated in three places**

The literal `"No app found to open link"` appears identically at lines 162, 242, and 349. Android string resources (`res/values/strings.xml`) are the conventional home for UI-facing copy; hardcoding it three times makes future wording changes error-prone and prevents localization. Extract this to a string resource (e.g. `R.string.error_no_app_for_link`) and reference it with `context.getString(R.string.error_no_app_for_link)` in each `Toast.makeText` call.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

0 participants