diff --git a/Fly App/android/app/src/main/kotlin/com/pilotvault/flyapp/DjiSdkBridge.kt b/Fly App/android/app/src/main/kotlin/com/pilotvault/flyapp/DjiSdkBridge.kt index ed524f4..10be3ff 100644 --- a/Fly App/android/app/src/main/kotlin/com/pilotvault/flyapp/DjiSdkBridge.kt +++ b/Fly App/android/app/src/main/kotlin/com/pilotvault/flyapp/DjiSdkBridge.kt @@ -49,6 +49,14 @@ class DjiSdkBridge( */ private const val IDENTITY_RETRY_MS = 2_000L private const val IDENTITY_MAX_ATTEMPTS = 30 + + /** + * The SDK can swallow a registration failure without ever calling + * [DJISDKManager.SDKManagerCallback.onRegister] — e.g. it logs "Exception when + * executing encrypt/decrypt functions" when DJI's server rejects the App Key — + * leaving the app on "Registering…" forever. Give up after this long. + */ + private const val REGISTRATION_TIMEOUT_MS = 60_000L } private val mainHandler = Handler(Looper.getMainLooper()) @@ -57,6 +65,19 @@ class DjiSdkBridge( private var eventSink: EventChannel.EventSink? = null + private val registrationTimeout = Runnable { + emit( + mapOf( + "type" to "registration", + "state" to "failed", + "error" to "DJI did not answer the registration within " + + "${REGISTRATION_TIMEOUT_MS / 1000} s. Check the internet connection, " + + "and that the DJI App Key is activated for package " + + "${appContext.packageName}.", + ) + ) + } + /** * The *flight controller's* serial number — not the aircraft's. * @@ -181,12 +202,16 @@ class DjiSdkBridge( private fun registerApp() { emit(mapOf("type" to "registration", "state" to "registering")) + mainHandler.removeCallbacks(registrationTimeout) + mainHandler.postDelayed(registrationTimeout, REGISTRATION_TIMEOUT_MS) DJISDKManager.getInstance().registerApp( appContext, object : DJISDKManager.SDKManagerCallback { override fun onRegister(error: DJIError?) { + // A late answer still wins: it replaces a timed-out "failed". + mainHandler.removeCallbacks(registrationTimeout) if (error == DJISDKError.REGISTRATION_SUCCESS) { emit(mapOf("type" to "registration", "state" to "success")) DJISDKManager.getInstance().startConnectionToProduct() diff --git a/Fly App/lib/main.dart b/Fly App/lib/main.dart index c2a273f..a427433 100644 --- a/Fly App/lib/main.dart +++ b/Fly App/lib/main.dart @@ -173,6 +173,9 @@ class _HomePageState extends State { case 'failed': _model.registration = RegistrationState.failed; _model.registrationError = event['error'] as String?; + // The error otherwise only shows in the settings sheet, which the + // home "Connect aircraft" flow never opens. + _snack('Registration failed: ${_model.registrationError ?? 'unknown error'}'); break; } _model.bump();