What’s Changed in Android 4.4 KitKat?

Written by: on November 11

The Android 4.4 release is packed with new APIs and features for both users and developers.

While my colleagues are walking you through the details of some of the bigger changes, I’d like to take the time to go over some of the more subtle additions and behavioral changes that developers should expect to encounter.

Permissions

Launcher Shortcuts

The INSTALL_SHORTCUT and UNINSTALL_SHORTCUT permissions have been added to the public SDK in API Level 19, making public the permissions necessary for applications to directly add or remove shortcut icons on the device’s Launcher.

These permissions are actually not new. They have been defined since Android 1.x, but back then the permissions were defined inside of the Launcher application itself rather than the public SDK, so applications making use of this new permission will be able to access this ability even on older Android devices.

External Storage

The rules for external storage have changed. Back in 4.1, the READ_EXTERNAL_STORAGE permission was introduced to complement WRITE_EXTERNAL_STORAGE, but at that time it wasn’t made required. This permission is now enforced in 4.4, but it a unique way. External storage, from an access control perspective, has been split into two major chunks: the app-specific directories for your application, and everything else.

To read or write data in your app’s specific location, no permissions are needed anymore. This basically applies to any directory you would obtain from a method on Context, such as getExternalFilesDir() or getExternalCacheDir(). If you are using these directories, eventually you will be able to even remove the need for the WRITE_EXTERNAL_STORAGE permission in your application.

To read data anywhere else on external storage, applications must obtain either the READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permission (both will grant read access). This would be any directory path obtains from Environment, such as getExternalStoragePublicDirectory() or getExternalStorageDirectory().

A More Flexible Approach

Periodic behaviors associated with the system managed timers of AlarmManager and SyncAdapter will now be more flexible by default. The purpose of this is to allow the system to batch events together whenever possible and reduce the number of wakeup events on the device, helping to conserve overall power.

The previously exact methods, AlarmManager.set() and AlarmManager.setRepeating(), will now behave more like AlarmManager.setInexactRepeating() and will be subject to event batching. There is no method starting with 4.4 to create an exact repeating alarm. If you require an alarm that is exact and repeats, you must now call the new setExact() method and set a new alarm yourself on each trigger event.

If you use a SyncAdapter, the periodic sync behavior provided by ContentResolver.addPeriodicSync() has always had some flex by design. This is increasing in 4.4 to encompass a window of up to 4% of the sync period (e.g. 2.5 minutes on a 1 hour sync period). In addition, the new SyncRequest.Builder API has been added to allow one-shot or periodic syncs with a little more control over the flex interval. For example, SyncRequest.Builder.syncPeriodic() performs the same basic function as addPeriodicSync(), but accepts an interval leading up to the period in which the adapter can safely flex to optimize when the sync should occur.

These functions will not change from underneath you, as they are pinned to setting the targetSdkVersion to at least 19. But, be aware of them once you increase the target and start testing your application’s compatibility. In the long run, however, favoring flexible alarms and syncing whenever possible will help your applications respect the device’s battery and provide a better overall experience for the users.

Bitmap Reuse

In an effort to further assist applications in reducing their memory footprint, Android 4.4 steps up the APIs for reuse of Bitmap allocations (easily the one thing that causes most Android developers to reach their heap limit too quickly). Starting in Android 3.0, we were given the ability to reuse an existing Bitmap instance (using inBitmap with BitmapFactory.Options) when decoding data with BitmapFactory, but the constraints were fairly steep; the image must be the exact same dimensions and configuration, and only JPEG/PNG decoding was allowed.

In Android 4.4, we now have Bitmap.reconfigure() to modify and existing instance to fit a new dimension and pixel configuration. BitmapFactory has been updated as well for this reconfiguration behavior to reuse inBitmap without the previous constraints.

Constraints do still exist though. When a Bitmap is created, it has a size and configuration that define the overall byte count of the allocation. This initial allocation size can never change for that instance. So while we can reconfigure a Bitmap over and over, each change cannot cause the required byte count to exceed the initial allocation size.

So, for example, I could safely reconfigure an instance from 200×200 at ARGB_8888 to 100×100 at ARGB_8888, and then again to 300×300 at RGB_565, because all of those fit inside the initial allocation. If I tried to reconfigure it to 300×300 at ARGB_8888, however, an exception would be thrown. It is also important to note that you cannot reconfigure a Bitmap while it is attached to a view. This should be done after the element has been detached or moved off-screen.

In other words, if your application can determine a suitable size for a single instance, even if it may be larger than the pixels needed at any given time, you can still reduce memory usage. A single 360KB Bitmap reused for both a 300×300 and 200×200 image (obviously not shown simultaneously) is better for everyone than needing 520KB (360KB + 160KB) for two separate instances.

More Smart Collections

To join the ranks of SparseArray, SparseIntArray and its other cousins, Android 4.4 brings a new memory-efficient collection to the platform in ArrayMap.  Where the SparseArray family was meant to improve performance by reducing allocations necessary to use primitives as keys, ArrayMap allows a full key-value mapping with objects, but is much more aggressive about capacity sizing than the java.util.HashMap, keeping object allocations down as the item count and capacity increase.  ArrayMap also keeps memory low by decreasing its size as items are removed; something one cannot expect from java.util.  In addition to being part of android.util in API Level 19; ArrayMap is also available in v19 of the Support Library, so you can make use of it even if you aren’t targeting 4.4 just yet.

