fix(train): Health Connect's permissions asked as the system's from Android 14 on

From Android 14 on, Health Connect's permission contract makes AndroidX's
REQUEST_PERMISSIONS intent, which only a ComponentActivity's result registry
handles: FlutterActivity started it, no activity answered, and the app
crashed on answering twice, the error and then the empty result ("Reply
already submitted"). It asks with requestPermissions there now, answered in
MainActivity's onRequestPermissionsResult; a permission or route request
that doesn't start is no longer kept waiting, so it is answered once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-01 00:37:53 +01:00
commit 5f8514b441
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 35 additions and 5 deletions

View file

@ -153,6 +153,15 @@ class HealthConnectBridge(private val activity: Activity) : MethodChannel.Method
return true
}
/** Answers the question for permissions the system asked (Android 14 on); false for any other. */
fun onRequestPermissionsResult(requestCode: Int): Boolean {
if (requestCode != PERMISSIONS_REQUEST) return false
val result = asking ?: return true
asking = null
scope.launch { result.success(granted()) }
return true
}
/** Stops what is still running. */
fun dispose() {
scope.cancel()
@ -181,9 +190,23 @@ class HealthConnectBridge(private val activity: Activity) : MethodChannel.Method
return
}
asking = result
val contract = PermissionController.createRequestPermissionResultContract()
@Suppress("DEPRECATION") // FlutterActivity is no ComponentActivity, so no result registry.
activity.startActivityForResult(contract.createIntent(activity, wanted), PERMISSIONS_REQUEST)
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// From Android 14 on, Health Connect's permissions are the system's:
// the contract's intent there is AndroidX's REQUEST_PERMISSIONS, which
// only a ComponentActivity's result registry handles and no activity
// answers (v0.1.0 failed so on every request).
activity.requestPermissions(wanted.toTypedArray(), PERMISSIONS_REQUEST)
} else {
val contract = PermissionController.createRequestPermissionResultContract()
@Suppress("DEPRECATION") // FlutterActivity is no ComponentActivity, so no result registry.
activity.startActivityForResult(contract.createIntent(activity, wanted), PERMISSIONS_REQUEST)
}
} catch (error: Exception) {
// Not asked: the caller answers with the error, and nothing else may.
asking = null
throw error
}
}
/**
@ -246,8 +269,14 @@ class HealthConnectBridge(private val activity: Activity) : MethodChannel.Method
return
}
routing = result
@Suppress("DEPRECATION") // As in ask: no result registry.
activity.startActivityForResult(ExerciseRouteRequestContract().createIntent(activity, id), ROUTE_REQUEST)
try {
@Suppress("DEPRECATION") // As in ask: no result registry.
activity.startActivityForResult(ExerciseRouteRequestContract().createIntent(activity, id), ROUTE_REQUEST)
} catch (error: Exception) {
// As in ask: not asked, so answered only with the error.
routing = null
throw error
}
}
else -> result.success(null)
}

View file

@ -166,6 +166,7 @@ class MainActivity : FlutterActivity() {
grantResults: IntArray,
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (health.onRequestPermissionsResult(requestCode)) return
if (requestCode != RECORDER_REQUEST) return
asking?.let { (wanted, result) ->
asking = null