diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/KeyboardVisibilityFeature.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/KeyboardVisibilityFeature.kt index 33005c78..828d3932 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/KeyboardVisibilityFeature.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/KeyboardVisibilityFeature.kt @@ -186,13 +186,13 @@ class KeyboardVisibilityFeature( lastKeyboardHeight = heightPx lastKeyboardVisible = isVisible - val timestamp = EventSequence.next() + val sequence = EventSequence.next() logger.debug("$TAG: Keyboard change - height=$heightPx, visible=$isVisible, animating=$isAnimating") runOnUiThread { flutterEvents.onKeyboardVisibilityChanged( - timestamp, + sequence, heightPx.toLong(), isVisible, isAnimating diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt index 346ee5f4..2164923a 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt @@ -67,7 +67,7 @@ class WebExtensionToolbarFeature( .filter { !store.state.extensions.containsKey(it) || store.state.extensions[it]?.enabled == false } .forEach { extensionId -> addonEvents.onRemoveWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extensionId, actionTypeArg = WebExtensionActionType.BROWSER, ) {} @@ -78,7 +78,7 @@ class WebExtensionToolbarFeature( .filter { !store.state.extensions.containsKey(it) || store.state.extensions[it]?.enabled == false } .forEach { extensionId -> addonEvents.onRemoveWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extensionId, actionTypeArg = WebExtensionActionType.PAGE, ) {} @@ -107,7 +107,7 @@ class WebExtensionToolbarFeature( webExtensionBrowserActions.keys.toList().forEach { extensionId -> if (extensionId !in enabledExtensionIds) { addonEvents.onRemoveWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extensionId, actionTypeArg = WebExtensionActionType.BROWSER, ) {} @@ -118,7 +118,7 @@ class WebExtensionToolbarFeature( webExtensionPageActions.keys.toList().forEach { extensionId -> if (extensionId !in enabledExtensionIds) { addonEvents.onRemoveWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extensionId, actionTypeArg = WebExtensionActionType.PAGE, ) {} @@ -131,7 +131,7 @@ class WebExtensionToolbarFeature( if (extensionNotAllowedInTab(extension, tab)) { webExtensionPageActions[extension.id]?.let { addonEvents.onRemoveWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extension.id, actionTypeArg = WebExtensionActionType.PAGE, ) {} @@ -139,7 +139,7 @@ class WebExtensionToolbarFeature( } webExtensionBrowserActions[extension.id]?.let { addonEvents.onRemoveWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extension.id, actionTypeArg = WebExtensionActionType.BROWSER, ) {} @@ -221,7 +221,7 @@ class WebExtensionToolbarFeature( ) addonEvents.onUpsertWebExtensionAction( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extension.id, actionTypeArg = if (isPageAction) WebExtensionActionType.PAGE else WebExtensionActionType.BROWSER, extensionDataArg = data @@ -236,7 +236,7 @@ class WebExtensionToolbarFeature( val imageBytes = icon.toWebPBytes() runOnUiThread { addonEvents.onUpdateWebExtensionIcon( - timestampArg = EventSequence.next(), + sequenceArg = EventSequence.next(), extensionIdArg = extensionId, actionTypeArg = if (isPageAction) WebExtensionActionType.PAGE else WebExtensionActionType.BROWSER, iconArg = imageBytes diff --git a/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/IntentReceiver.kt b/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/IntentReceiver.kt index 781e7863..ab891b46 100644 --- a/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/IntentReceiver.kt +++ b/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/IntentReceiver.kt @@ -22,7 +22,7 @@ package eu.weblibre.simple_intent_receiver import io.flutter.plugin.common.BinaryMessenger import eu.weblibre.simple_intent_receiver.pigeons.IntentEvents import eu.weblibre.simple_intent_receiver.pigeons.Intent as PigeonIntent -import eu.weblibre.flutter_mozilla_components.ext.EventSequence +import eu.weblibre.simple_intent_receiver.ext.EventSequence class IntentReceiver(messenger: BinaryMessenger) { private val intentEvents: IntentEvents = IntentEvents(messenger) @@ -31,4 +31,3 @@ class IntentReceiver(messenger: BinaryMessenger) { intentEvents.onIntentReceived(EventSequence.next(), intent) { } } } -} diff --git a/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/ext/EventSequence.kt b/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/ext/EventSequence.kt new file mode 100644 index 00000000..704ec5d5 --- /dev/null +++ b/packages/simple_intent_receiver/android/src/main/kotlin/eu/weblibre/simple_intent_receiver/ext/EventSequence.kt @@ -0,0 +1,22 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package eu.weblibre.simple_intent_receiver.ext + +import java.util.concurrent.atomic.AtomicLong + +/** + * Thread-safe monotonic sequence counter for event ordering. + * + * Replaces System.currentTimeMillis() for event timestamps sent to Flutter, + * guaranteeing strictly increasing values regardless of wall-clock changes + * and eliminating same-millisecond collisions. + */ +object EventSequence { + private val counter = AtomicLong(0) + + fun next(): Long = counter.incrementAndGet() +}