Preparing your Android apps for freeform
After diving into the new Android announcements from the past few months, we quickly became convinced: fully resizeable Android apps are coming, and they’ll be here sooner than you think. So what do you need to do to make your apps freeform-proof?
Fully freeform, resizeable app windows have long been the domain of desktop OS’s only, but mobile devices have recently been playing catch-up. But why are we so sure complete resizability is coming to Android – and soon?
Let’s recap: some recent Android history
Back in March, Google presented the first preview of Android 7 Nougat. One of its new features: multi-window support. Apps in Nougat can be resized to 33%, 50% or 66% of its width/height, depending on the device’s orientation, both on tablets and phones.
In fact, multi-window support was already present in Android Marshmallow. You could activate it by tinkering with your device’s system flags and developer options, but it wasn’t advertised or documented anywhere.
After the launch of Nougat, attentive readers of the official developer documentation found a mention of a new system feature flag, enabling fully resizable apps. Note that I used the word “mention”: it’s limited to a small sidenote.
“Manufacturers of larger devices can choose to enable freeform mode, in which the user can freely resize each activity. If the manufacturer enables this feature, the device offers freeform mode in addition to split-screen mode.”“
Today, there are no existing devices that have already enabled this feature. As a developer you can modify your emulator image, but that’s not something an end-user will do. However, there is already an app called Taskbar, which can teach us a few things. The app brings you a “start menu”-like experience, like on a Windows computer. And, you guessed it, it also lets you open apps in freeform mode. It does require enabling a developer option, but it does not require a rooted device. This means every user running Nougat can make use of this feature, without tinkering with the internal configuration of the operating system.
And it doesn’t end there: at Google I/O, Google announced that the Play Store was coming to ChromeOS. Unlike previous “experiments”, where Android apps were repackaged using ARC (App Runtime for Chrome), we can now run apps just like on Android. On a desktop OS you might expect fully resizable apps, but this isn’t the case. Apps can run in 3 different sizes: portrait, landscape, and maximised.
Taking all this into account, we’re quite convinced that Google is preparing to introduce fully resizeable apps on both Android and ChromeOS sooner rather than later. And the good news is: we can already start developing and testing those apps! Read on, and we’ll walk you through the most important elements of implementation…
Creating apps for split screen
A first thing to take a closer look at is the app’s behaviour in split screen. When our app goes into split-screen mode, our activity will be recreated, meaning we’ll see
onCreate being called again. This also happens when we resize our app to 33%, 50% or 66%.
That makes perfect sense, since the configuration of our app has changed. It’s comparable to what happens when you rotate your device from portrait to landscape: the screen size is changed and your activity is recreated.
Make sure to save your state when
onSaveInstanceState is called, so you can restore it after when your activity is recreated. Just like on a rotation change, you can decide to handle this yourself by adding a
onConfigurationChange attribute in your activities tag inside the
<activity android:name=".MainActivity" android:configChanges="screenSize|orientation|smallestScreenSize|screenLayout" />
In this case your activity won’t be recreated, but you’ll receive a call to
But what happens while the user is still resizing your app, and the handle didn’t yet snap to one of the predefined percentages? Don’t worry, the operating system handles this without calling your app for help. If your app is being made larger, the background color will be used to fill the newly created space. If it’s getting smaller, the OS will clip your app. The moment the user releases the handle and the window snaps to one of the predefined sizes, your activity’s configuration will change.
In other words, there’s not a lot that we have to change to let an app work nicely in split-screen.
onPause or onStop?
However, there is one thing that’s worth mentioning. Say a user taps on the home button or on a notification and leaves your app. You’d probably use this opportunity to perform some clean-up, like pausing video playback for example.
Most of the times, we (and I’m sure we’re not the only ones) would implement this logic in the
onPause method. Why? Because most code examples use
onPause, and both are called when your app becomes invisible – meaning that in most scenarios, it doesn’t make much of a difference.
However, that behaviour changes once your user enters split-screen. If he has two apps visible, only one of them will be in an active state while the other one will be paused. Entering and leaving this paused state will trigger the well-known
But – and it’s an important but – this means that your app will stay visible after a call to
onPause. To return to our example of video playback, this means that your user wouldn’t be able to watch a video while chatting on WhatsApp.
To avoid such situations, we moved this logic to
onStop, and recommend that you do, too.
The intricacies of freeform mode
Now let’s continue with the behaviour of an app while in freeform mode. To test your app, you can install TaskBar on your Android 7+ device or follow the steps described in this article.
Note that some of the details I’ll describe below about freeform mode is what we can currently observe on Android 7.1. There isn’t much official documentation on the topic, so once the feature becomes more official, there could be changes.
The first thing I should mention is that your app will probably work in freeform mode – at least if you created your app to work responsively on different screen sizes. And if you already provide support for split-screen view, you’re almost entirely good to go already – the behaviour when your app loses focus is identical to what we described above.
But of course, a few things are different.
One example is resizing your app: once the user starts dragging the window, you do get a call to
onConfigurationChanged this time.
For every single pixel the window gets resized, this method will be called. Ever had the idea of doing some heavy work in
onConfigurationChanged? Change your mind as soon as possible, because that’s not going to turn out well.
Now let’s say you have an app where you have a regular layout, and a different layout with the sw600dp qualifier. If your window is smaller than 600dp and you enlarge the window, your configuration will change once you cross 600dp. This means, just like when using split-screen, your activity will be recreated unless you’re using the
onConfigurationChanged trick. Nothing unexpected, right?
However, if you have a different activity where you don’t provide a different layout file, your activity will still get recreated if you cross this border. Once you create a new resource bucket, your activity will always recreate, even if you don’t use it. The issue with this is that your configuration now changes a lot more often than you’d think.
To me, that doesn’t really make sense, but I’m willing to assume there’s a good reason for it.
Let’s say your window resizes from 500x550 to 600x550. Your orientation will go from portrait to landscape, and your configuration will change. But if you’re using AppCompat (which you probably are) you will notice a lot more configuration changes. AppCompat adds alternative resources for large, xlarge, h720dp, sw600dp and landscape. This means that even an empty application already has several resource buckets that will affect your app when resizing in freeform mode.
The key point: with freeform mode in mind, keeping your your activity creation as lightweight as possible becomes more important than ever.
What to do with window sizes?
By now we know how our app will behave on freeform mode when we resize it, and how we can influence it.
But how do we influence the window size of our app when it launches?
Well, that’s actually pretty easy to do. In your AndroidManifest.xml file, inside the
activity tag, you can put a new
<activity android:name=".MainActivity"> <layout android:defaultHeight="500dp" android:defaultWidth="600dp" android:gravity="top|right" android:minHeight="450dp" android:minWidth="200dp" /> </activity>
What does this mean for your app? Well it’s actually quite self-explanatory. Your app will open in a 600x500 window at the top right of your screen. If you resize the window, you can’t make it smaller than 200x450. Yup, it’s that simple!
Now go forth and make flexible apps!
Let’s recap: as you can see, it’s actually not that much work to support both splitscreen and freeform resizing of your app. There’s only a number of ground rules to remember. So be prepared for a lot of recreations of your activity, make sure you stop video playback in
onStop instead of
onPause and know the consequences of creating new resource buckets…
Team Android is hiring! If you think this sounds cool, you haven’t seen anything yet… If you’d like to work with us, click here & check out our job openings!