Blue O

Inside Android O: A developer's preview of the next big OS update

Google recently unveiled the newest major version of the Android operating system—Android O. I don’t know what "O" is going to stand for (Oreo? Oatmeal cream pie?), but what I do know is that this update brings lots of new features, improvements, and API changes to developers.

If you are as excited as me and can’t wait to learn about all the new stuff that Android O brings to the table, then you are in the right place. I've spent a week digging into the developer preview, and now I'm going reveal all the important features and changes in Android O that I found and explain how your app might benefit from them. 

Stay up with the Android developer crowd

Picture-in-picture mode

If you remember, Google introduced the picture-in-picture mode for Android TV users back in Android Nougat. This feature allowed users to pin a video in one corner of the screen while navigating between different apps, much like the YouTube mobile app. This significantly improves the multitasking experience of users, allowing them to keep an eye on one video as they browse for more. 

Previously, developers were quite reluctant to implement this feature because it was only available on Android TV and the Android TV marketplace is tiny in comparison to the phone and tablet marketplaces.

 

Figure: Example wireframe showing where the blue video sits in the lower right corner.

But now is the perfect time to start exploring this feature in more detail with its introduction to all Android devices in Android O. If you have an app with video playback, image slideshows, or anything similar, try it out.

Implementing this feature is pretty straightforward. You need to declare an attribute, android:supportsPictureInPicture, to be true in your AndroidManifest, which allows a particular Activity to enable PIP for it. Before Android O, you also needed to set the android:resizableActivity to true, but now that is not mandatory.

<activity android:VideoPlaybackActivity"
android:supportsPictureInPicture="true" ...>

Now your Activity knows that it needs to support the PIP mode, but that’s not enough. You need to manually call enterPictureInPictureMode() when you want your users to enter the mode. You can also customize the way the PIP frame looks and works (for example, you can modify the aspect ratio, actions, etc.) by passing the PictureInPictureArgs to the enterPictureInPictureMode() method.

There are a few gotchas, though. In PIP mode, you need to remove several UI elements from your Activity, since the PIP window is quite tiny (240x135dp). You also need to seamlessly restore those hidden UI elements when the user exits the PIP mode to give a consistent user experience. To get this working, you can use the handy onPictureInPictureModeChanged(boolean) callback.

@Override
public void onPictureInPictureModeChanged(boolean isInPIPMode) {
if (isInPIPMode) {
// Hide the controls in picture-in-picture mode ...
} else {
// Restore the UI elements again ...
}
}

Another important thing that you shouldn’t miss is that when your Activity enters the PIP mode, the onPause() lifecycle method is called and your Activity is actually in the “paused” state. We generally tend to pause any media playback in onPause(), but it defeats the whole purpose of the PIP mode, doesn't it?

So from now on, instead of pausing any media playback in onPause(), you should do it in onStop(). If your application logic still forces you to pause the playback in onPause(), there are better ways to do that without messing up the PIP mode.

@Override
public void onPause() {
// Do not pause playback in PIP mode
if (isInPictureInPictureMode()) {
...
} else {
// It is safe to pause the playback ...
}
}

If you want to see a working sample of the picture-in-picture mode, here is a Github repo you should definitely check out.

New notification channels

Google started changing the notification system as far back as Lollipop, and it isn't done yet. With every Android release, new features and enhancements are brought to the notification system to make things easier for users.

Figure: A preview of what notification channels will look like in Android O

Android O introduces notification channels, which let users manage their notifications in a more convenient and efficient way. The control is now moved from individual notifications to a group or channel of notifications.

This feature is really great from a developer's point of view as well. Previously, users could completely block your app from showing any notification if they got annoyed with your frequent promotional notifications. But now if they get annoyed with your app’s promotional notifications, they can block that particular channel, leaving all other notification channels from your app untouched.

Your app can create as many notification channels as necessary using the straightforward createNotificationChannel() method.

You can also customize this notification channel in any way you want. Here is a quick example of how you get started.

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

// The identifier of the channel
String id = ...;
// The user visible name of the channel
CharSequence name = ...;
int importance = NotificationManager.IMPORTANCE_HIGH;

