Tuesday, April 9, 2013

Google Maps for iOS is broken in a fairly major way, after a recent update

Google Maps for iOS is broken in a fairly major way, after a recent update

After Apple Maps took me to the wrong place once or twice, I switched to using Google Maps exclusively. But I noticed it’s been behaving very strangely recently, relating to automatic screen dimming. But before I explain the issue, some background is necessary.

All about Auto-Lock

iOS has a feature officially referred to as ‘Auto-Lock’, which really is just a fancy way of saying the screen will turn off automatically after a period of time of not interacting with it. You can configure the amount of time it takes before this happens in Settings > General.

It’s worth noting, for reasons that will become clear, that Auto-Lock behaves differently when the device is connected to power (e.g., my car charger), compared to when it is on battery. On battery, the screen will turn completely off after the Auto-Lock interval has elapsed, and the only way to turn it on again is to push either the home button or the sleep/wake button; but when connected to power, the screen will only turn most of the way off, and can be turned all the way on again simply by touching any part of the screen. Most importantly, in this latter case, touching the screen does not send any touch events to the app which is visible on the screen; you could have put your finger right on top of a button, but the app would not know that you had touched the button while the screen was dimmed. This makes sense, because in the dimmed state, you may not be able to clearly see where the buttons and other controls are placed, so it would otherwise be easy to interact with something unintentionally.

Apps can temporarily override the Auto-Lock setting in order to force the screen to stay on for as long as they want. This is usually accomplished with UIApplication -setIdleTimerDisabled:. Regardless of what an app does with this setting, it the operating system restores it back to the standard behaviour once the user returns to the home screen or switches to another app.

Previously, both Apple Maps and Google Maps would override Auto-Lock while navigation was in progress (by setting the value to YES), but restore it after navigation ends (by setting the value back to its default, NO). In other words, simply having the app open was not enough to keep the screen on; you actually had to be in the middle of receiving directions. This is a sensible trade-off between battery life and providing the user with essential information when necessary.

What Google broke, and how they broke it

As of the most recent Google Maps update, the screen now dims automatically, several seconds after the app has provided a direction, in cases when there are no future directions planned for some amount of time. The difference here compared to what I described above is that instead of using the time interval since the last user interaction, Google Maps uses a combination of the time interval since the last direction and the time interval until the next future direction, to determine when to dim the screen.

This is in fact not iOS’s Auto-Lock feature in action; one reason you can tell is that, contrary to how Auto-Lock works, touching somewhere on the screen while it is dimmed in Google Maps does result in a touch event being sent to and reacted to by the app. One likely result of this is disabling location tracking, which is what happens if you touch anywhere on the map (i.e., most of the screen) while the app is in the middle of giving you directions. This is extremely inconvenient: the map no longer shows your current location, but instead is frozen at the location where you happened to be whenever you last touched it, which is almost certainly not what you wanted when you were in the middle of looking at directions for how to get someplace.

Most likely, Google Maps is using the UIScreen brightness property to force the screen to dim after a time interval of its choosing, rather than allowing iOS to use the system-wide configured Auto-Lock interval. This is probably because of the app’s intention to brighten the screen again in anticipation of the next direction coming up; indeed, the way they apparently implemented it is the only way I can think of that it would even be possible to accomplish this, since there is no API (as far as I’m aware) to allow an app to bring the device out of an Auto-Locked state. Moreover, the screen brightness setting, being an entirely different mechanism than Auto-Lock, does nothing to prevent user interaction with UI controls.

In short, Google Maps prevents the device from going into Auto-Lock, but then implements its own feature which is similar in some ways to Auto-Lock, but not the same.

It gets worse. Most of the time, touching the screen after Google Maps dims it, in addition to cancelling location tracking and making you curse in frustration, restores the screen brightness to its original level. But sometimes, it doesn’t. Again, because the operating system’s own Auto-Lock feature is not being used here, it is up to Google Maps to set the UIScreen brightness back up to the level that it was previously at before it was dimmed. But it sometimes fails to do that, in which case you can tap the screen all you want, but it will never go back to being visible. In fact, since UIScreen brightness makes the change system-wide (the same as if the user had changed it in Settings), even pressing the home button to return to the home screen, or switching to a different app, will not fix the screen brightness! The contents of the screen will remain nearly invisible until you press the sleep/wake button to turn the screen completely off, and then press sleep/wake or home to turn it on again, which for some reason sets the device back to a reasonable brightness level (perhaps in some way related to the Automatic Brightness setting Edit: Explained here).

