diff --git a/mobile/lib/shared/diagnostics/diagnostics_controller.dart b/mobile/lib/shared/diagnostics/diagnostics_controller.dart index c7cddefde..5ac17e256 100644 --- a/mobile/lib/shared/diagnostics/diagnostics_controller.dart +++ b/mobile/lib/shared/diagnostics/diagnostics_controller.dart @@ -61,6 +61,12 @@ class DiagnosticsController extends ChangeNotifier { Future setConsent(bool granted) { return _serialize(() async { if (_consentGranted == granted) { + // A failed close keeps the runtime initialized even though the + // persisted preference and visible control are already off. Allow the + // same revocation to retry teardown until it succeeds. + if (!granted && _initialized) { + await _applyCurrentConsent(); + } return; } diff --git a/mobile/test/shared/diagnostics/diagnostics_controller_test.dart b/mobile/test/shared/diagnostics/diagnostics_controller_test.dart index ce8db62a0..a3f3540fa 100644 --- a/mobile/test/shared/diagnostics/diagnostics_controller_test.dart +++ b/mobile/test/shared/diagnostics/diagnostics_controller_test.dart @@ -207,7 +207,7 @@ void main() { expect(reporter.initializeCalls, 1); }); - test('close failure preserves persisted revocation', () async { + test('close failure preserves revocation and retries teardown', () async { final controller = await createController( storedValues: {diagnosticsConsentPreferenceKey: true}, ); @@ -219,6 +219,17 @@ void main() { expect(controller.consentGranted, isFalse); expect(preferences.getBool(diagnosticsConsentPreferenceKey), isFalse); expect(reporter.closeCalls, 1); + + reporter.closeError = null; + await controller.setConsent(false); + + expect(controller.consentGranted, isFalse); + expect(preferences.getBool(diagnosticsConsentPreferenceKey), isFalse); + expect(reporter.closeCalls, 2); + expect( + logs, + contains('Diagnostics disabled: user consent is off; Sentry closed.'), + ); }); test('continues accepting changes after a failed operation', () async {