Android 6.0 – Runtime Permissions – Facebook Case Study

With Android 6.0 Marshmallow, permissions have moved from an up-front approval model to a runtime model.

This is great for users, as they now have fine-grained control over what information apps can access, but it introduces new challenges when designing interactions that involve those permissions.

Installation

First, let’s take a look at the experience downloading an app fresh from the Google Play Store.

Here’s what installing Facebook looks like on KitKat (5.x):
KitKat Google Play Store

Here’s what the user experiences on Marshmallow (the dialog is only shown the first time a user installs an app post-upgrade):

App Store Training

There’s less friction during install since users don’t need to guess why the app might need access to the Phone permission in some situation.

Requesting Permissions

To illustrate how the new permission model works on Marshmallow, let’s walk through an example in the Facebook app. Imagine we want to share a picture. Let’s tap the “Photo” button.

The user is immediately shown this system dialog which formally asks for permission to access the device’s storage.

Tapping “ALLOW” will let the user proceed to select a photo. Tapping “DENY” does not allow the app access and makes subsequent requests more complicated as we’ll see shortly.

The “Second Ask” 

In an attempt to avoid an app constantly popping the system dialog, Marshmallow surfaces a “Never ask again” checkbox on subsequent “official” requests for a given permission.

second request part two two

A poorly designed app might let the user get to this state too quickly without providing additional context why the permission is required.

If that happens, it’s unlikely an average user will be able to reactivate the permission, as it’s hidden behind the “Permissions” screen for that app in settings:


Fortunately, Facebook is not a poorly designed app – the design team has figured out a sequence of interactions to ensure the permission is granted before entering this bad state.

Ask Before You Ask

In the situation where a user declines the first official request for a permission, Facebook explains to the user why it’s needed before invoking the second official request.

Summary

Overall, there are some interesting nuances to requesting permissions with the new model introduced in Marshmallow. Here’s a final diagram attempting to document the possible flows.

Flow Overview
(click to enlarge)

As you can see, there are progressively more steps the user must complete the longer the permission is withheld.

Further reading:

Brenden Mulligan wrote a fantastic reference in the art of asking for permissions on iOS.

Official documentation:


Disclaimer: I have no affiliation with Facebook, I choose it as a case study since it’s a very popular app that handles the corner cases nicely.

nc – “Netcat”

My favorite tool of the day is nc, or Netcat.

Like most unix programs, it’s a well-documented single purpose application. From the man page:

The nc (or netcat) utility is used for just about anything under the sun involving TCP or UDP.  It can open TCP connections, send UDP packets, listen on arbitrary TCP and UDP ports, do port scanning, and deal with both IPv4 and IPv6.  Unlike telnet(1), nc scripts nicely, and separates error messages onto standard error instead of sending them to standard output, as telnet(1) does with some.

This is particularly handy when debugging network applications. Instead of wondering whether bugs lie in your application code or in the server, you can simply point your application to nc to easily see what’s being sent across the wire.

To illustrate the simplicity, let’s send “Hello world” between terminal windows (this could be across the world almost as easily).

Start by opening a terminal window and typing “nc -l 4567”. This command tells netcat to listen for incoming TCP connections on port 4567.

Screen Shot 2013-11-13 at 10.37.33 PMNext, open a second terminal window and type “nc localhost 4567”. This command tells netcat to connect to localhost (the current machine) on port 4567. This connection will succeed because we’re the ones listening.Screen Shot 2013-11-13 at 10.39.30 PM

You’ll notice it looks like the program is hanging, but start typing into the terminal and press enter/return and you’ll see each line appear in the first terminal like magic.

Screen Shot 2013-11-13 at 10.42.10 PMScreen Shot 2013-11-13 at 10.42.13 PMKilling the second window will close the connection.

Additional applications for this include sending files over the connection (via netcat localhost 4567 < file.format).

Android 4.4 – KitKat – Step detector code

One of the new features in Android 4.4, KitKat is the “Step Counter” and “Step Detector” sensors.

I wrote a quick sample app that utilizes the step counter. It acts like a simple pedometer, registering for the sensor events when it starts, and updating the UI with the latest step count whenever a new event is returned.

This updating won’t be in real-time, as the system batches up events. The code currently specifies SensorManager.SENSOR_DELAY_NORMAL as the update frequency – this amounts to 200000 microseconds, or 5 updates a second (should be good enough, even if you duct tape your phone to a cheetah).