Immersive Mode

A new set of layout flags are available for toggling System UI visibility. Beginning with 4.0, applications had the ability to hide the status bar and soft navigation buttons temporarily using the View.SYSTEM_UI_FLAG_FULLSCREEN and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION flags for a “lean-back” experience where visual content could take up the entire display. However, this mode was not interactive, and the UI controls were immediately returned as soon as the user tapped anywhere on the screen (an event your application did not receive).

In Android 4.4 View.SYSTEM_UI_FLAG_IMMERSIVE and View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY have been added to augment this. Using these flags in concert with the others mentioned, the same System UI can be hidden, but remain that way while the user interacts with the fullscreen application content. Google is still cautious about leaving the user without navigation controls, however. A system-level edge swipe gesture allows them to be brought back at any time, and the first time a user experiences this mode, a system overlay will appear, forcing confirmation that the user understands how to get the UI controls back.

Here is a simple example, built inside of a view’s click handler method (set via an android:onClick attribute) of the flag combination needed to put the user in immersive mode.

public void onToggleClick(View v) {
    //Hide the system UI.
    //The system will make the controls re-appear for us
    //when the user does an edge swipe from the top or bottom.
    v.setSystemUiVisibility(
            /* This flag tells Android not to shift 
              * our layout when resizing the window to
              * hide/show the system elements
              */
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            /* This flag hides the system status bar.  If
              * ACTION_BAR_OVERLAY is requested, it will hide
              * the ActionBar as well.
              */
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            /* This flag hides the on-screen controls
              */
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            /* This flag tells the controls to stay hidden until
              * the user brings them back explicitly with a gesture
              */
            | View.SYSTEM_UI_FLAG_IMMERSIVE);
}

Previously, I mentioned a second flag for making immersive mode “sticky”. This flag behaves the same way as the first, except that any time the user brings back the System UI elements, they will be auto-hidden again after a period rather than staying permanently back in place. Your application can cancel this mode by clearing the stick flag.

WebView

WebView has some new guts in 4.4; it is now completely built on Google’s Chromium source code. This brings performance enhancements and new features from HTML5 and CSS3, but it also means there are some behavioral differences for developers to contend with.

The capturePicture() method has been officially deprecated in favor of a more standard method of capturing a snapshot of the WebView’s content, such as manually triggering onDraw() to draw the contents into a Bitmap-backed Canvas.

Also, evaluateJavascript() provides a new method of executing Javascript that supports a callback result, although currently the loadUrl() method of doing so is not discouraged or otherwise deprecated in the documentation (…yet).

Google has a great document providing further details on the issues you might run into migrating to the new WebView.

App Ops Returns

It seems the App Ops functionality that first showed up in 4.3 is still not quite ready for prime time, but pieces are starting to show up in the 4.4 SDK.

We now have AppOpsManager, a system service dedicated to enforcing the allowed operations an application can perform alongside its current static permissions. It’s still not quite clear how this API will function in the end, but we can start to see the types of operations AppOpsManager is responsible for. Each operation is defined by an OPSTR_* constant, and in Android 4.4, they all have to do with user location.

This model of dynamic permissions enforcement is coming, whether we like it or not, so keep your eyes on these elements as the SDK evolves in the future.

A New Runtime

Since its inception, Android has relied on the virtual machine runtime we call Dalvik to execute the Java bytecode into which most applications are compiled. Dalvik was built from the ground up to provide a Java runtime to Android that fit in line with the process isolation and security model the operating system required.

In Android 4.4, however, we can see that Dalvik’s lifecycle is finite and will soon be replaced by a completely new implementation, dubbed the Android Runtime (ART). Little is known at the moment about it, beyond the introduction we received. It’s major differentiator seems to be that ART will compile Dex bytecode at install time into the native instructions, rather than the current operation of Dalvik which does this at runtime using a Just-In-Time (JIT) compiler model. Contrary to some reports, there doesn’t seem to be any evidence that this change is at all based on licensing or ownership issues regarding the Java language.

The ART compiler seems to support two modes: quick and portable. The quick mode is similar to a JIT (compiling the code at runtime), while the portable mode seems to be linked pre-compiling using LLVM. This LLVM connection might finally explain the mysterious appearance of the GDK project in AOSP a few versions back.

On devices like the Nexus 5, ART can be enabled in place of Dalvik as a Developer Option to allow developers to test applications and provide feedback on any issues that may crop up with the new runtime environment. All developers are encouraged to at least try their applications with ART enabled and report anything funny they find back to Google.

This piece is one of eight in our KitKat Developer’s Guide. Check back later this week for new updates or follow us on twitter.

Dave Smith

Dave Smith is a Senior Engineer at Double Encore, Inc., a leading mobile development company. Dave is an expert in developing mobile applications that integrate with custom hardware and devices. His recent focus lies mainly in integrating the Android platform with embedded SoC hardware. He is a published author and speaks regularly at conferences on topics related to Android development. You can follow Dave on Twitter and Google+.

Article


Add your voice to the discussion: