Reviewed on: 2025-01-14
User interaction state is determined by the InteractionStateHandler, an InputHandler which reads user input activity in the form of InputEvents traveling through the InputPipeline.
The handler is Active on startup and remains Active as it receives InputEvents. The service transitions to Idle after a certain amount of time, known as the idle transition threshold, has transpired since the last timestamp processed by the handler, e.g. 100 milliseconds.
Products may configure this threshold using the fuchsia.ui.IdleThresholdMs configuration capability.
If the service receives InputEvents after transitioning to Idle, it will transition back to the Active state.
On startup or with events ┌──────────┐ │ ┌──────┐ │ ┌────┐ └>│Active│─┘ │Idle│ └──┬───┘ └─┬──┘ │ │ │No events for X amount of time│ │───────────────────────────────>│ │ │ │ InputEvent │ │<───────────────────────────────│ ┌──┴───┐ ┌─┴──┐ │Active│ │Idle│ └──────┘ └────┘
Where X = idle transition threshold
InteractionStateHandler counts button, mouse, and touchscreen events as user interactions. In the future, we will use fuchsia.ui.SupportedInputDevices to count only input events from supported input devices.
One exception is lightsensor devices, which produce passive input data, and therefore is not used to compute the user interaction state.
Clients can subscribe to transitions in interaction state via fuchsia.input.interaction.Notifier/WatchState, which follows a hanging-get pattern.
The server will always respond immediately with the initial state, and after that whenever the system's state changes.
use async_utils::hanging_get::client::HangingGetStream; use fidl_fuchsia_input_interaction::{NotifierMarker, NotifierProxy}; use fuchsia_component::client::connect_to_protocol; let notifier_proxy = connect_to_protocol::<NotifierMarker>()?; let mut watch_interaction_state_stream = HangingGetStream::new(notifier_proxy, NotifierProxy::watch_state); while let Some(Ok(state)) = watch_interaction_state_stream.next().await { match state { State::Active => {/* do something */}, State::Idle => {/* do something */} } }
Some clients may be interested in implementing functionality far deeper into idleness than the InteractionStateHandler currently supports. As more concrete use cases arise, the service could be extended to meet growing needs. In the mean time, there are still ways the service can be used to meet certain goals.
For example, if the InteractionStateHandler transitioned to idle 100 ms after the last user input event, but a client wanted to do something only after it knew that a user has been idle for 1 second, it is still possible to use the current API to accomplish these goals.
It is recommended in this case to still subscribe to interaction state changes via fuchsia.input.interaction.Notifier/WatchState and implement your own timers beyond. One such approach might look like:
Idle state.Active state before the timer elapses, cancel the timer.