I’m using the TYPE_STEP_COUNTER Sensor, which dispatches an event with the total number of steps periodically when a new step is detected. The other Sensor is TYPE_STEP_DETECTOR, which fires a timestamp sensitive event with every detected step (rather than the total number of steps detected so far).

For now, this only works on a Nexus 5 running KitKat, since the API was added in KitKat and the Nexus 5 is the first device to ship with a dedicated low-power step detecting chip.

The code is available on GitHub: android-step-counter

Image

Android – Google Play Beta Testing

So, I’ve played with Google Play Beta Testing for Android for a couple weeks since Google IO now. I think there’s a lot of promise, but for now the process is perhaps a bit overly complicated.

Here are the steps to get it working (first time only):

  1. Create a Google+ community for the Beta tester group
  2. Sign into the Google Play Developer console, go to the APK section, then the Beta (or Alpha) tab and click “Manage list of testers”
  3. Select your community

APK Section

Beta ConsoleManage Testers

Now for each new person, you have to do the following:

  1. Invite tester to community (might have to sign up for Google+, might have to learn what Google+ is, etc)
  2. Make tester click a link to switch them to the beta build (format of https://play.google.com/apps/testing/com.your.package.name)
  3. Send them to the Google Play store to download your app (again?) to get beta build

If they do these steps out of order, it won’t work.

I really appreciate the effort Google has made to make it easier to distribute Beta versions of apps directly from the Developer Console and how easy it is to “Promote to Prod” when a given build has passed beta testing, but I think the first-time setup process could be better, and they could open it up to people without Google+ accounts (I’ve had at least one person decline to Beta test because they’re afraid of social media.)

Further Reading: Official documentation.

Flurry Configuration

Over the last few months, I noticed that one of my apps, was searching for GPS long after the app was closed. I noticed that it usually happened in low-GPS areas and seemed intermittent.

After looking into the usual culprits – not calling myLocationOverlay.disableMyLocation()  or not calling locationManager.removeUpdates() in onPause(), I discovered a new problem I hadn’t seen/heard of before.

After some forensic debugging, I found this line of code:

FlurryAgent.onStartSession(this, "<Flurry API Key>");

I thought, there’s no way that Flurry is requesting location and not giving it up when the app is backgrounded, right?

Wrong.

After some digging in the API docs, I found:

static void setReportLocation (boolean reportLocation)

Set whether Flurry should include location information within its reports. Defaults to true.

Calling setReportLocation(false) fixed the leaking GPS issue (since I don’t care about location analytics on Flurry anyway.

Hope that helps someone!

FastTimes: One Year Later

Since my last update, I’ve moved to Chicago and started work at Orbitz. Last summer, some of my coworkers told me about the Chicago Transit Authority (CTA) Bus Tracker API, which provides live arrival predictions for each of the 1,700+ buses and 11,000+ bus stops in Chicago. Upon closer inspection, I also discovered that the CTA had recently added an API to track live arrivals for each of the 145 El Train stops.

After working on Android apps during my time at Michigan, I was excited to continue Android development and build out an app that took advantage of the live prediction data.

As the saying goes, “good software starts by scratching a developer’s personal itch” and I began development by wiring up a really simple app that had 3 buttons (home and work), called to the CTA Train Tracker Service, parsed the response and displayed a dialog to with the predicted arrival time

As simple as this first product was, it was actually quite functional, allowing me to save several minutes off my commute each day. With this successful proof of concept, I began to build out a system that would be useful to more people around Chicago (after all, not everyone lives in my neighborhood and works in my building).

My primary goals were:

  • Build an app that integrated the Bus Tracker API, Train Tracker API and favorite stops.
  • Make it FAST.
  • All routes/stops should be stored locally and only need network to get live predictions
  • Make it popular, which means it had to be free and ad-free.

I spent the next few months working nights/weekends on and off to build out a 1.0 version of the app. I constantly “ate my own dog food”, using solely my own app when riding the CTA.

After about 2 months of part time work, I finished the first beta. I enlisted a few of my coworkers to try out the app on their phones and give me feedback. This included design tweak suggestions as well as bug reports. At this time, bug reports looked like “Sort by Time – Refresh still sets it back to sort by bus.”

At Orbitz, we practice a form of Agile development, which features frequent releases and constant iteration. I tried to iterate quickly and add features that I wanted to see in the app. A few lessons learned about self-development:

Ship.
It’s easy to be ashamed of the quality of your product. Don’t be. Ship and start iterating.
Ship early and ship often.
Even if your customers are co-workers who aren’t paying anything for your product, this early feedback is invaluable.
Instrument like crazy
In my app, I have lots of settings. In early versions of the app, I had no idea how users interact with my app. Free analytics tools like Flurry are immensely helpful in capturing these interactions.

After beta-testing personally and with office friends, I finally released “FastTimes: CTA” version 1.0 on October 18, 2011. The first week, I got 43 downloads (!). I was estatic. 43 people wanted to use something that I created in my spare time!

Train Lines
Train Lines
Screenshot of Orange Line
Orange Line View

Throughout the fall, I shipped several updates to the app, adding features, updating the stop list and improving stability. After joining the Orbitz Android team, I slowed down development somewhat, but have continued to grow the active user base to more than 4,650 active users today.

Total Active Installs
Active Installs Over Time

In the last year or so, the tools surrounding Android have gotten significantly better (although too many still start with “Robo”). Here’s a sample of what I use:

Roboguice
Dependency injection (@InjectView is awesome)
Robolectric
Android Unit Tests. Used for testing simple interactions and verifying that sample data yields the correct predictions
Flurry
Flurry provides a free tier of event tracking in exchange for collecting aggregate data about your app’s usage
Jackson
Easily parse XML/JSON
Bugsense
This easy-to-integrate tool allows the app to automatically post stack traces to the Bugsense website if the app crashes.
Github
Git. Use it. Or some kind of version control.

These tools are generally pretty well documented. StackOverflow is of course a great resource if you get stuck. Let me know if you have specific questions about integrating these tools.

One of the most exciting trends in the analytics has been the growth of Android 4.0+ devices to almost 30% of the active installs of the app.

2.3.x vs 4.0 adoption
4.0 has driven lots of downloads in recent months

In the 2.0 version, I plan to update the visual style of the app to be more consistent with the Ice Cream Sandwich design style. I also want to expand into more push notifications and increased analytics about app usage.

Special thanks to Rob, Jonathan and Hari for being my beta testers.

“CTA Train Tracker (SM)” , “CTA Bus Tracker (SM)”, and their associated logos are trademarks of the Chicago Transit Authority.

The opinions above are solely my own and do not reflect those of Orbitz Worldwide or its affliates.

OnRoute to California

A few weeks ago, I had the opportunity to travel to the Where 2.0 conference in Santa Clara CA as part of the OnStar Student Developer Challenge.

The Challenge was created for college students at Michigan, MIT, Carnegie Mellon, U Toledo and U Texas to create voice-controlled applications that run on the OnStar in-vehicle platform. We were given access to the QuickFuse voice development environment to work with and test.

I decided to develop an application similar to Glympse, the live location sharing application for mobile phones. The application was designed to allow drivers to seamlessly share the location of their vehicle with friends and family in real time via a website and Android phone application.

I branded this service as OnRoute, playing off the OnStar name and the phrase “en route”. After learning html, php and Javascript, I was able to put together a simple service that allowed the driver to speak the phone number of their friend or family member to start sharing their location. The other person could then use that phone number to create an account and view the car location.

The “about” page for OnRoute is still online.

I was selected as one of six semi-finalist teams selected from the original group of entries from Michigan, MIT, Carnegie Mellon, U Toledo and U Texas.

Of the six semi-finalist teams, three were from Michigan and the other three were from MIT. I was the only one-man team selected as a semi-finalist.

After going to the conference Tuesday evening and Wednesday morning, we presented our applications to the judges: Robert Scoble (scobelizer.com), Daniel Jacobson (Netflix API), Matthew Ervin (The Plum Group(Voice Apps)), and Jeff Liedel (OnStar VP). The presentations went well, but clearly the best presentation of the day was from an MIT group with an application called “EatOn”, which allowed drivers to find nearby restaurants. “EatOn” ended up winning the $10,000 Grand Prize, which they definitely earned.

Despite not winning, I was very happy to be selected as a semi-finalist. The talks I was able to attend were very interesting and useful. Highlights of talks include:

The presentations on NFC and QR codes were particularly interesting because I’ve been working on Android applications that utilize both these technologies.

All in all, the trip to the Where 2.0 conference was great. I met some very interesting people and heard some interesting talks. I thank OnStar for selecting me as a semi-finalist.