ground-android
ground-android copied to clipboard
GoogleApiManager$GooglePlayServicesMissingException - Google play services not available
GoogleApiManager.installGooglePlayServices com.google.android.ground.system.GoogleApiManager$GooglePlayServicesMissingException - Google play services not available
Fatal Exception: com.google.android.ground.system.GoogleApiManager$GooglePlayServicesMissingException: Google play services not available
at com.google.android.ground.system.GoogleApiManager.installGooglePlayServices(GoogleApiManager.kt:45)
at com.google.android.ground.ui.startup.StartupViewModel.initializeLogin(StartupViewModel.kt:32)
at com.google.android.ground.ui.startup.StartupFragment$onResume$1.invokeSuspend(StartupFragment.kt:55)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
at kotlinx.coroutines.BuildersKt.launch(:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(:1)
at com.google.android.ground.ui.startup.StartupFragment.onResume(StartupFragment.kt:53)
at androidx.fragment.app.Fragment.performResume(Fragment.java:3210)
at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:666)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:310)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1675)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3259)
at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:3191)
at androidx.fragment.app.Fragment.performResume(Fragment.java:3219)
at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:666)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:310)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1675)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3259)
at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:3191)
at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:285)
at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:333)
at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:322)
at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:245)
at android.app.Activity.performResume(Activity.java:8219)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4814)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4857)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2253)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7870)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1009)
@shobhitagarwal1612 Is it the correct behaviour or should we close the app or something in such scenario?
https://github.com/google/ground-android/blob/85d53fcb1b513c3db911c7cc81150741d756c31f/ground/src/main/java/com/google/android/ground/ui/startup/StartupFragment.kt#L57
We already handle this exception here.
https://github.com/google/ground-android/blob/85d53fcb1b513c3db911c7cc81150741d756c31f/ground/src/main/java/com/google/android/ground/ui/startup/StartupFragment.kt#L57
We already handle this exception here.
Should we close this issue? This is one of the crash seen in crashlytics today
This crash has occurred 15 times in prod on v0.1.11. Prioritizing as P1.
Let's show a more meaningful error message and exit instead of crashing.
Agreed to show an error message on the UI and exit, and log in debug. @jo-spek can check the translations
Agreed to show an error message on the UI and exit, and log in debug. @jo-spek can check the translations
@kenstershiro Unfortunately, Play services doesn't always report success or failure states correctly. In rare cases when we know we can't recover by asking the user to enable/install Play services, we can show an error. In other's we'll have to wait until the Play services are installed. Currently, we show the "Initializing..." spinner while that's happened. Perhaps we should add a distinct message for this case, e.g. "Waiting for Play services...". Wdyt?
@anandwana001 The easy way to solve this would be to split the init method in StartupViewModel into two, and to show one progress dialog while initializing Play services, dismiss once done, then show the current initializing progress spinner while initializing the auth manager.
Currently, we show the "Initializing..." spinner while that's happened. Perhaps we should add a distinct message for this case, e.g. "Waiting for Play services...". Wdyt?
Not sure the different message adds much value to the user, but if it's a simple change I'd agree.
Not sure the different message adds much value to the user, but if it's a simple change I'd agree.
In some cases, the OS never lets the app know the installation of Google Play services fails, causing the app to get stuck showing "Initializing..." In those cases, the user doesn't know they can recover by installing Play services; showing the "Waiting for Play services..." will give them some indication of what the app is waiting for.
When Play services is already installed, we can avoid showing the new "Waiting" dialog altogether. @anandwana001
The following fix in #2920 doesn't work as intended:
https://github.com/google/ground-android/blob/9ef90adb6cc8aade4bd87350fe820fd8c0a23ace/ground/src/main/java/com/google/android/ground/ui/startup/StartupFragment.kt#L50-L60
viewModel.initializeLogin() will not loop until Play services is installed since StartupFragment and its scope are stopped when the app navigates to the Play services install/enable flow.
Instead, we should make sure the flow is correct when the user returns to the app.
Currently, we show the "Initializing..." spinner while that's happened. Perhaps we should add a distinct message for this case, e.g. "Waiting for Play services...". Wdyt?
Not sure the different message adds much value to the user, but if it's a simple change I'd agree.
@kenstershiro @anandwana001 While debugging I realized we don't actually need this extra message, since when the user returns to the app from installing Play services, the init flow will happen again, which will in turn either pass directly to the sign in screen, or re-display the "install Play services" dialog. In that case the "Waiting for Play services.." progress spinner would never be shown.
I'll keep this for now since it's a safe fallback in case my previous comment was wrong. Closing.