Tag Archives: Android SDK

Animating numerical change using Android Interpolators

Count von Count kneeling

I recently completed a financial charting tool with several user controlled variables, such as interest rate, term, loan amount. One client request was on the reset to default values there should be an animation while incrementing/decrementing rather than the value jumping instantly. I decided a non-linear animation algorithm would give the best visual result by adjusting the values quickly before decelerating as the target value approached. The graph below shows the required deceleration over time.

Decelerate graph

You may recognize this as a common interpolation pattern used in Android for animating movement of views. With this in mind I decided the most flexible design was to utilize the built-in Android Interpolator classes to control the rate of increment/decrement while using ValueAnimator. I have packaged the end result into an easy to use class, AnimateCounter.

AnimateCounter

AnimateCounter is a simple to use class to animate a numerical count on any TextView derived object. Full source code is available here.

The animation below shows an example of AnimateCounter being used to animate four TextViews from 0 to 100. Notice how the rate of numerical change for each view is influenced by the use of the different Interpolators.

Android Interpolation examples

Features of AnimateCounter

  • Ascending or descending value animation
  • Supports standard Android Interpolator classes
  • Supports custom Interpolator classes
  • Decimal and floating point number support
  • Numerical precision support
  • Optional callback on completion

AnimateCounter Usage

An AnimateCounter object is constructed using the builder design pattern. At a minimum a TextView is required for construction, then use the builder functions to optionally set initial and final values, precision, total duration and the interpolator required for animation. If no interpolator is provided the ValueAnimator default, AccelerateDecelerateInterpolator, is used.

Example 1: Count from 0 to 100 in two seconds using the default AccelerateDecelerateInterpolator interpolation.

AnimateCounter animateCounter = new AnimateCounter.Builder(textView)
        .setCount(0, 100)
        .setDuration(2000)
        .build();

animateCounter.execute();

Example 2: Count from 0.00 to 1.00 (floating point number with 2 decimal places) in 10 seconds using LinearInterpolator.

AnimateCounter animateCounter = new AnimateCounter.Builder(textView)
        .setCount(0f, 1f, 2)
        .setDuration(10000)
        .setInterpolator(new LinearInterpolator())
        .build();

animateCounter.execute();

Example 3: Perform an action after counting from 10 to 0 using the OvershootInterpolator.

AnimateCounter animateCounter = new AnimateCounter.Builder(textView)
        .setCount(10, 0)
        .setDuration(2000)
        .setInterpolator(new OvershootInterpolator())
        .build();

animateCounter.setAnimateCounterListener(new AnimateCounter.AnimateCounterListener() {
    @Override
    public void onAnimateCounterEnd() {
        // Add action here!
    }
});

animateCounter.execute();

Built-in Interpolators

Here are some of the Interpolators that you may like to use to animate the numerical change. These are all provided as part of the Android SDK:

Roll your own: Custom Interpolators

If none of the built in Interpolators fit your needs it is simple to create your own. The following class shows how to create an acceleration deceleration interpolation result. You could replace the mathematical formula in this class as required to produce your desired result.

import android.view.animation.Interpolator;
public class CustomAccelerateDecelerateInterpolator implements Interpolator {
 /**
  * Maps a value representing the elapsed fraction of an animation to a value that represents
  * the interpolated fraction. This interpolated value is then multiplied by the change in value
  * of an animation to derive the animated value at the current elapsed animation time.
  *
  * @param input A value between 0 and 1.0 indicating our current point in the animation
  *              where 0 represents the start and 1.0 represents the end
  *              
  * @return The interpolation value. This value can be more than 1.0 for interpolators 
  * which overshoot their targets, or less than 0 for interpolators that undershoot their targets. 
  */
  public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
  } 
} 

Graphing tools can be used to visualize the interpolation algorithms and are the best place to start if you want to build our own custom interpolator. Here is an example.

Step 1. Find a mathematical equation for interpolation. The following equation shows a formula used in the Android accelerate/decelerate interpolator, where time is represented by t.

