Showing posts with label development. Show all posts
Showing posts with label development. Show all posts

Monday, December 3, 2012

Android: "Application level" Pause and Resume

Update

I have created an open source library using the concepts presented in this post. You can directly use the library to create your apps. Get it at android-app-pause on github

Introduction

I have often come across questions on StackOverflow and the android-developers google group about an Application-level onPause() and onResume(). In this post, I present one of the ways of achieving such functionality. But before that, what exactly do I mean by an app-level onPause()?

After all, an Android app consists of multiple components, several of which might be in the background. There could be Services, Threads, BroadcastReceivers, scheduled Alarms. How do these figure in a "paused" app? Well, here's my definition of an app being paused for the purposes of this post:

An app is considered to be paused when the app is no longer visible to the user. By definition, this means that when an app is paused, none of the Activities that belong to the app are visible to the user.

In my opinion, this is a fair definition since this would typically be the point when the app wishes to "pause" any background work it does. For example, an app might wish to cancel all scheduled alarms, or stop making HTTP calls when it knows that the user is no longer interacting with the app.

Similarly, an app is considered to be resumed when at least one Activity from the app is visible to the user.

This is the point at which the app can re-establish HTTP communication, re-schedule alarms and the like.

TL;DR

I got this idea from this answer that I gave on stackoverflow. The basis of this approach is that when an Activity starts another, both of them undergo lifecycle changes in a predictable fashion. The series of steps to follow to achieve the app-level pause and resume functionality is as follows:

  1. Create a bound Service (let's call this AppActiveService).
  2. In the onStart() of every Activity of your app, bind to AppActiveService.
  3. In the onStop() of every Activity of your app, unbind from AppActiveService.
  4. The onDestroy() method of AppActiveService represents the point when your app is "pausing"; while the onBind() method represents the point when your app is "resuming". Put the code you want to be run when your app "goes to the background" in AppActiveService's onDestroy() method.

To make things even simpler, you can put all the code above in a BaseActivity for your application and have all your other Activities inherit from this BaseActivity.

If you follow the steps above, the AppActiveService will have at least one Activity bound to it as long as your app is visible to the user. When this condition is false, no Activity is bound to the Service, at which point its onDestroy() is called.

Do note that we are using onStop() and not onPause() to un-bind from the Service. If you were to use onPause(), then there would be zero components bound to AppActiveService even as you are switching from one Activity to the other within your own app.

Gotchas

One gotcha in this approach is: What happens if your app "starts another app" using an Intent? No Activity from your app will be visible to the user - thus triggering an app-pause. Whether this is acceptable or not depends on your use case.

Conclusion

I plan to publish the code for this procedure as a library or at least as a gist on GitHub. Before that, I'm looking for feedback on how the code can be improved and made more robust. Have you come across the need to know when your app as a whole is "going away"? How have you solved the problem?

Saturday, September 29, 2012

Google Play Services, and Why We Still Need AccountManager

Introduction

Recently, Google has started rolling out the widely awaited Google Play Services, announced during Google I/O 2012. One of the major pieces of Google Play Services is the GoogleAuthUtil. The principal problem that this component solves is OAuth. Up until now, writing an Android app that requires OAuth has been complex and non-standard.

  • Complex, because you need perform the whole OAuth dance behind the scenes (not specific to Android, mind you).
  • Non-standard because the app developers ended up displaying their own custom screens for choosing the account to be used for OAuth. Also, the OAuth scopes are specific to the identity provider; and this led to displaying the raw oauth scope strings in some OAuth confirmation screens rather than a user-friendly description of the scope.

The AccountManager framework did some of the heavy lifting and attempted to address both the problems. However, it met with limited success on both counts. Which is why, when the GoogleAuthUtil, and the AccountPicker were previewed at IO2012, I was jumping in excitement. If you want your app to use OAuth with Google, then GoogleAuthUtil makes life a whole lot simpler.

Caveat

But, therein lies the caveat. It only applies to Google Accounts. One could argue that any Android device that has Google Play Services also has at least one Google account - so this is not a big deal. However, remember that many Android apps are actually just one of the ways of accessing a (possibly OAuth-protected) web service. The web service itself might offer several identity providers for the user to sign up, log in or authorize. Restricting that to just the Google account on the Android version of the app doesn't make sense.

What is really required is for more identity providers to leverage the AccountManager framework in Android. Admittedly, that is not so straightforward. Not only does it involve writing an AccountAuthenticator, there are some pieces specific to identity provider and there is no go-to place to publish the documentation for these provider-specific pieces.

Suppose I wanted to write an app that allows users to sign in with their Google, Facebook or Twitter accounts. Google is easy (it has been easy even before Play Services!). But what about the rest? How do I know what the accountType for Twitter is? How do I know the valid values for features parameter for Twitter?

But the problem doesn't stop there. Apparently, some third-party services require you to use their OAuth API to sign the user in. This is stated explicitly, as part of the terms of services. I noticed this when I was trying out a third party twitter client. I already had Twitter's official client installed, and hence my twitter account was available in the "Accounts" settings. Still, I had to enter my twitter credentials in a WebView. The third-party twitter client did not use AccountManager to log me in. I wrote to the developer about it and I was informed that Twitter required this as part of their terms of service.

Solution (?)

I really think third party identity providers (at least the big ones) should make an effort to leverage AccountManager framework of Android. This may be additional work - but just look at the size of the customer base they are targetting. With the new AccountPicker, the end user experience for using OAuth with Google is a breeze. It makes the traditional "log in using a web page" seem like a stone-age UX. The driving principle should be:

An end user should never be forced to enter the credentials for an account that is already present in the "Accounts" settings screen

Furthermore, it may project Google in a bad light since it may give the impression that Google is trying to make the UX good for its own services while leaving others in the lurch - which is not true.

Conclusion

In a nutshell:

  • Google Play Services (in particular AccountPicker) = Good - for Google Accounts.
  • Third party identity providers and OAuth providers: WebView = Bad. Please use AccountManager and AbstractAccountAuthenticator.

Thursday, July 26, 2012

That's NOT Fragmentation; But then What Is?


Of late, much has been said and debated regarding the fragmentation "problem" in Android. People who know me know that I'm a BIG fan of Android - as a user and as a developer. However, I do admit that Android is fragmented. That, in itself is not such a bad thing. But, this fragmentation is making my life as a developer that much more difficult. That's the bad thing.

Having said that, I get to read and here things like this a lot. These all belong to a category I like to call "What Fragmentation is NOT".

Oh! There's 4-inch phones, 7-inch tabs and 10-inch tabs? Damn! Fragmentation!

OR

Urghh! So many different device manufacturers? So many thousands of device models? They won't all have the same hardware and capabilities :-( Damn! Fragmentation!

Try This

What? Every release of Android has its own theme and look&feel? Damn! Fragmentation!

All of this makes me go "Oh No! Not again!" I wonder how developers don't realize that these factors are not limitations - they are an opportunity: to get your app to audiences you wouldn't have thought possible. Android platform has armed developers with great tools to address these factors.

  • The amazing resources framework allows you to adapt to a wide variety of configurations with little or no code. You can optimize your app for phone, tablet, portrait, layout, night mode, keyboard mode, dock mode, different languages and what not by simply providing alternate resources.
  • Then, there's the theme inheritance with which you can customize the look and feel of your app without looking out of place on the particular platform version.
  • If your app requires a particular capability to work; or if it cannot function in certain configurations, you can use manifest filtering to prevent it from being available to devices that don't match your criteria.

All the above rants, can then be attributed to developers not knowing the framework and the tools properly. These have nothing to do with fragmentation.


There are some problems, though, that have the potential of requiring developers to spend considerably more effort if they want their apps to target a large percentage of Android devices in the wild. A sampling of such problems follows.

RTSP Streaming:

Getting a simple RTSP video stream to play on even the more popular devices using Android's MediaPlayer framework is an uphill task (I've tried and basically given up). As per the specs it should "just work", but implementations haven't adhered strictly to the specs.