Need I explain that when you are in the midst of trying to drive a car, this is not really a good thing to have to be fiddling with?

Thinking about how I would implement this as a programmer: Before dimming the screen, I would copy the value of UIScreen brightness into a temporary variable, and then when it was time to brighten the screen again, I would copy that temporary variable back into UIScreen brightness. Fairly simple. But it’s easy (for most programmers) to see how this approach could go wrong: If I somehow accidentally copy the value of UIScreen brightness into the temporary variable when the screen was already dimmed, then the original brightness value would be lost; and every time the user or the app tried to restore the screen to its original brightness value, it would just be set to the dimmed value instead, every time, indefinitely. This could happen in the event of a race condition, possibly resulting from an event firing more times than expected in quick succession, or through unsafe use of multithreading. Although this is only my speculation, I have seen similar bugs enough times that this would be one of the first things I would look for if I were trying to debug it.

Sweet road to somewhere else

So, what can we learn from this? Typically, it is a really bad idea to try to re-implement operating system functionality from scratch at the application level, unless you have a really, really good reason. The reason is that your implementation is likely to miss subtleties that users depend on, and introduce bugs or other discrepancies that are not present in the operating system implementation. In the best case, it ‘feels wrong’ in ways that users notice intuitively but are unable to articulate precisely. In the worst case, it fails spectacularly due to a complex condition which the operating system developers anticipated and you, an app developer with much different sorts of concerns on your mind, did not. Which is exactly what happened here.

Although, it’s not really surprising that this was attempted, considering the app in question. Google Maps uses entirely custom user-interface widgets, too. It’s Not Invented Here from the ground up. This sort of design philosophy has a tendency to pervade throughout. In other words: Google aren’t trying to make a well-behaved iOS app, but instead, an experience unlike anything else on your iPhone. Well… I guess in that respect, they’ve succeeded.

What I can’t figure out is why it was so gosh-darned important to have the screen dim and brighten according to the timing of the directions. Why not just leave the screen on all the time while directions are up, like the previous version did, and like Apple Maps continues to do? I suppose there is an argument to be made about battery life, but even then, the obvious counter would be that this should only be enabled when device is UIDeviceBatteryStateUnplugged.

But even then, I’m not sure the trade-off is worth it. I frequently glance over at the screen while driving in order to see how far it is to the next exit or how long it will be until I arrive. As long as that information is always visible, it’s not substantially different from glancing at the speedometer or gas level from time to time. However, having to tap on the screen every time I want to see the map is an extra unnecessary use of my motor skills, which makes it an unnecessary distraction, and that makes it dangerous. I daresay that, even if I didn’t have a car charger, running down the battery a little bit in exchange for a safer driving experience would be the right choice to make, don’t you think?

The simplest explanation might simply be that they were trying to mimic the behaviour of the Android version of Google Maps, which follows the same dimming and brightening pattern, but which likely has a very different system for handling these sorts of things. I’m really going out on a limb here, but: It’s easy to imagine a non-technical product manager making this decision without understanding its ramifications, and then the developers having to do it because that’s the food chain. Then again, this is Google we’re talking about, so in theory there shouldn’t be any such thing as a ‘non-technical’ person. I wouldn’t know.

Have I reached the party to whom I am speaking?

The linked discussion thread does, remarkably, feature a few responses from a Google employee. The first is your standard impersonal brush-off in the form of your-feedback-is-important-to-us (uh-huh). A more recent response makes an oblique reference to ‘optimizing’, without actually admitting the existence of a problem; but perhaps, this may be taken to indicate that someone somewhere is working on something which might hopefully be relevant to the issue at hand. This kind of exchange is typical of what happens when the people who actually understand what’s going on are not the people who are allowed to talk to you. On the other hand, Google is legendary for their lack of end-user support, so the fact that there is any kind of response at all is, perhaps, a step in the right direction. Still, the fact that the app has remained broken for so long (over a month as of writing) is very frustrating. One would expect better from a smaller company that lives or dies based on the strength of their product, but Google are long since big enough for this sort of thing not to matter terribly much to them.

Meanwhile, I’ve been forced to give Apple Maps another try, seeing as how Google Maps is pretty much unusable for me in this state. So far, the Apple Maps data actually seems not so bad, and of course, the UI has always been much better than Google Maps. So, thanks, Google, for… [puts on sunglasses] showing me the way?