Monday, October 14, 2019

New behaviour of navigation controllers in IOS 13

I resumed working on an app that had been resting for a few weeks (while I had updated to iOS 13) and thought, Whaaat?

Navigation controllers do not display in fullscreen anymore, but overlaid, somewhat similar to popover controllers. You can also pull the whole controller down to dismiss it.



Interestingly, Apple has introduced a new setting and changed the default behaviour.

If you want the old behaviour, you need to modify the code. The workaround is fairly simple:

        let viewController = ...
        let navController = UINavigationController(rootViewController: viewController)
        if #available(iOS 13.0, *) {
            navController.modalPresentationStyle = .fullScreen
        }
        self.present(navController, animated: true, completion: nil)

Still, backward compatibility, grumble, grumble...

Thursday, March 7, 2019

Accessibility of the BankID iOS app

The BankID app


A month ago, I wrote a blog post about the EU directive that requires public sector web and mobile apps to be accessible. At last, here is the first instalment in the promised reviews of public sector iOS apps.

While the BankID app is not a public sector app - the ID is issued by the user's bank and managed through the BankID application - it is a common strategy for electronic identification in Sweden. Users use it to authenticate with websites and apps of government agencies, banks, healthcare providers etc., and also to sign documents. For public sector iOS apps, the BankID app is often the only means of authentication, so unless it is accessible, those applications aren't either.

The good news is that this app is fairly accessible with screen readers and devices configured to use large text size, at least for the most common scenario. It also seems that the team behind it responded quickly when a serious VoiceOver issue was reported (see this post on the TB Teknik blog, in Swedish).

Use scenarios


Authenticating with an app running on the same device


If a user wants to authenticate with a mobile app that runs on the same device as the BankID app, the source app starts the BankID app directly. The BankID app displays who is requesting the authentication, and the user can go ahead and enter their security code. The code is processed and if correct the user is returned to sending app, now authenticated.

Authenticating with a web app using social security number


If the user wants to authenticate with a web application, or with an app that is running on a device other than the one with the BankID app, the typical procedure is to enter a social security number in the source application prior to manually starting the BankID app. Once the authentication request is available to the BankID app, it displays the name of the entity that requests authentication, and allows the end user to enter a security code. The success or failure is propagated to the source application.

Authenticating with a web app using a QR code


An alternative procedure is for the website or app to present a QR code. In this case the user also starts the BankID app manually, then taps a QR code button. This opens a camera view where the user scans the QR code. On successfully scanning the code, the app displays the name of the entity that is requesting authentication and the user enters their security code as in the previous scenarios.

Signing a document or transaction


When signing a document the signing procedure is initiated from app where the user is authenticated. The user manually starts the BankID app, reviews the text to be signed, and then enters the security code.

Accessibility


Larger text sizes


Supporting larger text sizes in an iOS app involves two separate tasks. First the developers have to ensure that all text in the app is configured to be displayed with dynamic font sizes. Second, they need to make sure that the app displays OK if the end user ramps the text size up to the maximum size, to avoid that text is truncated, hidden or overlaps with other text. This typically involves reviewing the layout so that text elements can grow as needed, and sometimes specifying maximum font sizes for individual elements.

This app uses dynamic font sizing for some of the text. I tested on a small screen with the accessibility font size turned up to max (for instructions, see "Making the font even bigger" on this apple support page). A lot of text is both scaled and laid out to fit on a small screen without needing to scroll horizontally, but some notable exceptions are the Settings button and the QR code button (Screenshot 1 below).

Screenshot of the BankID app after it has started. The QR code button label font size does not scale with the phone's accessibility setting
Screenshot 1: QR code and settings button labels are not scaled

When authenticating, details about the authentication request are scaled, but not the navigation bar items, and the security code textfield label is truncated (Screenshot 2). For what it is worth, navigation bar items often do not scale very much on Apple's accessible apps either, and the buttons are in standard places.

Screenshot of BankdID app in authentication mode, showing how the important text has been scaled in response to the phone's accessibility settings, but the security code label is truncated
Screenshot 2: authentication mode

The QR code scenario has no buttons other than the navigation bar buttons, and the text on these buttons do not scale (Screenshot 3).

Screenshot of the BankID app in QR code reader view, with a back button and a "Switch Camera" button. The text size of the button labels is not scaled up.
Screenshot 3: QR code scanner view

In the non-QR code authentication scenarios, the important text is scaled. This is however not true of the signing scenario. The name of the entity requesting the signature is scaled, but the details of what the user is going to sign are not (Screenshot 4). 

Screenshot of the BankID app when used to sign a document. The text to be signed is not rendered with dynamic fonts, so the font size is small even though the device is configured to use large font sizes.
Screenshot 4: Signing a document
This text needs to be scaled too, possibly combined with the option of viewing the whole text in a separate view.

VoiceOver


VoiceOver language selection


The BankID app is localised to English and Swedish. If the device's locale is neither of those two, the text in the app defaults to English, but VoiceOver starts in the device language. I blogged about a workaround for this problem for end users in  Configuring the iOS screen reader VoiceOver to work with more than one language, and described a solution for developers so that end users don't have to manually change the language in How hard can it be to configure an iOS app to make sure that VoiceOver switches to the app's language? (Answer: really, really hard)

Usability of direct or social security number authentication


If you start the BankID app manually without having first initiated authentication through another app or web site, initial focus is set on the text "Ready to use. Start a login or a signature on a web page or in another app" as seen in Screenshot 1. So this is the first thing that is read out, which is good. In addition to the label, three other accessibility elements are identified, the QR code button, the "Settings" button and the "About" button, so you can reach all three. Settings is a standard table view.

If you start the app after having initiated authentication by entering your social security number into a different application, the app moves directly to a new view controller, with focus on the first element on that controller which happens to be the "Cancel" button on the navigation bar (Screenshot 2, repeated here).
Screenshot of BankdID app in authentication mode, showing how the important text has been scaled in response to the phone's accessibility settings, but the security code label is truncated
Screenshot 2: authentication mode


Swiping through the elements on the view, you reach
  1. The heading ("Identification")
  2. The user's name (which is rendered with a button, although tapping the button does not have any effect)
  3. The label "I identify myself at"
  4. The label of the entity requiring authentication
  5. The textfield where you enter the security code

The textfield for entering the security code (5) is not the iOS standard textfield. A standard textfield configured to mask the input plays a click when you enter a character, but this is a custom version with an asterisk as a mask for the character input, so the VoiceOver feedback is the word "Star" for every entered character. This had me very confused the first time - I thought I had accidentally entered a star.

Even though this view has a "Cancel" button, the escape gesture (two finger scrub in a Z-pattern) has not been implemented.

Once you've entered the code and tapped Identify, the app is configured to announce both when the authentication is in progress, and when it is complete, which is good.

If you enter the wrong code, an alert is displayed. On closing the alert, focus is transferred to the first item on the view again (the "Cancel" button), and the user has to manually transfer focus to the security code field.

Authenticating with a social security number is functional and the updates when authentication is in progress are very good. There are a couple of changes that could make it even better:

  • Although iOS VoiceOver users probably are used to it, it is odd to place the initial focus on the "Cancel" button when displaying the new view. A more efficient UI would transfer directly to the information of which entity is requesting authentication (or at least to the view heading), and implement the escape action as a quick way to cancel. 
  • When the view is displayed after the user has entered the wrong code, focus should be placed on the textfield for the security code when the alert is closed.
  • Replace the button that displays the name of the user with a label
  • For efficiency, it would be quicker if you didn't need to swipe through two separate accessibility items to find out the source of the authentication request (3, "I identify myself at" and 4, "<Entity>"). This could be achieved by suppressing 3 as an accessibility elements and setting an accessibility label on 4.
  • Replace the confusing "Star" feedback from the security code textfield.
  • Implement the escape gesture. 

Usability with respect to QR code authentication


QR code authentication is a whole other kettle of fish.  Websites wishing to use this mechanism need to think through the UX carefully, so that screen reader users are informed that the QR code mechanism is used, and that the QR code is displayed. The web site I used to test the functionality did neither - VoiceOver focus was not transferred to the QR code but remained on a no longer visible button, in such a way that the VoiceOver focus frame was rendered across and over the code. The user needs to be informed that a QR code for the BankID app is displayed, maybe with a reminder to make sure that their screen is lit up. It wouldn't hurt to say approximately where on the screen the code is positioned either. In general it is fair to say that this strategy requires UX design and good coding skills from the site developers.

However, this is supposed to be about the BankID app, so let's assume that the source app has done the right thing. From the BankID app, this procedure starts by tapping the QR code button. This brings us to a new view (Screenshot 3, repeated here) with a nav bar with a "Back" button and a "Switch Camera" button.

Screenshot of the BankID app in QR code reader view, with a back button  and a "Switch Camera" button. There is no heading or information on how to use it.
Screenshot 3: QR code scanner view


Initial focus is on the "Back" button. There is no heading on this view,  and"Switch camera" is the only other accessibility element.

Because of the focus switch, the user can infer that there has been a change in view, but there is no information on what to do. Switching to the front camera isn't very useful for this task (unless perhaps the rear camera is broken), though in this case it is a hint that a camera view is involved.

The escape gesture does work from this view and has the same effect as the "Back" button.

I attempted to move the phone slowly in front of the monitor and was able to capture codes most of the time though it took patience.

When the QR code is captured, the app switches view to enter a security code. This is the same view as is displayed in Screenshot 2. At this point you get the feedback that the view has changed because the screen reader focuses on the "Cancel" button on that view.

There is a significant delay after the QR code has been found until the security code view is displayed, but there is no auditory feedback in this interval. This means that as a user, you don't know that you have succeeded in reading the QR code, and you keep moving the device trying to locate it until this happens.

This mechanism is not for the faint of heart!

There are a number of things that the BankID app could do better in this scenario.

  • The user needs to be told what is expected of them, so some kind of text element has to be added. It could be a heading (which doesn't even have to be visible to non-screen reader users). Space is not a limitation since the heading can have an accessibility label that can be as long as needed. However, while this would work for screen reader users, the ubiquity of this app is such that users with cognitive impairments need to be able to use it too. Some form of visible instruction is a good idea. 
  • As well as explaining what to do, it would be helpful to include information about how much time the user has to carry out the task.
  • Because there is a long delay between the code capture and the audio feedback from switching to the next view,  there needs to be audio feedback as soon as the code has been captured.
  • The "Back" button should be labelled "Cancel" to match the other views. 


Usability with respect to signing 


The view used to sign has the same components as the authentication view, plus the text to be signed. VoiceOver reads out the text to be signed so this works as well as the authentication view does. 

 Summary 


For VoiceOver users, this app works reasonably well for authenticating in the non-QR code scenario, and for signing. With some changes, it would work even better.  The QR code authentication method is barely possible to execute (and that is assuming that the site that requests the authentication understand the challenges on their side).

The app works OK with large text sizes except for signing, where the text to be signed does not scale.



Wednesday, February 6, 2019

How hard can it be to configure an iOS app to make sure that VoiceOver switches to the app's language? (Answer: really, really hard)

In a previous post, I described how to configure the iOS screen reader VoiceOver to handle multiple languages, allowing the user to manually switch to the language of an app.

This is something that screen reader users who are proficient in more that one language almost always need to change manually when they want to use an app that is not localised to the device's system locale.

However, it doesn't seem to be impossible to configure apps to trigger VoiceOver to switch language automatically. When using VoiceOver with Safari, it switches to the language specified in the document.

I decided to investigate what programmers need to do to in order to make the screen reader switch language automatically in an app. In fact, I was on the verge of promising to do so in my previous post about manually changing the language that VoiceOver uses. Luckily I came to my senses and remembered that I should never assume that I can perform a housekeeping task in Xcode, no matter how normal and straightforward I think the task should be. After a lot of experimentation and some helpful suggestions, I have finally found a solution, so here goes.

There is a setting called Localization native development region in Info.plist but the graphical editor has a short list of languages. You can change it to another language if you switch to the source editor, but it does not take effect in the project settings. So after changing Info.plist, you need to edit the project file as well:
  1. Close the project in Xcode and open the file project.pbxproj in an external editor. 
  2. Search the file for properties called developmentRegion and knownRegions. Replace "en" with the actual locale.
The changes will be reflected on the project's info panel. Attempting to achieve the same result from the Xcode graphic editor does not seem to completely get rid of English in the settings above.

Now we've told the app what its locale is, and that it only has one known locale. Or? Frustratingly, though it seems highly plausible that the locale used to display strings in the app correlates with the desired VoiceOver language, it has no effect on what VoiceOver thinks it should do. It doesn't matter what you do with the project localization settings, having a base language or not - I tried.  Short of providing support for the system locale, the correct language does not get picked.

After asking for help on stack overflow I got a tip from the user Mats which led to a solution: setting the accessibilityLanguage in code in the application. Modify didFinishLaunchingWithOptions with the following addition:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Insert your application's locale
        application.accessibilityLanguage = "sv"
        return true

    }