Now, That's fragmentation.

Rapid Deprecations:

UI and design patterns that were previously suggested by the Android team have suddenly fallen out of favor and are now deprecated, only to be replaced with new patterns (yes, Android Design Guide, I'm looking at you). Examples include ActionBar, and the AsyncTask punishment.

The fact that device manufacturers haven't exactly kept up with the pace of Android platform version releases doesn't help. For example, as of July 2, 2012, the percentage of devices that support ActionBar functionality natively is just 13%.

The Android team, and the community have tried to bridge the gap by coming up with libraries that allow you to use the new features on the old versions (via Android Compatibility Library, ActionBar Sherlock etc), but these don't completely solve the problem. There are still gaps, and if you want to develop an app that both follows the new patterns and is truly well-behaved on even 75% of the installed base, you have to roll your sleeves and get your hands dirty.

Now, That's fragmentation.

Very Basic Changes in the Framework:

Since HoneyComb (Android 3.0), the dedicated hardware "Menu" key has been dumped in Android, to be replaced with an overflow menu in the ActionBar. This seems like a simple problem, until you come across problems like this one.

You can't even be confident that your erstwhile awesome app will display that menu properly across all devices.

Now, That's fragmentation.

The way you are supposed to use the Back Button has been changed and made all the more confusing to both developers and end users. There was even a talk at the recent Google IO conference in which half an hour was spent explaining the reasoning behind the back button.

To balance the way the back button is supposed to work in various versions of the platform, with the way you want it to work might take quite a lot of effort (especially since the compatibility API's don't really do the job here).

Now, That's fragmentation.

Patent-induced inconsistencies:

We've all got used to the "Chooser" displayed by Android whenever you click on, say, a link in an e-mail. This chooser allows you to select the app that you would use to display the link (probably a list of browsers installed on your device).

Pretty basic stuff, right? Well, this may no longer be the case. As a result of a patent issues, at least one manufacturer has modified this behavior. This is bad news for app developers that depend on this feature for their app to be even discovered. Work-arounds exist but are very very round-about. Also, what if another manufacturer follows some other approach to get past the patent problem?

Now, That's fragmentation.


There are other issues I can point out, but I guess I've made my point (at least to all two of you who've made it this far). Luckily, most of these problems are likely to be contained in the near future. This makes sense if you look at the fact that Android is still a maturing platform. The team behind it is bound to realize how some of the earlier decisions were wrong and it is good for the platform and ecosystem if they take steps to correct the mistakes. For example:

  • The AsyncTask, ActionBar and Menu key problems I mentioned will probably not be a problem once we have more devices running ICS and above.
  • The Back Button and other issues surrounding navigation guidelines are also likely to be eliminated once we have more developers developing apps that follow the new guidelines consistently. I also don't expect Google to make any more drastic changes in these areas in the near future.
  • Even the MediaPlayer framework inconsistencies are bound to shrink with more adoption of the newer platform releases.
  • At Google IO 2012, Google announced the PDK (Platform Developers' Kit) aimed at shortening the gap between the announcement of a new platform release; and device manufacturers rolling out phones or updates with the new release. Believe me - this is GOOD!

That leaves the issues related to patent and other legal stuff. There's not much Google or any device manufacturer can do in that space, when evil and jealous competitors are deciding to abandon innovation and instead pick up cheap means to combat competition, is there?


Conclusion:

Yes, Android is fragmented. Today, the effort it takes to make your app play well on various versions, and implement all the new guidelines is disproportionate to the gains (that's purely my own opinion). But this won't last.

Once this pie-chart shows a growth in ICS and newer devices, lot of our problems as developers will be minimized. As for fragmentation caused by reasons outside Google's control - well we'll just have to live with it.