aceleration deceleration function

Step 2. Graph your equation. Visit graphsketch.com or any graphing site and enter in the formula. When using graphsketch.com it is required in this format:

cos((x+1)pi)/2)+0.5

The generated graph should confirm if the output from the formula is going to meet your needs. Using the above example the following graph is produced. Note the acceleration during the first half of the duration and the deceleration during the final half.

Accelerate decelerate graph

Step 3. Convert into Java. To use in your custom interpolator you need to convert your equation into Java code, for example:

cos((x+1)pi)/2)+0.5
(float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;

Source Code

Source for AnimateCounter available on GitHub

Attribution

“Count von Count kneeling” by Source. Licensed under Fair use via Wikipedia – https://en.wikipedia.org/wiki/File:Count_von_Count_kneeling.png#/media/File:Count_von_Count_kneeling.png

1 Comment

Filed under Android SDK, Animation

Disable Android ART ahead-of-time compilation to optimize debug deployment

Android ART

With the introduction of the ART runtime came ahead-of-time (AOT) compilation to replace the Dalvik just-in-time (JIT) compilation. This is achieved on app installation when a one time process is executed to convert the APKs DEX files into a compiled app optimized for the device it is running on. Devices running the old Dalvik VM use JIT compilation that is performed at run time and only on frequently executed parts of apps. This change is designed to increase execution performance of apps on the new ART runtime.

For developers AOT compilation can cause frustration as every time an app is changed it has to be reinstalled on the target device. The AOT compilation process can take anything from a second to well over 10 seconds, the more code in an app the longer the device compilation process takes.

The good news is that it is possible to disable this AOT compilation for your debug builds, although this will cause your app to revert to being interpreted as it is executed. Disabling AOT compilation reduces the total time taken to deploy the app to the device and as a developer if you are modifying code and executing the app time after time, any increase in deployment speed is a welcome improvement. The tradeoff is a reduction in performance, although you are not likely to notice this performance hit for most types of applications. You should also consider that if you are writing an app that performs intensive computations then you may find saving a couple of seconds on installation for a compromised runtime performance is a counter-productive optimization.

Disabling ART ahead-of-time compilation

Disabling the AOT compilation is as simple as adding the application attribute android:vmSafeMode in your AndroidManifest.xml. Here is an example:

<manifest
 package="com.testing.sample.myapp"
 xmlns:android="http://schemas.android.com/apk/res/android">

 <application
 android:icon="@mipmap/ic_launcher"
 android:label="@string/app_name"
 android:vmSafeMode="true">
 ...

It is important to understand that this is not an attribute that we want to override on our release builds. It is possible to apply the attribute to debug builds only by creating a new …/app/src/debug/AndroidManifest.xml file. In this new manifest file you don’t need to replicate your existing manifest and can simply include the attribute you wish to add:

<manifest
 xmlns:android="http://schemas.android.com/apk/res/android"> 
 <application android:vmSafeMode="true" />
</manifest>

Note: It is only possible to disable AOT compilation if you have a targetSdkVersion of 22+ and you’re running a device using the ART runtime.

Execution timing of ART ahead-of-time compilation

Before you make this change you should first identify that AOT is causing a significant delay to your deployment times. For small apps it is likely that you will save less than a second of installation time and this optimization is probably not required.

The device process that performs the ahead-of-time compilation is called dex2oat and outputs logging information that allows us to see the execution time elapsed. Filter your logcat for items containing dex2oat and you will see the execution time for the process.

Here is example output with AOT compilation enabled:

07-03 10:19:02.650  21326-21326/? I/dex2oat﹕ /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.testing.sample.myapp/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@app@com.testing.sample.myapp-2@base.apk@classes.dex --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --swap-fd=8
07-03 10:19:03.989  21326-21326/? I/dex2oat﹕ dex2oat took 3.338s (threads: 4) arena alloc=107KB java alloc=2MB native alloc=4MB free=3MB

Output with AOT compilation disabled:

07-03 10:17:33.934  19031-19031/? I/dex2oat﹕ /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.testing.sample.myapp-1/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@app@com.testing.sample.myapp-1@base.apk@classes.dex --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=interpret-only --swap-fd=8
07-03 10:17:34.693  19031-19031/? I/dex2oat﹕ dex2oat took 1.258ms (threads: 4) arena alloc=0B java alloc=2MB native alloc=502KB free=7MB

Checking if manifest includes vmSafeMode

The logcat output of the dex2oat process also lets you check that the vmSafeMode attribute has been correctly applied. When vmSafeMode is set to true this process will be executed with the following argument:

/system/bin/dex2oat ... --compiler-filter=interpret-only

If you are seeing this option when installing your release APK then it is likely you have included vmSafeMode in your apps main AndroidManifest.apk rather than the debug only manifest.

Another method I found for determining if vmSafeMode is set for a given APK is to use the aapt.exe tool. You will find the aapt tool in the build-tools folder of the Android SDK, which differs in location based on your chosen OS. You will probably have several different versions installed and will find it in a location such as:

.../Android/sdk/build-tools/22.0.1/aapt.exe

Execute the list command:

aapt list -a myapkfile.apk

This should produce output including:

Android manifest:
N: android=http://schemas.android.com/apk/res/android
  E: manifest (line=17)
    A: android:versionCode(0x0101021b)=(type 0x10)0x1
    A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
    A: package="com.testing.sample.myapp" (Raw: "com.testing.sample.myapp")
    A: platformBuildVersionCode=(type 0x10)0x16 (Raw: "22")
    A: platformBuildVersionName="5.1.1-1819727" (Raw: "5.1.1-1819727")
    E: uses-sdk (line=22)
      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x15
      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x16
    E: application (line=26)
      A: android:label(0x01010001)=@0x7f0b0001
      A: android:icon(0x01010002)=@0x7f030000
      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
      A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff

Side effects of disabling AOT compilation

Without ahead-of-time compilation your app is going to run slower, it probably won’t be noticeable, but the runtime will have more work to do during execution. I have heard some developers have had major performance problems, such as execution of intensive processing experiencing a 10x increase in execution time. So keep an eye out for any performance problems.

So far I am happy to report that I have not run into any execution issues or unexpected behavior while testing this optimization.

References

Android ART:

https://source.android.com/devices/tech/dalvik/

Android Manifest vmSafeMode attribute:

http://developer.android.com/guide/topics/manifest/application-element.html#vmSafeMode

1 Comment

Filed under Android SDK, Performance

Vector Graphics in Android: SVG Format

Vector graphics native support has long been on the wishlist of Android developers who have to export their vector graphics as a rasterized PNG file for each different device resolution.

The main use case for vector images are simple icons that need to scale to fit the resolution of the device. Another more complex use case is to implement functionality like that of the Androidify app from Google. In that app you can tweak and accessorize your little Android friend without any of the artifacts that become present when resizing raster images.

Why doesn’t Android support SVG?

I don’t believe there has ever been official word out of the Android team about support for SVG (Scalable Vector Graphics). However it is safe to assume that the reason SVG is not supported as a native image format is because of performance issues. SVG files can run into megabytes of XML data and to render a SVG those megabytes of XML have to be parsed and interpreted and then rasterized. Do some testing using some complex SVG images with some of the open source libraries in this article and you will see the performance issues that surface.

With Android 5.0 we have seen the future direction of vector graphics for the operating system, that is the VectorDrawable class. I will discuss this new functionality in more detail in a sequel to this article, but the take away from it is that full native SVG support will not be coming to Android any time soon, if ever. To read more about converting your SVG files to a VectorDrawable see the second part of this series on Vector Graphics in Android:

https://androidbycode.wordpress.com/2015/03/18/vector-graphics-in-android-converting-svg-to-vectordrawable/

Open Source SVG support

The solution for developers to get vector image support has been to turn to the open source community to fill this gap. There have been a few solid implementations providing SVG support in line with the majority of the SVG specification. However there is no prefect solution for using SVG files in Android and there never will be. Every implementation will have performance issues and, of what is currently available, they all have quirks (some would call bugs) that need to be worked around.

Here is a list of the main open source projects. None of these projects will support every SVG and none will support every part of the SVG specification. You will need to try each solution with the type of SVG files you want to render in your app.

AndroidSVG

Website: https://code.google.com/p/androidsvg/

Description: Parser and renderer for Android that claims almost complete support for the static visual elements of the SVG 1.1 and SVG 1.2 Tiny specifications.

Last release:  1.2.2-beta-1 (16 June 2014)

Known issues: 

  • Stroking of underlined or strike through text is not supported in versions of Android prior to 4.2
  • Android 4.3 bug that breaks the <clipPath> feature when using renderToPicture()
  • SVGImageView has documented issues in Android Studio

Status: Code is still being developed and a 1.3 release is planned although the last source code changes were checked in August 2014.

License: Apache License 2.0

Review: I had no issues with this library when rendering simple SVG files. Throw some complex SVGs at it and you see the performance hit you are taking. On some environments I was hitting the stack size limit and could not load some complex images. For my use case loading the SVG on a thread and displaying a placeholder image until completion of the load produced the most successful outcome.

svg-android

Website: https://github.com/pents90/svg-android/tree/master/svgandroid

Description:  The developers describe this as a compact and straightforward library for parsing SVG files and rendering them on an Android Canvas. This was the library used to render the interface of the original Androidify app.

Status: Appears abandoned, last changes 2012

License: View the license here

Summary: Very popular on initial release, there are many forks of this project but few have made substantial ongoing bug fixes. If this library works well for you except for some bugs then you may want to hunt around the many forks.

svg-android-2

Website: http://code.google.com/p/svg-android-2/

Description: Scalable Vector Graphics Support for Android. This project, a fork of the svg-android project, exists to provide additional capabilities to the svg-android project.

Status: Last code changes were Jan 2014, although very little active development takes place in this project, occasional bug fixes are applied.

License: Apache License 2.0

Summary: Fork of svg-android with enhanced features and newer bug fixes, however development is spasmodic.

TPSVG Android SVG Library

Website: https://github.com/TrevorPage/TPSVG_Android_SVG_Library

Description: SVG image parser for Android. The developers description is that it converts image to list of native android.graphics objects which can then be speedily rendered on Canvas, and provides callbacks to allow image elements to be manipulated programmatically.

Status: September 2013 was last activity on this project

License: Apache License 2.0

Commercial Support

There are some commercial options available for SVG support on Android. I have not tried them and have not read glowing reviews of them that would have me reaching for my wallet, if however any of them proved to have a performance edge loading SVG files then they may be worth your consideration.

Conclusion

SVG is a open standard that allows developers to quickly make p vector graphics without expensive software. However it is not a standard that was designed to be quickly rendered inside applications, which is why it is not supported by native Android. There are cases however where using SVG can not only save you development time, but also increase the visual appeal of an app.

If you believe your app falls into the category of those that can benefit using SVG then you may consider using one of the open source libraries. I would recommend AndroidSVG, as long as you follow my two golden rules with SVG and Android:

  • Keep the complexity of your SVG files to a minimum
  • Never load an SVG on the UI thread (either pre-load in advance, or display a placeholder while it is loading)

You may have to get your hands dirty and fix bugs yourself in any of these open source libraries, or work around bugs by manipulating the XML of your SVG files. It is best to have a variety of tools capable of writing SVG files as different tools will produce different XML that will perform differently with these libraries.

One last word of warning. Before you jump in and implement anything using the SVG format in your app you should take a look at VectorDrawables.  I won’t go into the pros and cons of these here, I will leave that for part 2 of this series on Vector images in Android.

Sample Project

For a functional sample showing the use of AndroidSVG, take a look at the following project from GitHub:

https://github.com/bmarrdev/CountryRank

References

SVG Homepage

http://www.w3.org/Graphics/SVG/

SVG Specification

http://www.w3.org/TR/SVG11/

Inkscape Open Source Vector Authoring Tool

https://inkscape.org/

Leave a comment

Filed under Android SDK, Image

Nexus Lollipop soundpool.load() not so sweet

When I got my first taste of the Android L pre-release I noticed something rather disturbing when running some games.  I was using a Nexus 5 and every now and again a long pause where an app would become non-responsive. Sometimes it was a couple of seconds and other times it was 10, 20 or more seconds without response, then it would finally burst back to life. After doing a little digging and I tracked it to an issue with the Nexus family using the SoundPool.load() function.  This issue lives on with the latest Android 5.0.2 build.

Issue Description

The Android SoundPool class allows developers to pre-load several short sound clips so the may be played at any time without the lag of decompressing on the fly.  This is perfect for game developers where sounds may be played many times. On the Nexus family of devices, the execution of the SoundPool.load() function may take several seconds to load a very small audio file, instead of the few milliseconds as has been the case with the same files on previous Android versions, or with other devices running Lollipop.  The issue relates to the ‘AwesomePlayer’ media engine. There is a way to confirm if this is an issue in your code.  Go to the media section of the developer options and check the ‘Use NuPlayer (experimental)’ checkbox.  Run your app again and you should see none of the unresponsiveness that has lead you to this post. If the delay remains it is likely not being caused by the SoundPool.load() issue.

Issue Status

As of Android 5.0.2 this is an unresolved issue in the Android Open Source Project (AOSP) issue tracker. It’s can be reproduced on most of the Nexus devices that have support for 5.0, from the Nexus 4 through to 5, 7 (2012 & 2013) and 9.  I have not been lucky enough to get my hands on a Nexus 6 to confirm if it suffers the same affliction.

Poor app design exposed

The Android media engine requiring seconds to load a small sound file is clearly not acceptable, but what it does is exposes apps that are executing the sound pool loading code from the UI thread. For a few small audio files that were taking a few milliseconds each, this was never noticed. But best practice dictates load functions like this should be happening on a background thread. Structure you app so the thread has maximum time to load all it needs to load without needing to hold up the user.  Once this change is made chances are this issue will no longer be a problem in your app and you won’t be waiting for the AOSP fix.

Changes to SoundPool in API 21

While on the subject of the SoundPool class, Android 5.0 (API 21) also brings some recommended usage changes.  So read on if you have not changed the way you create your SoundPool on Lollipop devices. If you take a look at the SoundPool interface the constructor public SoundPool(int maxStreams, int streamType, int srcQuality) is now deprecated. The recommended usage is to create and configure the SoundPool instance using the SoundPool builder class (SoundPool.Builder) The SoundPool Builder is only available on API 21+, so you will need to create your SoundPool differently based on the SDK version of the device your app is running on. When your code is executed on devices running 5.0+ create the SoundPool using the builder, as follows:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void createSoundPoolWithBuilder(){
    AudioAttributes attributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .build();

    mSoundPool = new SoundPool.Builder().setAudioAttributes(attributes).setMaxStreams(6).build();
}

For devices running 4.4 and older use the SoundPool constructor:

@SuppressWarnings("deprecation")
protected void createSoundPoolWithConstructor(){
    mSoundPool = new SoundPool(6, AudioManager.STREAM_MUSIC, 0);
}

Check the device version to call the appropriate function to create the SoundPool:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    createSoundPoolWithBuilder();
} else{
    createSoundPoolWithConstructor();
}

Hopefully this has sorted your Android 5.0 SoundPool woes.

Update March 2015: This issue was still present for my Nexus devices after initially updating to Android 5.1, although it seems on a clean install of 5.1 the default media engine is now NuPlayer which does not have exhibit the SoundPool issue.

lollipop

4 Comments

Filed under Android 5.0, Android SDK, Audio, SoundPool