Developing like a pro — portrait only apps

Likes to Android with the aim of making that million dollar app one day; retiring to a beach of his choice. For now writes blog posts to hopefully enlighten others & gain some feeling of self worth.

When writing an Android application there comes a time when the client / business utters those dreaded words. "Let's support only portrait for phone and landscape for tablets" they might add ... "just for now". After all the debates and your passion to prove this is the wrong decision sometimes it just has to be done. This blog post will discuss the hidden pitfalls of this decision including unexpected crashes and explain how you can work around these to make a solid, well functioning app that you can change to supporting both orientations in an instant.

I admit I am not the UI guy, I fail at making things shiny and at tweaking the UI views to get it just right. I much prefer the 'back end' of the application the code that makes it run with shiny caches and performant loading. Therefore this post is not going to be hovering around resource buckets, or layouts. So when I say supporting both orientations in an instant. I mean from this perspective and yes you would likely have to do further work to improve your alternative orientation view design - not todays problem.

What is a configuration change

device configurations can change during runtime (such as screen orientation, keyboard availability, and language). When such a change occurs, Android restarts the running Activity (onDestroy() is called, followed by onCreate()). 1

Device configuration changes are bad news for your activity it is killed and a fresh one created in its place. However this new activity knows nothing about your data in the last activity unless you implement onSaveInstanceState and restore this state when the new activity is created. When you lock an app to landscape or portrait not noticing these device configuration changes will have a big impact on your app users and therefore your app store ratings. Put another way; when an app is locked to portrait onSaveInstanceState will not be implemented as the developer has never seen a config change and so they have not seen the bugs they have to fix.

Your activity rotating - even if this is by accident as you lean your hand to the side is the most obvious tool you have to highlight glitches or app crashes in your code from config changes.

An activity rotating is a change of device configuration. There are other instances of a configuration change that you aren't too likely to bump into whilst developing but WILL happen when in the wild i.e. when you release your app. For instance somebody plugging in a keyboard or secondary screen, changing the global font scale, putting the device in a car dock or changing the device language. These are rare events as you develop but as your user base grows they become more prevalent. If you have activity rotation disabled you aren't going to be noticing configuration change bugs unless you actively test for them.

So what can we do to deal with this, the client wants a portrait only app, we want to not glitch/crash on configuration change. Lets talk about some tools and techniques to bridge the divide here.

orientation only locked by 180°

Allow your users to be free! Just because the business only wants to support tablet landscape orientation doesn't mean you can't support orientation changes. Introducing sensorLandscape.

sensorLandscape - Landscape orientation, but can be either normal or reverse landscape based on the device sensor. Added in API level 9. 2

There are both sensorPortrait and sensorLandscape. This means you will get configuration changes you just have to spin your device around a full 180 degrees. This benefits the user as well if they have some crazy display or pass there tablet to a friend upside down. Unfortunately on phones the 180° portrait view is disabled by default (enabled by default on tablets) so most phones won't support this, but some will so no harm having it on! This can be seen here, here and here in the AOSP source code.

As an example of changing your AndroidManifest.xml:

<activity  
      android:name="com.novoda.MyActivity"
      android:screenOrientation="sensorLandscape" />

Side note: there is a funny old bug (typo) that has now been fixed where you had to use sensorPortait (missing the R) depending on the Android version you targeted.3

orientation not locked whilst developing

Don't lock the application orientation unneccesarily. What about only locking it as part of the release process? Development builds are only seen by the team, developers, testers. Therefore the business rule of orientation portrait only applies when the customer sees the app.

Keeping it unlocked whilst you develop allows you to test orientation change and find those pesky rotation bugs.

Another advantage here is the business / clients can see the application in both orientations, back at the start of this post when we talked about the debate for not locking. Sometimes seeing is believing, watch as a stakeholder naturally holds the phone in landscape to interact with a certain view and then whisper to them that users won't be able to do that ;-) the power of example.

Two ways you can enable this:

Using flavors you can replace parts of your AndroidManifest.xml file. You can 4. You could also keep a single manifest and just change the screenOrientation value using an integer in the corresponding flavor resources. Below is a brief example of the former.

/src/devFlavor/AndroidManifest.xml

<activity  
      android:name="com.novoda.MyActivity"
      android:screenOrientation="unspecified" />

Then override it on release

/src/releaseFlavor/AndroidManifest.xml

<activity  
      android:name="com.novoda.MyActivity"
      android:screenOrientation="portrait" />

You can also do it programmatically in your Activity using the debug flag.5.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      if(BuildConfig.DEBUG) {
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
      } else {
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
      }
      super.onCreate(savedInstanceState);
    }

developing with 'don't keep activities'

I was trying to find the official documentation for this developer option but I don't think any exists. Other docs state you can use this option to simulate low memory pressure on your Activity (which is true). Here I show how it can also simulate a config change (from our perspective). To toggle on this option go to.

Settings > Developer Options > Don't keep activities

What this will do is when navigating through your app and back to an Activity you have previously seen. It will force this activity to be recreated. Therefore you can think of this like a configuration change when this option is turned on on your device.

Once an activity is no longer in the foreground and visible to you, it will have its onSaveInstanceState called. When you navigate again to this activity (most likely with the back button, or calling finish() on the current activity). The original will be recreated and be passed the Bundle that was saved.

Put another way, if your activity has onStop called on it, with this option toggled on it will also have onSavedInstanceState and onDestroy called. When navigating back onCreate will be called with the restore bundle.

You can use Don't keep activities to develop in an environment where you have to consider saved state more often. Especially for the QA out there this is gold mine for finding bugs that the developer has no clue how to reproduce until you explain you have this option turned on.

Use it to encounter scenarios you would not usually see whilst developing as discussed, but remember the users in the wild WILL see these cases! This is why it is imperative they are coded for, giving your app a seamless experience.

Conclusion

Configuration changes are a great tool to find bugs in your application. Having your application locked to one orientation does not mean you don't have to cater for these bugs, it just means they are more hidden and harder to reproduce. Therefore there are two take away points

Doing this will give you a sturdy, hardened application that will fare well in the wild. You will get less strange and erroneous crash reports and you have some sure ways to attempt to reproduce these bugs if you see them.

Further, your application is ready to be enabled for both orientations. Just you know drop in some designs, add a resource bucket, ship it!

About Novoda

We plan, design, and develop the world’s most desirable Android products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.

Let’s get in contact