DroidKaigi / conference-app-2024

The Official Conference App for DroidKaigi 2024
Apache License 2.0
410 stars 200 forks source link

Crash Occurs When No External Apps Handle android.intent.action.VIEW #660

Closed JoesPredator closed 2 weeks ago

JoesPredator commented 3 weeks ago

Overview

It's a quite rare case, but if there are no external apps available that can handle 「android.intent.action.VIEW」, tapping on items like 'Code Of Conduct' will cause a crash.

To Reproduce

It can be reproduced by disabling all apps such as Google Chrome.

https://github.com/user-attachments/assets/11305297-62d4-4ad1-bca6-a152b752f4a5

Proposed

I thought it would be helpful to display a message like 'No compatible browser available' when there are no apps that can handle it.

https://github.com/DroidKaigi/conference-app-2024/blob/9f3e72052486fbc3de0a421c9b8eb8e4180a8da4/app-android/src/main/java/io/github/droidkaigi/confsched/KaigiApp.kt#L297-L299

Log

FATAL EXCEPTION: main
Process: io.github.droidkaigi.confsched2024.dev, PID: 32252
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://portal.droidkaigi.jp/... (has extras) }
    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2073)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1729)
    at android.app.Activity.startActivityForResult(Activity.java:5320)
    at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:704)
    at android.app.Activity.startActivityForResult(Activity.java:5278)
    at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:683)
    at android.app.Activity.startActivity(Activity.java:5664)
    at androidx.core.content.ContextCompat.startActivity(ContextCompat.java:295)
    at androidx.browser.customtabs.CustomTabsIntent.launchUrl(CustomTabsIntent.java:662)
    at io.github.droidkaigi.confsched.ExternalNavController.navigateToCustomTab(KaigiApp.kt:403)
    at io.github.droidkaigi.confsched.ExternalNavController.navigate(KaigiApp.kt:299)
    at io.github.droidkaigi.confsched.KaigiAppKt.mainScreen$lambda$3$lambda$2(KaigiApp.kt:213)
    at io.github.droidkaigi.confsched.KaigiAppKt.$r8$lambda$JIEyaXFntgABBE3OoziDlLilNsY(Unknown Source:0)
    at io.github.droidkaigi.confsched.KaigiAppKt$$ExternalSyntheticLambda1.invoke(D8$$SyntheticClass:0)
    at io.github.droidkaigi.confsched.about.AboutScreenKt$AboutScreen$4.invoke$lambda$7$lambda$6$lambda$3(AboutScreen.kt:121)
    at io.github.droidkaigi.confsched.about.AboutScreenKt$AboutScreen$4.$r8$lambda$RDzU_UQREHSgwGwqu8RdFYWQ9NM(Unknown Source:0)
    at io.github.droidkaigi.confsched.about.AboutScreenKt$AboutScreen$4$$ExternalSyntheticLambda4.invoke(D8$$SyntheticClass:0)
    at io.github.droidkaigi.confsched.about.component.AboutContentColumnKt.AboutContentColumn$lambda$1$lambda$0(AboutContentColumn.kt:43)
    at io.github.droidkaigi.confsched.about.component.AboutContentColumnKt.$r8$lambda$ZHsxWheBV-BKHVdemCvQm6Zg2sI(Unknown Source:0)
    at io.github.droidkaigi.confsched.about.component.AboutContentColumnKt$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0)
    at androidx.compose.foundation.ClickablePointerInputNode$pointerInput$3.invoke-k-4lQ0M(Clickable.kt:987)
    at androidx.compose.foundation.ClickablePointerInputNode$pointerInput$3.invoke(Clickable.kt:981)
    at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1.invokeSuspend(TapGestureDetector.kt:255)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:175)
    at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:164)
    at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:466)
    at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:500)
    at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:489)
    at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:364)
    at androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNodeImpl$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:719)
    at androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNodeImpl.dispatchPointerEvent(SuspendingPointerInputFilter.kt:598)
    at androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNodeImpl.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:620)
    at androidx.compose.foundation.AbstractClickablePointerInputNode.onPointerEvent-H0pRuoY(Clickable.kt:947)
    at androidx.compose.foundation.AbstractClickableNode.onPointerEvent-H0pRuoY(Clickable.kt:795)
    at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:387)
    at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:373)
takahirom commented 3 weeks ago

Using a Snackbar here is a bit challenging, so I think it's okay to use a Toast instead.

ked4ma commented 3 weeks ago

:raised_hand_with_fingers_splayed: As commented above, I felt it's little bit complecated to show with snackbar, so I would like to show a message as toast :pray: