[ Silence ]
Welcome to Accessibility in iOS.
My name is Sam White, I am one of the iOS Accessibility Engineers here at Apple.
Today, I want to talk to you about developing great applications for everyone.
And I want to show you how to do that by implementing a little bit of Accessibility in your applications.
So before we get started, what do we mean when we say Accessibility in this context?
Well, in iOS, Accessibility is really about supporting different abilities and more broadly than that, supporting different users.
So, if you look at the iPad and the iPhone, you see these amazing devices, you know, they help they let you communicate with your friends, watch movies, browse the internet.
But the user experience of these devices is very much one size fits all.
And so, if we look at, you know, two users of these devices, no two users are the same, you know, so this is the problem we have.
And more specifically, no two users have the exact same abilities so this is where Accessibility comes in on iOS.
Accessibility is the thin layer that sits between you and your device and it transforms your input into something more appropriate for the device and similarly, it transforms the device's output into something more appropriate for you.
So today's talk is broken into two main parts, I'm going to start by giving you a brief introduction to some of the Accessibility features that we offer on iOS.
And this should give you an idea of how users will experience your accessible application.
And while we're at it, I'm really excited to say we're adding a brand new Accessibility feature in iOS 7 so I'm really excited to show you that.
And then for the remainder of our time and really, the bulk of the talk, we're going to be doing some Accessibility development.
So, I've brought an application with me that has some Accessibility issues.
So, we're going to fix them kind of from starting with the most basic, working our way up to the advanced issues then I'm going to use some brand new API on this application that we've added in this release to do some really cool stuff that was never before possible and it's going to let you do some cool stuff in your applications.
And then, we're going to wrap up the day by looking at some brand new API we've added to Guided Access in this release.
And I'm going to show you how you can use that API to really customize the user experience of your application on the fly.
So, iOS Accessibility features.
One of our most powerful features is called VoiceOver and VoiceOver is a screen reader application that lets blind and low vision users use iOS in the same way that everyone else does.
And so, VoiceOver works by intercepting all touch and Multi-Touch gestures and transforming those into commands that drive a cursor around the screen, the cursor you see in this image.
And so, what that does is it allows a blind or low vision user to explore an interface and have it spoken to them to learn about it before they chose to interact with it.
We also added a feature in iOS 6 called Guided Access.
So we introduce Guided Access to deal with the problem of distractions.
So if we return to, looking at the iPhone and the iPad, we realized these devices have a great number of distractions associated with them.
If we look at the hardware, they have many hardware buttons, you know, volume buttons, lock buttons and the interface itself responds to, you know, a variety of touch and Multi-Touch gestures.
And what this means is, if you're a user who, you know, maybe has trouble focusing or a child, these distractions can really get in your way.
And so, what Guided Access does is it gives you a setup screen that allows you to remove many of these distractions on a per app basis.
So, you can really focus in on exactly the content you want to.
Also in iOS 6, we added Made for iPhone hearing aids.
And so, Made for iPhone hearing aids let you control your hearing aids right from your iOS device which you likely already have with you.
And so, this let you do things like adjust the volume or adjust the balance between your hearing aids if you have more than one.
I mean it even lets you quickly select from multiple audiologist tuned presets that you have in your hearing aid and on your device.
So, if you walk into say a noisy environment like a restaurant, you know, you can quickly change your hearing aid to an equalizer setting more appropriate for that environment.
And similarly, maybe if you walk into a movie, a very quiet environment, you can again pull out your iPhone and quickly choose a preset more appropriate for that environment.
And the last Accessibility feature, I wanted to give you kind of a brief introduction to today is called Assistive Touch.
So, we added a Assistive Touch to iOS in iOS 5.
And really, the goal of Assistive Touch is to help users with physical and mobility impairments perform the complex Multi-Touch gestures and hardware button presses that are really necessarily to use iOS effectively.
And so, Assistive Touch does this by giving you a single on-screen menu that contains all these gestures and hardware button options.
And can be activated by just a single touch.
And also, Assistive Touch can be driven using an external Accessibility device such as a joystick.
So, I want to return to this idea of supporting different abilities with Accessibility for a moment.
Now that we've seen some of the more visible Accessibility features, this starts to make sense, right?
We introduced Guided Access to offer some cognitive support, we have VoiceOver that offers visual support and so the question arises, you know, where do we go next?
Over the years, we've built up a pretty rich Accessibility environment on iOS and it's really second to none.
And so, to answer that question of where we go next, I want to explain the picture you see in front of you.
And what you're seeing is what's known as a Switch User and switch software is designed to allow a user to interface with the computing device using just a single switch.
And so, this is accomplish by scanning through the interface automatically and listening for those switch presses from a user, you know, when the thing they are interested in, you know, becomes selected via the scanning process.
And so, as you may have guessed, I'm really excited to say that we've worked really hard, you know, day and night and we've gone ahead and baked a complete switch software solution right into iOS in this release.
And so rather than talk about it, you know, a picture is worth a thousand words, I'd love to just give you a quick demo right now.
As with all of our Accessibility features, you can find them by opening up the Settings application, go into General and then to Accessibility.
And so, as I mentioned before, you can see that the Accessibility features on iOS are really grouped by needs.
So, we see the vision heading followed by the vision related Accessibility features, similarly hearing and hearing features.
And if we scroll all the way down, we see physical and motor and that's where switch control lives.
And so, before I turn it on, I just want to scroll down a bit and give you an idea of how customizable this feature is.
Again, we think it's really important for each user to be able to tune this feature to really meet their abilities and work with work well with them.
And so again, we've built in an incredible amount of customization here so users can really set it up in a way that works well for them.
And so, if I go ahead and turn Switch control on, you can see a cursor that begins scanning through the interface.
And so, this in itself is pretty amazing, right?
If you've seen Switch software before, usually, the solution is to, you know, drive if you're on a desktop, it's to drive a mouse cursor around the interface.
And, you know, if you're on mobile device, maybe you drive some false finger around the interface.
But because of your help in years passed and, you know, our work on the OS end, we've already marked up the interfaces with this great Accessibility API.
And so, we can just jump in and leverage to that API and build this feature on top of it because we know these elements exist.
And so, that's how we were able to build an element scanning switch solution.
And so now, this cursor is scanning through the interface waiting for switch presses.
And so, ahead of time, I've gone ahead and paired my external Bluetooth switch with this device and right out right off the bat, we're supporting a large number of external switches that will work for you.
And so, as this cursor scans the interface, I wait for, you know, what I'm interested in to be selected, and then I can press my switch to bring up a context menu.
And so if I bring up the context menu here, you can see, I'm presented with options that are appropriate for this element.
And in this case, I'm just going to wait until the Home button group becomes selected and I'm going to drill into it with a single switch press.
And then again, press right on the Home button and you can see it's the equivalent of just pressing the Home button yourself.
And so, let's say we want to take a look at, you know, how Apple stock is doing today.
And so again, we'll just wait until the group with stocks in it is selected and there it is and now, I'll just wait for stocks to be highlighted and press again.
And again, you can see this context menu pops up with anything I might be interested in, you know, for this element, anything this element responds to.
And so, I'm going to wait until touch is selected and maybe I want to see the graph associated with Apple stock.
And so again, I'm going to walk down to the Apple stock and use touch to drill in.
I can see how you get the graph related to Apple stock.
And so again, this is a really powerful feature and we think it's going to open up iOS to a whole new group of users and we're really excited to get it in your hands and to get feedback from you.
And so, that's Switch control.
OK. So as I said before, the rest of today, we're really just going to dive in and do some development and fix some Accessibility problems.
So before we do that, I want to give you a brief introduction to how UIAccessibility works under the hood to try and give you a better understanding of that process.
After that, we're going to do an Accessibility audit of the application I brought today and this will allow us to quickly find any Accessibility issues we have in our application so we can kind of get a game plan of how we're going to fix them.
And then once we've identified these bugs, we're going to use the UIAccessibility API to fix them again, you know, starting with the most basic and we'll see how far we can get just using those basic Accessibility attributes.
And then we'll work up to some more advanced problems, use a little bit of advanced API.
And again, the brand new API is going to let us do some some cool stuff that we're excited to see where you guys take that and then we'll finish up by looking at Guided Access.
So, how does UIAccessibility work?
The easiest way to explain this is to look at an Accessibility feature in action.
So here, you can see VoiceOver is on the far left, the Calculator application is on the far right, and we see UIAccessibility in the center tied to the UIKit stack as it is.
And so, as I said before, when VoiceOver is on, it is intercepting all of the touch and Multi-Touch gestures on the screen.
And what it's doing when it intercepts those is it's transforming them into questions that it can ask your application using UIAccessibility.
And so, if a user were to touch on a Calculator app say in the center of the screen, VoiceOver then internally, you know, computes this question, what is the element at this point?
And so, VoiceOver goes over through UIAccessibility to answer this question.
And if your application has correctly implemented, you know, the appropriate UIAccessibility methods, VoiceOver can then pull things like the accessibilityLabel and the accessibilityFrame right from your application and back over through UIAccessibility.
And so once VoiceOver has this information, it can transform it into output that's appropriate for the user so that output may be speech or possibly Braille.
Great. So now, we have kind of a general idea of how Accessibility features will query our application.
So, how can we make sure our application correctly responds to these queries?
How can we make sure we are playing well with these Accessibility features?
Well, as I said before, really, the easiest way to do this is to do an Accessibility audit of our application.
And so, if you're working in a simulator, we have a tool for you called the Accessibility Inspector.
But even better, if you're on the device, we can just use the Accessibility features themselves and this is really going to give us a great understanding of how our app works with Accessibility.
Both of these features can be found in the Settings application under General Accessibility as we saw before.
And it's worth noting that we also have a great extra feature called the Accessibility Shortcut, some of you may know it as its former name, just triple-click.
Accessibility Shortcut lets you tie an Accessibility feature or more than one feature to three clicks of the Home button.
And so, this lets you quickly click the Home button three times, turn something like VoiceOver on, do an audit of your application, click the Home button three times to turn VoiceOver off.
So, it's really handy for this audit process.
And so now, let's dive in and find our accessibility bugs today, let's see what we have to deal with.
Okay, as we said, we're going to open the Settings application, General Accessibility, same as last time.
I'm going to scroll all the way to the bottom and I see the Accessibility Shortcut.
So again, I'm going to pair VoiceOver with my Accessibility Shortcut and I really recommend you use VoiceOver.
I mean, you know, you can use Switch Control if you're feeling courageous.
But VoiceOver has the easiest learning curve and it's really a, you can turn it on, and just hear what's under your finger, navigate around.
It's really a quick and easy way to do a great accessibility audit.
And so now, if I click three times VoiceOver on, settings.
VoiceOver comes on and it reads what's under the cursor as expected.
And if I click three times again - VoiceOver off.
VoiceOver turns off so it's really easy.
And so now, let's open our application and see what we're working on today.
So the application we're going to be making accessible today is a floor a series of floor plans of the convention center.
And so, let's exam it before we turn accessibility on and see what and, you know, see what we're going to have to fix.
So if we look across the top, we have a label of the convention center and it looks like an indicator of what floor we're looking at.
On the left hand side, I see an Elevator control that as expected, let us increment or decrement the floor we're seeing.
And at the very bottom, a control called Coffee and if I swipe it, it shows us, you know, where you can find Coffee in the convention center right now.
And so, if we triple click to turn VoiceOver on - VoiceOver on.
Home button to the left, top and center.
So it comes on as expected and it lands on the first thing it finds and in this case, it finds a label at the top of the screen and that label is already accessible so that's great.
Let's try and touch the floor value next to the label.
So, it looks like I'm not getting anything when I touch the floor number next to the or next to the heading, I'm going to try touching the control on the left hand side.
Again, I don't see anything VoiceOver doesn't know anything is there, the control at the bottom, nothing and as expected, the map in the center, again, not accessible at all.
So, it looks like we've got our work cut out for us.
This is going to be, you know, you think this might be a tough job but you're going to be amazed that just in a few minutes, we're going to take this completely inaccessible application and make a great accessibility experience.
Okay, so we have an idea of the bugs we need to start tackling, you know, how are we going to fix these bugs, what API are we going to use?
So as I said, we're going to start with the basic API first and work our way up, pick off the low hanging fruit, take, you know, take off take down the easy bugs.
So, the two most important accessibility attributes we're going to be working with are isAccessibilityElement and accessibilityLabel.
So, for isAccessibilityElement, you want to return yes for any element that you want VoiceOver to see.
When we were using our application, we saw that VoiceOver wasn't even aware of most of the elements on screen.
And so to fix this, this would be the appropriate piece of API.
And it's worth noting that if you're using standard UIKit controls or labels like UILabel, this is on by default, VoiceOver knows about these by default.
You really get a lot of accessibility for free when you use the built-in classes.
And second, as I said is accessibilityLabel.
Here, we want to return a textual representation of the element and in the case of VoiceOver, this is the first thing VoiceOver is going to speak to the user.
And the last three pieces of easy API we're going to need to use are accessibilityHint, accessibilityValue, and accessibilityTraits.
So, for accessibilityHint, we're going to want to provide some additional usage information to the accessibility features like VoiceOver.
And we're going to want to do this in cases where maybe the implications of using this control or element as it were are non obvious.
So in the case of our Coffee control if we think back, you know, when you use the Coffee control, it changes something somewhere else.
So this would be a great place to add a hint to let the user know, you know, what's happening.
Coffee is, you know, the activating the switch will show or hide Coffee in a different location.
We also have accessibilityValue so the usually, an elements label is quite static but a value is meant to be changed.
So, if we think back to the header across the top of the application, we remember we had a static label that said Moscone West but we also had a floor value.
And so again, this is a great place to use accessibilityValue.
That floor can change as we adjust the elevator control up or down.
We can view a different floor and we always want to make sure we're returning the correct information to VoiceOver because it's going to call into these APIs a lot.
And so, the very last piece of basic API we need is accessibilityTraits.
So accessibilityTraits are a bit mask of unsigned integers that you can or together to really convey the behavior and intended use of that element.
And so, traits are a little tricky, you know, a little hard to wrap your head around if this is your first time.
So, let's take a look at an application that's already in iOS and see how the traits are applied.
Well first, we see this header across the top of the application, you know, it really contains the city and the temperature of that city and this really conveys, you know, the most information for this application.
And so here, it would be appropriate to use the header trait.
Similarly further down, we some static text, you know, these days of the week do not change, so the static text trait would be appropriate here and it would give VoiceOver an indication of how to speak this item.
Further down, we see a Standard button and the button trait will be appropriate here and it's worth noting that since this is, you know, built on top of a standard UIButton, a UIKit class, it already has this UIAccessibility trait of button, we don't actually need to add it.
And again, this is the case for a lot of these built-in classes, you know, they have the isAccessibilityElement yes, they're visible to VoiceOver, they have the appropriate traits.
If you've assigned a name to your button, if you're just using a standard round rect button, VoiceOver will use that as the label.
So, VoiceOver is very intelligent about these standard classes.
So, it's a good way to get the most accessibility for your buck.
And then lastly, we have this page control across the bottom and again, by default, this page control is an adjustable item.
And if you are rolling one yourself, you know, a selector type control, here is where you'd want to use adjustable and this really will lend itself well to that elevator control we saw on the left hand side of the screen because it is basically just an increment or decrement or up and down the change of the floor.
Great. So now, we know what pieces of API we need to use to get us most of the way there, how do we use them?
Well, if your interface is quite static and you are working in Interface Builder, the good news is you can handle most of it right there.
So, we have an Accessibility enabled check box that corresponds to isAccessibilityElement.
Similarly, we have a text field that is that corresponds to accessibilityLabel.
A text field that corresponds to accessibilityHint and then you see a series of check boxes below that correspond to accessibilityTraits and you're going to want to select all the traits and they are, you know, under the hood or together to really convey the behavior and usage of this element to VoiceOver or any Accessibility feature.
So, what if you're working in code?
Well again, if your interface is quite static, we can set these attributes, we don't have to override them.
And so, you know, we find an appropriate place to do that like awakeFromNib our header is created and then we're going to set the isAccessibilityElement value to yes.
We're going to set our accessibilityLabel to something appropriate.
And then, we're going to set our accessibilityTraits to something appropriate.
And again, in this case maybe the header trait was most appropriate.
But your interface isn't always static, right?
I mean our interface that we're working on today is not static so what do you do in these dynamic cases?
Well, here is where you're going to want to override these methods and make sure you're always returning the appropriate value at the appropriate time.
And so here, we've overridden accessibilityValue and we're always returning the actual floor number that we're on.
And so again, we're going to use accessibilityValue in our application for exactly this purpose.
Great. So now that we have an idea of the basic API we're going to use, let's go ahead and see how well we can do with just that in our application, OK?
So, let's start by taking a look at this, you know, header information across the top of the application.
So, if I find the class, I know that is my titleView, I'm going to go ahead and just grab the basic accessibility attribute stubs and drop them in and just go right down the list.
So first, we want VoiceOver to see this element so isAccessibilityElement YES is absolutely necessary.
Secondly, we need a label for this element and we saw that because we have a standard UILabel as a sub view of this view, you know, it was already accessible, it already had it lends itself well to accessibility.
So, what we're trying to do here is combine the floor and the label together because they really only make sense together out of context if you just heard, you know, two out in the middle of nowhere, it really makes no sense.
And so again, we're combining this information, we're combining these sub views together.
And so, we're going to do that by simply returning the value that title label was already giving us, titleLabel, text, great.
So, this is a pretty obvious element, accessibilityHint is not really necessary here but we do have a use for value.
And for value, if I jump to the header, I can see that this element, you know, has a representation of the floor internally.
And so this is a great place to use that.
[ Pause ]
[ Pause ]
And I'll leave traits out of this one.
It's worth mention that Accessibility is just like application design in general.
You know, there is often no exact right answer, just like you're designing your interface to convey what you want to convey to the user, you do that with Accessibility as well.
And so, you know, you need to make these choices as you progress.
And I should also make note, you know, we always want to localize our labels and use number formatters as appropriate.
VoiceOver works in a huge number of languages but for brevity, we'll leave that out today.
So next, let's take a look at this Coffee control on the bottom of the screen.
We're going to start the same way as before.
The first thing to do is make sure Accessibility can see this control.
Again, we need to return a label for this, something appropriate and go ahead and call it Coffee.
And as we said before, you know, the implications of activating this switch might not be obvious to all users so let's go ahead and return a hint here, maybe something like show or hide Coffee locations.
So, what should our value be?
Well, we do have a value associated with this control, right, and that value is off or on.
And so here, if I jump to my header again, I see that it does have a state of off or on and so I'll just go ahead and use that state.
And if it's on, let's return a string that says on.
And similarly, if it's off, let's just go ahead and return off.
And lastly, traits, what should the traits be for this.
Well, I'm thinking that the most appropriate trait here is button.
This really is a stateful button.
If you, you know, press it, you can get it to go on, if you press it again, you can get it to go off.
And so, we'll see how button works.
Let's see lastly, let's take a look at this Elevator control on the left hand side of the screen for our, you know, to see how to use our basic API.
And so, let's find it, Elevator control.
We'll drop in our stubs.
Again, let's make it visible to Accessibility, that's our first step.
We need an appropriate label for Accessibility features to speak or use as they need.
And here, let's do Floor.
It, you know, there's really no need for a hint in this case.
Again, it's pretty obvious.
The same as before, we're going to need to convey that floor value and if we flip to our header, we see that this control too has or this element too has a floor value associated with it.
So, let's go ahead and return the oops.
And lastly, traits, what traits do we want?
Well, as I said before, this is really an incrementor/decrementor and so, this is one of those times when you as the implementer, you know, have to make these decisions yourself just like you're designing your application.
We're going to have to make some Accessibility choices.
So, we could make the top button, you know, an increment button and the bottom button a decrement button.
But again, I've decided that, I think, it would be most useful if we just made this an adjustable control that you could easily flip up and down.
And so, let's go ahead do that, I'll try adjustable.
Great. And so now, let's go ahead and push this to our device and see how we did with just a little bit of accessibility.
Double tap to open, VoiceOver.
VoiceOver is a little jumpy, anxious.
[ Pause ]
Okay, so if we switch back over to our application, let's turn VoiceOver back on.
VoiceOver on, landscape.
Home button to the left, Moscone West, floor two.
Great. So if we check the title or the header across the top of the screen.
We see that, we've now mashed all of that information together into one element and it really makes sense, you know, the context and the label are really all there together.
So let's try the control on the side of the screen.
Floor two, adjustable.
Swipe up or down with one finger to adjust the value.
Great. So VoiceOver can see this element as well.
And since we've used the adjustable trait, it even gives us a hint on how to use this element and it's telling you to swipe up or down to increment or decrement.
So, I'm going to swipe up.
Unfortunately, we hear the bonk so there's something we're missing there.
We're almost there so we'll have to handle that one again.
And the Coffee control at the bottom.
Coffee, up button.
Show or hide Coffee locations.
And we heard the hint which gave us some more information about what this control actually does, you heard it speak button because we applied the button trait to this control.
And so now, let's go ahead and try and double tap to activate this.
OK. So we still have an issue there as well.
You know, VoiceOver is unable to activate it.
By default, when you double tap, VoiceOver is going to send a touch to the center of that element.
And in this case, since our control is using swipe, this touch sent to the center is not going to do what we want it to do but we're in great shape, right?
We fixed a huge amount of the interface with just a little bit of work.
So, let's see how we can get the rest the way there.
Well, the elephant in the room in this application, the big hurdle we have left to get over is that map.
How do we convey this rich spatial information out of what is essentially a custom drawn view.
So, the answer to that is we use something called the UIAccessibility container protocol.
And here, we're going to create Accessibility elements that represent everything we want to convey to the user and return them using the UIAccessibility protocol.
And so, the three methods, we're going to be using are accessibilityElementCount, accessibilityElementAtIndex, and indexOfAccessibilityElement and you might be thinking these look like array methods.
Well, that's great.
They line up very well with an array.
So, what we can do is create these elements, put them in an array and I've called my array rooms here and I just rely on those, NSArray methods to really return this information to Accessibility as needed.
And so, let's look at how we would do that, how do we fill that array with accessible elements?
Well, the first thing we need to do is create an accessibility element for every room.
And so, this is an example of us doing it in a loop.
Secondly, accessibility elements unlike UIView elements.
If, you know, if we're talking about UIView elements, they have an accessibleFrame, an accessibilityFrame rather by default, and that accessibilityFrame is just pulled from the actual frame of that element.
But we're creating these elements, you know, out of thin air so they don't have a frame, so we need to figure out what we want this frame to be.
And so, I have a helper method that's, you know, giving me a Frame for each room and we have a nice convenience function in UIAccessibility.h that lets you convert your frames from view coordinates to screen coordinates because all of the accessibility works in the screen coordinates.
But the great news is you don't really have to worry about it, just use this convenient function.
And the last thing we need is a label.
So, we need to, you know, convey a textual representation of these accessibility elements to VoiceOver or whatever the accessibility feature is.
Another problem we had was that Coffee control across the bottom of the screen, right?
We double-tapped on it, nothing happened.
And again, you know, our hypothesis is that that is because it was only activatable by swipe.
We in this case, we're using a UIGestureRecognizer under the hood and it's just looking for swipe, it's not handling touch at all.
And so when you get yourself into cases like this, we've added some brand new API in iOS 7 that's going to allow you to, you know, get yourself out of this corner.
And the way you can do that is overriding accessibilityActivate on any method.
And if you handle Activate, you simply return yes after you handled it.
And so here, what we're going to do is take that default input from VoiceOver and transform it into, you know, the equivalent of a swipe so this control just works.
And then lastly, some really cool API that we've added is accessibilityPath.
So, in historically, VoiceOver has only worked with, you know, the cursor has only been a rect.
And the problem with this is that we're unable to convey spatial information to users, you know, if you can imagine if this Map used a rect for every single element, it wouldn't really help us.
We wouldn't really get any of that rich spatial information.
But now in iOS 7, we can override accessibility path or set accessibility path as necessary and this is going to be preferred over accessibilityFrame any time it's present.
I mean you can see what this is on the screen, what this is going to allow us to do.
Great. So, let's now go back to the application and implement some of this more advanced API and see what we can do.
OK. Again, I'm going to go ahead and grab my stubs, I'm going to find my floorPlanView and drop them in.
As we said, we need somewhere to cache this.
We don't want to be making these elements all the time, right?
That would be expensive so let's create an array to store them in and I'll call my array, how about axRooms?
Great. And so now, as we saw on the slide, we can simply go through these, use our array, and fill these in as appropriate.
So, for accessibilityElementAtIndex, we're just going to use the corresponding method on NSArray.
Similarly for accessibilityElementCount, we just go right to the array.
And then as expected lastly, for indexOfAccessibilityElement, we can just align that well with indexOfObject and pass that element in.
Great. So now, we're returning these elements as needed but we still have to create them, right?
And to do that, let's go ahead and grab our helper method and walk through it.
So here, we're lazily creating an array to hold these accessibility rooms and so, this won't happen until Accessibility asks us for them, you know, and at the very last minute lazily, they will be created.
And then you can see, I have a helper method here, floor plan features.
Under the hood, that is returning to me all of these paths that are being drawn because that's really what we need.
And so, you might notice that we are enumerating this backwards and there is a reason we're doing that.
We're enumerating backwards because I've ordered my bezier paths from biggest to smallest.
And so, it's important the array of elements that we're creating are actually used for hit testing as well.
As a user drags their finger around the screen, you know, that's how we're hit testing for these accessibility elements that we've created.
And so we have to order these from smallest to biggest.
We want, you know, elements that are above bigger elements to be hit testable.
If we put the largest element on top, you know, none of the smaller sub-elements would ever be reached.
So, it's important in this case that we go backwards through the array.
And then again, at every step, we're going to create an accessibility element, we're going to get an appropriate accessibility label for that element and we're going to get and set an appropriate accessibility path for that element.
And just like we have a convenience function for converting frames to screen coordinates, we also have the convenience function for converting paths to screen coordinates so it's really helpful.
So, that's not it, we have one more thing to do.
What happens when we change floors or show or hide Coffee?
Well we're going to need to throw this array of elements out occasionally, right?
If we select a different floor, those accessibility elements we created are no longer valid.
And so, anytime we set a floor, we can just simply throw those rooms out.
And similarly, if we change the visibility of Coffee, we can just, again, throw the rooms out.
And the next time, VoiceOver or an Accessibility feature calls in looking for them, they will be just created, you know, with new updated information.
Great. So, two more problems we had.
One, we still have to fix our Coffee control, so let's go ahead and do that now.
And as I stated, the new method we're looking for here is accessibilityActivate.
And so if we jump to the header, we again see that on state and really, all we want to do is toggle that on state when VoiceOver double taps.
So we can do self.on equals not self.isOn and that should take care of it.
And as I said before, if we are handling it, we want to return yes and in this case, obviously, we're handling it every time.
Maybe you have some more complex logic and this return value is not constant.
And then lastly, we have this elevator control.
We need to swipe up and down to work appropriately.
So, let's go ahead and find the elevator control again.
And the last two methods we need to implement are two methods that work hand in hand with the adjustable trait and those methods are accessibilityDecrement and similarly, accessibilityIncrement.
And so, it just so happens, I have a decrement floor and increment floor method and so, this will be really easy.
I can just go ahead and call decrement floor in the accessibilityDecrement method and similarly, increment floor in the accessibilityIncrement method.
Great. So let's clean and go ahead and build our application and see how we did.
[ Pause ]
Okay, let's turn VoiceOver on.
VoiceOver on landscape.
Home button to the left.
So, let's go down and try the elevator control first.
I'm going to stop VoiceOver Speech by doing just a two finger tap on the screen.
Now, I remember the VoiceOver told me to swipe up or down to adjust this so let's swipe up.
And it did not work and that happens.
And so let's - Take time.
Let's try repushing.
Double tap to open.
WW floor three.
Okay, there we go.
We just Xcode problem, it was angry with us but so we repushed the code, we can do the swipe up and now, we get the third floor.
And if we swipe down - Two.
Coffee Let's try that Coffee control.
I'm going to double tap on it.
And you can see that VoiceOver produces the appropriate noise to let the user know that yes, this worked.
Everything is happy, we now see Coffee.
And now really, the biggest issue is how did we do in terms of the path?
So, let's touch in to the lobby.
Great. So now, we can see that VoiceOver knows about the lobby.
And if I move my finger down, take the escalator.
I see the escalator.
And now, I can just kind of move up and I'm in the lobby, I'm still moving up.
And I get to the stairs eventually.
So you can see that this allows VoiceOver users to, you know, move their finger around the screen and really get a sense of the spatial nature of this Map.
Hold hot coffee.
Thankfully, even Coffee works.
[ Pause ]
[ Applause ]
Great. So as I said, you can see we took this really inaccessible application and made it Accessible with just a little bit of work.
And, you know, I think you're going to find that's the case for you as well.
And so now, let's move on to Guided Access.
I want to talk about a few things we learned from Guided Access since we introduced it in iOS 6.
And so, the first thing we learned was hardware buttons are useful.
Our initial approach with Guided Access was when Guided Access is active.
We kind of remove all hardware buttons, you know, none of them work, we really want to remove all those distractions.
But we got some feedback and, you know, it turns out a lot of really powerful great, you know, camera apps use the volume buttons and other apps use more buttons for different things so lesson number one, hardware buttons are useful.
Lesson number two is if you want to occlude a region from touch in Guided Access, currently, you know, you draw an area around that region on the that area becomes grade out when Guided Access is active.
And so, that works great.
You can disable buttons as you need to.
The only problem is this doesn't address the visual distractions associated with the application and so, that's the problem and we think we can do better.
And lastly, developers are eager to adapt.
A lot of you reached out to us and, you know, that's what drove this API.
And so, we're really happy to show it to you and see how you use it.
And so, the best way to explain this is to jump right in and just give a demo of Guided Access.
[ Pause ]
So now, I'm going to return to the Accessibility Settings menu, to General Accessibility.
I'm going to scroll down, remove VoiceOver from my shortcut and instead, add Guided Access.
I'm going to go ahead and set a passcode for Guided Access, nobody look.
Great. So we're all setup, let's open our application.
And so, if I click three times and enter the Guided Access workspace.
So, what if we want to share this application with someone or maybe we're a developer that wants to develop one application for two purposes?
One application to give to users of say a conference at this venue and that same application to maybe post around the halls and just display the floors.
So, maybe you want to hide certain controls or really change the user interface on the fly.
And so up until now, really, the only option you've had is again, to circle these controls you want to occlude and then VoiceOver or and then Guided Access will disallow touch from happening in these places and so users won't be able to change these things.
But again, especially if you're developing one application for both users in Kiosk, these visual distractions still exist and it, you know, it looks pretty unprofessional in that case.
And so, let's go ahead and remove those regions.
And so now, in Guided Access in iOS 7, any app that's bought into this developer API will have this new option that we can see in the bottom right corner and you're presented with options button and an icon of your application and your application's name.
And so, when I touch that options button, up pops this list of all of the restrictions that my application wants to provide to the user.
And so in this case, we see that we have a controls restriction and some detail text that kind of explains the implications of using this control.
In this case, these controls adjust the floor and show Coffee.
And so, if I go ahead and turn those controls off and resume Guided Access, what happens is we call into your application and we tell you, you know, the user wants to make these changes, you know, act appropriately, and then it's your job this is your opportunity to then go into your application and make the appropriate visual changes or respond otherwise accordingly.
And so similarly, if we go back in, turn the controls back on and resume, you can see that your application is given another call and, you know, here is your chance to re-add those controls to your view hierarchy.
So that is the new Guided Access Developer API so let's take a look at how it works.
So right off the bat, the first things to note are these restrictions are per application, they are not per view they are not per view controller.
And because of that, the appropriate place to implement them is on your UIApplicationDelegate.
So, this protocol exists there and there alone.
The second thing is we wanted to make buying in as easy as possible.
We really wanted to lower the bar and, you know, make adaption easy.
And so for that reason, state persistence comes free.
You don't have to maintain state in your application of what the user has currently set this restriction to.
We do that for you and we simply call you anytime you need to, you know, update your interface as appropriate.
And so, the first three methods that we're going to look at are guidedAccessRestriction Identifiers, textForGuided AccessRestrictionWith Identifier: and detailed TextForGuided AccessRestrictionWith Identifier:.
And so let's start from the top.
In Guided Access restriction identifiers, you're going to want to return a unique restriction identifier for every restriction that you'd like to enable the user to control.
And so in this case, I've just, you know, made a static string for this to, again, for brevity to kind of shorten it.
But the header offers more on the way to do this and we really recommend that you use reversed DNS notation.
These all need to be unique in your application.
So again, here is where you would return an array of these strings.
And then, the other two methods we're going to call into your application when we detect that you have a restriction you'd like to convey to the user.
Then for each restriction identifier, we call in your application and we say, you know, what is the text you would like presented to the user for this restriction identifier?
And similarly, what is the detail text you would like presented to the user.
So this is your chance to give that to us and we will display it to the user.
I mean you can see here, I'm not actually checking the restriction IDs, we only have one restriction so, you know, we can go ahead and safely just return the values for our one restriction.
And the last method is mouthful that we want to take a look at.
guidedAccessRestriction WithIdentifier:did ChangeState:.
So, this is what I was talking about before and the reason you don't have to maintain state in your application, we're doing that for you.
And anytime the state for restriction identifier changes, we simply call into this method with the restriction ID and with the new state of that restriction and this is really your chance to update your user interface as appropriate.
And so here, we're doing self set control enabled enabled.
And lastly, we do have a helper function that will let you check the state of a restriction at any time if you need to.
So that's Guided Access and, you know, we're really happy to get out there, we're excited to see what you're going to do with it.
You know, you asked for it, we delivered it but there's one more thing that you asked for over the years and we're really happy to give it to you today and that's a brand new Text-to-Speech API.
[ Applause ]
So, we know a lot of applications in the App Store have some Text-To-Speech functionality.
And really, up until today, your only option has been to, you know, roll your own Text-To-Speech ability into your application and while this works, it can make your application quite large.
And so, we have gone ahead and added this in and the good news is it's extremely easy to use, you can use it in just three lines, you can make your application speak.
And now, you have this, you know, this option.
First you just allocate and initialize a synthesizer object.
Second, you make an utterance out of a string that you'd like to speak.
And last, you just speak the utterance and it's that easy.
You can make your app speak with just three lines and it's also worth noting that this works in Safari.
There are some Web Speech, there is a Web Speech ability that you can leverage to get this to work right from Safari if you're working on a web application.
Great. So for more information, go ahead and check our documentation.
We have a great wealth of Accessibility documentation that should help you get started.
And if you, you know, you have deeper questions, the dev forms are always a great place to go for those deeper questions.
For related sessions, there is a desktop accessibility talk in this room directly following this so stick around if you're interested in desktop accessibility.
Or if you are interested in developing, you know, Made For iPhone hearing aids, or switches for our Switch Control feature, you can come over to the designing accessories for iOS and OS X.
I mean, that is also directly following us over in Nob Hill.
So in summary, we saw that adding accessibility is easy, I mean, we made this application accessible with just a few lines and it was, you know, virtually inaccessible before.
It's going to get you more users and great feedback.
We've always found throughout the years that the Accessibility communities provide us with great feedback.
And then lastly, you know, we take accessibility very seriously here.
And so, we want you to too and it's that partnership that has made iOS really the best mobile accessibility platform out there.
Thank you all for coming.