Sam
Sam

Reputation: 351

Is there a way to detect VoiceOver focus change / user interaction at the `UIApplication` or `UIWindow` level?

One of the features of the app I'm working on is an "idle timeout" - basically if the user doesn't interact with the app for more than five minutes, their session ends for privacy / security reasons.

This is currently implemented by overriding sendEvent(_ event: UIEvent) in the app delegate and resetting a timer.

However, what I've noticed is that sendEvent(_ event: UIEvent) isn't called at all when a user is interacting with the app using VoiceOver.

It is called when the user double-taps to activate a control, but it isn't called for focus changes, interacting with .adjustable controls, and so on.

This means that if a user is swiping through a long list of rows in a table view, for example, sendEvent(_ event: UIEvent) isn't called and a user may be timed-out of the app, even though they were interacting with it.

Is there a way to detect VoiceOver focus changes or interactions at the UIApplication or UIWindow level, or a notification that can be subscribed to for a clean solution?

The closest solution I've found suggests using the UIAccessibilityFocus protocol on individual views, but this feels like it could be quite messy and involve a lot of subclassing (https://stackoverflow.com/a/20712889).

Any different suggestions for an idle timeout that works for VoiceOver and non-VoiceOver users would also be much appreciated - there could well be something I've missed.

Upvotes: 1

Views: 1893

Answers (2)

stalker
stalker

Reputation: 1

Unfortunately the solution based on listening to UIAccessibility.elementFocusedNotification only solves part of the problem.

The notification is not generated when you click again on an already focused item (which is certainly logical). Besides, activation of elements without accessoryLabel also does not result in notification generation (when VoiceOver is enabled).

Therefore, developing an idle timer that takes VoiceOver into account is not yet fully possible.

Upvotes: 0

Sam
Sam

Reputation: 351

So I figured out the solution here and I'm now kicking myself.

UIAccessibility.elementFocusedNotification is the key (https://developer.apple.com/documentation/uikit/uiaccessibility/1620210-elementfocusednotification).

So a solution could look something like:

NotificationCenter.default.addObserver(self,
                                       selector: #selector(self.accessibilityElementFocussed(notification:)),
                                       name: UIAccessibility.elementFocusedNotification,
                                       object: nil)

@objc private func accessibilityElementFocussed(notification: NSNotification) {
    // Reset your idle timer here.
}

Hopefully this helps someone out - I've seen a lot of solutions for idle timers online that don't take into account VoiceOver users.

Upvotes: 1

Related Questions