This finally triggers the screen reader to read the accessible elements in the app in the selected language.

Note that anybody who has written an accessible application should set the accessibilityLanguage, whether the app is localised or not, as you could have users who whose device's system locale is one that you do not support. For localised applications, you will need to detect which locale was used and match the accessibilityLanguage to that one.


Tuesday, February 5, 2019

Configuring the iOS screen reader VoiceOver to work with more than one language

A quick tip for users who need for the iOS screenreader VoiceOver to work with more than one language.

By default when you turn on VoiceOver, the screenreader language is the same as the device's default language. But what if you have apps in another language, or want to visit websites in another language?

You can switch language on the go by navigating to the VoiceOver Speech settings, that is, open General, Accessibility, VoiceOver, Speech. At the end of this view, there is a section called ROTOR LANGUAGES. You can additional languages as needed.

Switch language on the fly by opening the rotor, turning until you hear the languages setting and flicking up and down to find the desired language (more information on using the rotor in Apple's guide to the VoiceOver rotor).

It is reasonably common for web sites to identify the language of the content, and where this has been done, and it seems that the VoiceOver/Safari combo automatically picks the right language if it has been configured, i.e. there is no need to actively change the language in the rotor.

For apps the situation is different. I have as yet not been able to figure out what would trigger an automatic language change in a native iOS app (whereas VoiceOver does switch language in apps that rely on displaying web content if that has language markup).  Specifying the base language for the app, and ensuring that the locale configuration does not contain any leftover language files does not seem to be sufficient. I'll add an update if I find a solution.

Update: the solution is posted in How hard can it be to configure an iOS app to make sure that VoiceOver switches to the app's language? (Answer: really, really hard)

Monday, February 4, 2019

"Some important buttons on the main screen remain unlabeled. Fortunately it's not too hard to figure out what they do with some trials."

What sort of user experience is this? An all too common one, if you are using a screen reader. The title is a quote from a review of the iOS version of the Duolingo app on the AppleVis site, where blind and low-vision users help each other use Apple products and apps running on those platforms. Here is the review in full:

In spite of issues making recent versions totally unusable, this version is once again usable. However, even though it is [usable], there are definitely some annoying problems to watch out for. The first is that some important buttons on the main screen remain unlabeled. Fortunately it's not too hard to figure out what they do with some trials. The second is that there is no way to tell what color your tree is. This means that you can't determine if you need to strengthen weak skills or not. You also can't easily figure out which skills are complete. The third issue is that it's not always possible to reread what you've typed, in questions where you're expected to enter your answer via the keyboard. In spite of these major problems, I still use the app regularly, because the app is really good at what it does.
 Review by Aron C on the AppleVis web site. First added on August 13, 2013; updated on October 4, 2017. Emphasis mine.

The review has over 70 comments, many of which involve posters helping each other figure out how what to do when they have gotten stuck. For example, at one point a suggested workaround for reaching the settings included temporarily turning off the screen reader to tap a button.

The comment thread ought to be required reading for anybody involved in the production of user interfaces, not least to dispel any doubts that people with vision impairments use smartphones and have reasonable expectations on usability just like everyone else.

Things are about to change, at least for one class of applications. As of September 23, 2018 the EU directive on the accessibility of the websites and mobile applications of public sector bodies is in force. It became Swedish law on January 1 2019: Lagen om tillgänglighet till digital offentlig service (in Swedish, published by the Agency for Digital Government). New public sector web sites need to be accessible by September 23, 2019; existing ones by September 23, 2020; and mobile apps by June 23, 2021.

The Swedish publication states that "the requirements to which web sites and mobile applications will need to conform are yet to be decided" (my translation) as they are still in progress. It adds that they will likely be based on a European standard based on WCAG 2.1 AA, a document that lists requirements both for web and mobile apps. I have to admit to being surprised by the fact that there is a compliance date in the relatively near future without any official requirements (all too familiar in the software industry, I know!). But assistive technology is not new, nor is legislation in the area, with  the US congress having enacted Section 508 of the Rehabilitation Act of 1973 in 1998. There should be plenty of experience to draw on.

Lack of specifics notwithstanding, it can safely be assumed that the standards will require accessibility for users without vision, users with limited vision, and users with limited color perception. For these user communities, the implementation techniques involved in supporting them are well understood, whether it be for mobile or web apps, so there is no reason to wait - good usability (not to mention good governance) means access for everybody.

While the mobile app compliance date is a couple of years out, adopting an approach of wait and see  is not a good idea. Apart from the common decency argument, accessibility is a lot like internationalization - it can be added afterwards, but things will go a lot more smoothly if everybody involved understands from the get-go that dynamically sized fonts, like message translations, mean that the size of elements is not fixed. (Also, it is not unusual that actions which improve screen reader experience constitute usability improvements at large.)

I am going to evaluate some Swedish public sector apps, both mobile and web, to see how they fare with respect to screen readers and accessible font sizes, and will post the results here. First out will be the iOS versions of "Mina Sidor" published by by Försäkringskassan (the Social Security Administration) and BankID, an app that allows users to authenticate themselves electronically that is one of the accepted means of authenticating with government agency sites. Until then!

PS. If you want to try out a screen reader on your smartphone, the iMore accessibility guide is a good resource for getting started on iOS devices. Google's Talkback guide explains how to use the Android built-in screen reader.

Friday, August 18, 2017

Why do I see the wrong business hours in Facebook and Google business listings?

I have lived in Sweden for a handful of years now, and am slowly coming to grips with the country taking a collective break during weeks number 28-31 (yes, figuring out when that is, is a test).

This summer I have (among other things) failed to bring pastries to a party and missed out on a visit to the public library because I thought that Facebook and Google were showing me the current business hours.

I should probably have learned to call ahead by now. However, as a "vän av ordning" (friend of orderliness), and also as somebody who has had the (mis)fortune to work on calendaring tools for a significant portion of my career, I wonder how hard it can be to do it right.

If I were going to develop this, it seems like the easiest (?) approach would be to get the business hours from a calendar. Google can even direct users to create one with their own calendar UI. Now (I'm thinking), the business owner can sit down in January, wrapped in a blanket and with a big cup of tea, and create recurring events for their regular opening hours and exceptions for public holidays, weeks 28-31, and the annual company shrimp-eating jaunt.

My "Enter business hours" UI will consist of a textfield where you paste the URL to the calendar. Then I do some magic CalDAVing and display the correct business hours (or non-hours) for the week. Nobody will be stand outside a closed door with a long face longing for tartes a l'abricot. I am a hero!

But given that I haven't had great luck with looking up business hours on Facebook or Google, I suspect that this is not how their UIs work.

Looking at Facebook business pages, the UI for business hours contains seven rows corresponding to the days of the week, where you can enter start and end of business hours.

In other words, the stressed-out-of-their-skull business owner, who is desperately trying to get everything wrapped up before loading their car to the gills with kids and paraphernalia to go to the summer house has to remember edit the Facebook page on the last day (and the Sunday before they open again). So it's understandable that Facebook business hours might not reflect holiday closures.

Another interesting question is, what do Spanish businesses do? They usually close in the middle of the day, but this UI can't capture that..

With Google, the basic UI is similar to Facebook's, but Google does go further: it is possible to set non-contiguous work hours, and to change the hours on special days. Importantly, you can specify the exceptional days in advance, so entering the data is not time-sensitive. You can even upload the data from a spreadsheet, but interestingly, you can't specify a calendar.

I think we can agree that Facebook makes it too hard for users to do the right thing. Specifying known departures from normal business hours is something that you should be able to do well in advance.

But it also seems like just offering the ability to enter non-normal business hours in advance isn't sufficient, that is, it doesn't make it easy enough to ensure that business owners actually do it. There is something about the Google UI that doesn't sufficiently prod business hours to think of the non-normal weeks.

Which brings me back to the calendar based solution I mused about earlier. Perhaps thinking of business hours as events on a calendar could be the prod that makes the user remember to deal with exceptional dates?

There are other advantages too - if the data for the business hours was a calendar URL, then the business owner would potentially be able to use a single calendar URL for all apps that display their business hours - what a time saver! And if you are suddenly struck by vomiting disease, you wouldn't have to log in to Facebook, Google, et al and change them. You just grab your mobile phone and delete the opening hours on that day and it is hopefully reflected in the UI in the near future. (No connection between vomiting disease and any businesses I may have tried to visit during the summer, I should point out).

But maybe the world isn't ready for exceptions to recurring events?

What do you think? Let me know!

New behaviour of navigation controllers in IOS 13

I resumed working on an app that had been resting for a few weeks (while I had updated to iOS 13) and thought, Whaaat? Navigation controll...