From 3afeff45d8bd5fff66e1d0fa2c15fa2527487af1 Mon Sep 17 00:00:00 2001 From: Fabian Henneke Date: Thu, 30 Jul 2020 10:29:01 +0200 Subject: Fix two SMS Autofill crashes (#985) SMS OTP Autofill currently crashes for two reasons: 1. Tasks.await has a precondition of not running on the UI thread. 2. Exceptions thrown from Tasks are always wrapped into ExecutionExceptions and need to be unwrapped before they can be identified as ResolvableApiException. This commit addresses both issues by making waitForSms a proper coroutine using withContext and a custom wrapper around Task that relies on suspendCoroutine and automatically unwraps exceptions. --- .../autofill/oreo/ui/AutofillSmsActivity.kt | 33 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt b/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt index 02394867..4413ea10 100644 --- a/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt +++ b/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt @@ -24,13 +24,30 @@ import com.google.android.gms.auth.api.phone.SmsRetriever import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.common.api.ResolvableApiException -import com.google.android.gms.tasks.Tasks +import com.google.android.gms.tasks.Task import com.zeapo.pwdstore.autofill.oreo.AutofillAction import com.zeapo.pwdstore.autofill.oreo.Credentials import com.zeapo.pwdstore.autofill.oreo.FillableForm import com.zeapo.pwdstore.databinding.ActivityOreoAutofillSmsBinding import com.zeapo.pwdstore.utils.viewBinding +import java.util.concurrent.ExecutionException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +suspend fun Task.suspendableAwait() = suspendCoroutine { cont -> + addOnSuccessListener { result: T -> + cont.resume(result) + } + addOnFailureListener { e -> + // Unwrap specific exceptions (e.g. ResolvableApiException) from ExecutionException. + val cause = (e as? ExecutionException)?.cause ?: e + cont.resumeWithException(cause) + } +} @RequiresApi(Build.VERSION_CODES.O) class AutofillSmsActivity : AppCompatActivity() { @@ -105,15 +122,21 @@ class AutofillSmsActivity : AppCompatActivity() { } } - private fun waitForSms() { + private suspend fun waitForSms() { val smsClient = SmsCodeRetriever.getAutofillClient(this@AutofillSmsActivity) try { - Tasks.await(smsClient.startSmsCodeRetriever()) + withContext(Dispatchers.IO) { + smsClient.startSmsCodeRetriever().suspendableAwait() + } } catch (e: ResolvableApiException) { - e.startResolutionForResult(this, 1) + withContext(Dispatchers.Main) { + e.startResolutionForResult(this@AutofillSmsActivity, 1) + } } catch (e: Exception) { e(e) - finish() + withContext(Dispatchers.Main) { + finish() + } } } -- cgit v1.2.3