NotificationChannel channel = new NotificationChannel(id, name, importance);

// Configure the notification channel
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.enableVibration(true);

notificationManager.createNotificationChannel(channel);

Major change: In Android O onwards, if you want to send a notification, you must set a channel for that notification using the channel identifier. 

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

// Sets an id for the notification, so it can be updated.
int notiId = 1;
// The id of the channel it should belong to
String CHANNEL_ID = ...;

// Create a notification and set the notification channel
Notification notification = new Notification.Builder(this)
.setContentTitle("Message")
.setContentText("Content")
.setSmallIcon(R.drawable.ic_noti)
.setChannel(CHANNEL_ID)
.build();

// Send the notification
notificationManager.notify(notiId, notification);

Now, all the notifications you send from your app get properly categorized into their appropriate channels. Users can customize the behavior of any channel (lights, sounds, vibration, etc.) or block a particular channel completely if they really want to.

Apps don’t have the permission to programmatically change the settings of a notification channel or override the choices made by the user, but you can always read the settings of any channel using the getNotificationChannel() API.

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

// Get access to a particular notification
NotificationChannel notificationChannel = notificationManager.getNotificationChannel(“CHANNEL_ID”);

// Or the list of all notification channels your app has created
List<NotificationChannel> notificationChannels = notificationManager.getNotificationChannels();

Managing notifications (for both users and developers) will be much better with the introduction of this feature. If you want your app to target Android O, then make sure you implement these changes so that notification functions are up to date.

AutoFill framework

If you have ever used password management apps such as LastPass, DashLane, or 1Password, then you have seen autofill in action. The problem is that this autofill mechanism needs to be built by all apps individually and it's not a trivial task.

Android O's new autofill framework makes it much easier for developers to add this functionality, allowing apps to autofill usernames, passwords, emails, credit card details, or any other form-related data with ease. This will be a big timesaver for the developers of form-heavy apps.

To start using this feature, your app needs to have an autofill service that can parse the client Activity’s View hierarchy, find the autofillable views, and fill those views using whatever framework has appropriate data for it. 

If you are targeting Android O and you want your app’s views to be detected and autofilled by the Autofill Framework, then you might need to do some extra work. If you are using Android’s standard Views and ViewGroups, then you don’t need to do anything extra to get the autofill feature to work automatically for your app.

However, if you wrote a fancy custom view, then you need to expose some metadata that the Autofill Framework requires to work its magic. Whenever your custom view is autofilled, an autofill event is triggered. This is when your custom view should know how to handle this autofilled data by appropriately overriding the autoFill(AutoFillValue).

Your custom view should also override getAutoFillType() and getAutoFillValue() to tell the framework what type of view it actually is and what its current autofillable value is.

Here is a complete working sample for you to get started with the new AutoFill framework.

Battery life improvements

We know how serious Google is when it comes to the battery life of Android devices. The Doze Mode introduced in Marshmallow brought a significant improvement in the battery life of Android devices. This was enhanced and fine-tuned further in the Extended Doze Mode introduced in Android Nougat.

Android O will be bringing even more battery improvements by tapping into how various apps consume battery while they are in the background. Now, apps running in the background will have limited access to what they can do mainly in three areas—background services, implicit broadcasts, and location updates, which are by far the most notorious culprits in draining battery. Well played, Google!

Background services

There are new limitations imposed on background services, allowing them to run for only a few minutes if your app is not in the foreground. After that window of time, they are essentially stopped, preventing any further battery abuse. An obvious solution to avoid this limitation would be to use the JobScheduler as much as possible. The JobScheduler is very smart when it comes to scheduling jobs and batching them intelligently so that devices can enjoy a sound sleep for a longer period of time. Here is an excellent article that can help you make the necessary changes for Android O regarding background limitations.

Implicit broadcasts

We already knew that there were some restrictions placed on Broadcast Receivers in Android Nougat, but Android O makes them even more strict. Now you cannot register implicit broadcasts in your app’s manifest (except for a few). You have to do that programmatically while your app is running using the registerReceiver() method. All explicit broadcasts are fine though.

This is a very judicious decision because there are lots of unnecessary broadcasts sent to apps that don’t even need to listen to them at the current moment, thereby wasting a lot of battery juice.

Location update

There are also some restrictions imposed on how apps fetch location updates while in the background. If your app is in the background, then it cannot retrieve location updates more than a few times per hour (the exact number will be decided before the final release). And this restriction is applicable to all apps irrespective of their target SDKs. This sounds a bit scary for some apps, for sure.

If you need to receive faster location updates, consider moving your app to the foreground, or use a foreground service or the GeoFencingApi, which is well optimized for low battery consumption.

Adaptive icons

As the name "adaptive icons" suggests, Google is trying to create icons for apps that can have different shapes for different devices and OEMs. For example, your app can have a square icon on a Samsung Galaxy S7 and a rounded icon on a Nexus 5X.

The idea here is that each device would provide a mask that can be used by the operating system to render icons of different shapes. This will allow OEMs to easily have unique-looking home screens, and according to a standard. I think this is the first baby step from Google toward a native theme engine, which was always present on custom ROMs such as CynogenMod.

These adaptive app icons can be used in the app shortcuts, inside the Settings app, in the sharing dialogs, or the home screen. The adaptive icons can also support various visual effects (like zoom, bounce, etc.) when the user interacts with them.

Implementing adaptive icons in your app is pretty simple. All you need to do is create a maskable icon and specify two layers in it, the foreground and background layer.

<maskable-icon>
<background android:drawable="@color/ic_background"/>
<foreground android:drawable="@mipmap/ic_foreground"/>
</maskable-icon>

This initial step toward an icon language is a very impressive and welcome move by Google.

A bit more on Android O

I have already discussed some of the major features and changes introduced in Android O, but those aren't all there is. There are several small but interesting and important changes introduced in Android O that I'll share next.

Native support for fonts as resources

Until now, you needed to use third-party libraries (such as Calligraphy) if you wanted to have custom fonts in your app. But with Android O, you will have native support for fonts as resources in your app. Thank you, Google, for finally doing this! It could have been much earlier, but better late than never.

And there is also talk about bringing it to the support library as well. Don’t throw away Calligraphy from your project until then.

Autosizing TextViews

Another notable introduction is Autosizing TextViews. This can come in handy when you have dynamic content on the screen and you want your text to expand or contract depending on the screen space available on the device. You probably have been using this “autosizing” feature through third-party libraries before, but now it’s built into Android itself.

New options for image color spaces

If you have an image gallery application where you need to show images of various color spaces accurately, then there is good news for you. In Android O, image color space will not be limited to sRGB. Applications will be able to display Adobe RGB, ProPhoto RGB, and other color spaces properly. You can also switch between different color spaces easily.  Here's how it's done:

// Convert from sRGB to AdobeRGB
ColorSpace.Connector connector = ColorSpace.connect(
ColorSpace.get(ColorSpace.Named.SRGB),
ColorSpace.get(ColorSpace.Named.ADOBE_RGB));

float[] adobeRGB = connector.transform(r, g, b);

New accessability services

If you have been using Accessibility Services in your app, then there are quite a lot of additions in Android O that you might want to look at. These include a dedicated accessibility button in the navigation bar, fingerprint gestures, word highlighting, and much more.

Seek and reverse animations

The AnimatorSet also brought a very cool change allowing you to seek and reverse animations. This will allow you to get a bit more creative with animations.

Programmatically answer phone calls

Last but not the least, Google has introduced a new permission, android.permission.ANSWER_PHONE_CALLS, which allows apps to programmatically answer incoming phone calls. Now just imagine the different utility apps you can build using this cool feature.

APIs are not final, but check it out yourself!

Android O certainly brings quite a lot of new features and improvements for developers to play with. These APIs are obviously not final and can change before the final release of Android O, but it gives us a good idea of what Android O is going to be like, and it gives us some time to start getting our apps ready before the new dessert is finally served.

Stay up with the Android developer crowd

Image credit: Flickr

Topics: Mobile