Category 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

Advertisements

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

Google Cloud Test Lab for Android

While it was not the most exciting announcement at Google I/O, one of the most useful services announced was that of the upcoming Cloud Test Lab. Cloud Test Lab allows Android developers to have their apps automatically tested on real physical devices. Sounds pretty cool eh? Well it gets better, on launch it will have 20+ Android devices and it’s free! Well some features will be free anyway. Here is how Google describe the service:

For comprehensive testing before releasing your app, Cloud Test Lab gives you access to physical devices so you can see what’s going on for your users in the real world. Plus, you can run all of your tests across all devices, all at the same time—giving you access to massively parallel testing, bringing you deep and scaled insight.

Cloud Test Lab

What you need to know

Google Cloud Test Lab

Website: https://developers.google.com/cloud-test-lab/

Current Status: Early Access sign up is now open

Estimated Release Date: September 2015

Device support: 20+ devices on launch

Cost: Free for basic functionality

Sign Up: Follow the links from your Google Play Developer Console account, as shown below.

Link to signup to Cloud Test Lab

Figure 1: Signup to Cloud Test Lab from the Developer Console

The Early Access Form is simply a few questions as shown below. You will need to have an app published though the Developer Console to apply.

Cloud Test Lab signup

Figure 2: Early Access Form for Cloud Test Lab

Cloud Test Lab functionality

The Google Cloud Test Lab is based on technology from Appurify, which Google acquired back in June 2014. Appurify have some pretty awesome technology, so this is a service that is packed with potential.

As this is a yet to launch service, details from Google are a bit vague at the moment. Here are a couple of important statements that give a bit more of a hint of what we can expect.

Every APK submitted to Play Store’s Alpha and Beta channels will be automatically scanned on more than 20 physical devices and get a free launch performance report. Developers who want to run customized testing can eventually purchase it through Cloud Test Lab.

My hope is that Google’s strategy won’t be to focus on making money directly from this venture but use the service to drive an improvement in the quality of apps. The service has the potential to make it faster and easier for developers to deal with the issues associated with the fragmentation of Android devices. I see this playing out with a subset of functionality on a subset of devices being provided for free. This will be fantastic for indie developers and small companies that do not make enough money from their apps to spend $1000’s on testing. This free functionality is likely to be the use of basic app crawlers to provide unscripted pseudo-random testing. It will probably be more advanced than letting monkey loose on the app and most likely built from the Appurify robot app crawler functionality.

A much larger set of functionality from a much larger pool of devices is not a cheap service to provide and will come at a cost for developers. This will target the top 1% of apps and provide a method for supplementing the apps existing internal testing. The sort of extra functionality likely to be included would be features such as:

  • Support of automated testing frameworks such as Espresso and UIAutomator
  • Full control of device environment, such as network connection, signal strength, memory, language and location
  • Comprehensive network traffic, memory, CPU, battery and FPS performance profiling
  • Comprehensive device library

Devices I want to be included

Now I don’t ask much, but I want the physical devices to be a range of devices that covers the following:

  • Devices from each manufacturer
  • Flagship devices for each of the past several years
  • Each released CPU architecture
  • Each Android API, including preview APIs
  • Combinations of Feature Sets
  • Android One devices
  • Various physical screen size
  • Various screen densities
  • Various screen resolutions
  • Range of languages
  • Languages with RTL layouts
  • Android Wear devices
  • Android TV devices
  • Android Auto devices

When do we find out more?

More details and a test run of the service is still a month or two away. Stay tuned to the Cloud Test Lab site for updates.

Leave a comment

Filed under Android SDK, Cloud Test Lab, Testing

Material Design Snackbar using the design support library

A Snackbar is a lightweight material design method for providing feedback to a user, while optionally providing an action to the user. They are displayed on the screen until a specified interval has passed, the user swipes to dismiss them, or when the user interacts with another part of the screen. Think of it as a modern take on the Android Toast.

This week at Google I/O 2015 the Android Design Support Library was released including a Snackbar implementation. Before now implementing and following the material guidelines for a Snackbar was left to the developer. A few third party libraries were released to make developers lives easier, but now official support for Snackbar has been introduced to make it easier than ever to add a Snackbar to your Android app.

Support for Snackbar pre-lollipop

While the Snackbar concept was introduced with the material design guidelines, the newly released Android Design Support Library works with devices right back to Android 2.1 (API 7). That is over 99% of active Android devices.

Material design specification for Snackbars

Many of the design rules for Snackbars are automatically enforced by the new support library. For example, if you provide lower case text for the action button it will automatically be displayed in upper case. However you still should brush up on the exact guidelines to know the best practices and what you can and can not do with a Snackbar. Take a look at the specification for full details.

A summary of the guidelines are:

  • Content: Keep text short
  • Icons: Do not add icons
  • Core functionality: Do not place core app functionality into a Snackbar
  • Multiple Actions: Use a dialog if you have multiple actions
  • Input: Snackbar does not block input, use a dialog for this
  • FAB: Don’t block the floating action button (FAB)
  • Consecutive: Only one can be displayed on the screen at any time
  • Single-line height: 48dp
  • Multi-line height: 80dp
  • Font: Roboto Regular 14sp
  • Action button: Roboto Medium 14sp, all-caps text
  • Default background fill: #323232 100%
  • Width on Tablets: Minimum 288dp, maximum 568dp

Adding a Snackbar to your app

Firstly you will need to add the Android Design Support Library dependency to your gradle build script:

compile 'com.android.support:design:22.2.1'

Next, you need to add a CoordinatorLayout to your xml layout. More details about what new features this new layout class bring are included later in this blog. Here is one that will position itself centered at the bottom of the screen:

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"        
    android:layout_height="match_parent"        
    android:layout_alignParentBottom="true"        
    android:layout_centerHorizontal="true"        
    android:id="@+id/snackbarPosition">
</android.support.design.widget.CoordinatorLayout>

In your AppCompatActivity class you need to configure the Snackbar object using the Builder design pattern. The most useful functions will be to create the Snackbar with make(), optionally set an action that the user can perform using setAction(), and finally to display the Snackbar to the user, show().

Snackbar will only work in Activities that are AppCompatActivity. If your activity extends a standard Activity or ActionBarActivity then you will need to either change your base class or use a third party implementation of a Snackbar.

Here is an example of a Snackbar that displays a message and allows an action to be executed by the user:

import android.support.design.widget.Snackbar;

public class MainActivity extends AppCompatActivity...

final View.OnClickListener clickListener = new View.OnClickListener() {
    public void onClick(View v) {
       ...
    }
};

final View coordinatorLayoutView = findViewById(R.id.snackbarPosition);

Snackbar
    .make(coordinatorLayoutView, R.string.snackbar_text, Snackbar.LENGTH_LONG)
    .setAction(R.string.snackbar_action_undo, clickListener)
    .show();

The result should be a Snackbar displayed on the device as shown in the image below. Note how the Snackbar in this image conforms to the specification. The text is kept short and the action text is all upper case. It is displayed on a tablet, so you will see rounded corners of 2dp and that a minimum width is enforced.

Snackbar displayed on tablet

Snackbar displayed on pre-lollipop tablet

Processing the Action button

The Snackbar action button should present an action related to the information being presented to the user. The most common type of actions are UNDO and RETRY.

Remember in the Material Design Snackbar specification that you can only show one action on a Snackbar, and that action must be short text composed entirely of uppercase text, no icons.

In the previous Snackbar example you can see that creating a View.OnClickListener() and adding it with an action is quite simple. The only work left is how you handle a click on the action button. Let’s take a look at an example, it is one of the most common use cases for a Snackbar. You have a list of items that are loaded from a database. With a swipe of the finger the user removes an item from the list and you display a Snackbar to confirm to the user that the item has been deleted and provide a action button to UNDO the delete and restore the item.

There may be a temptation to think that the easiest solution here is to remove the item from the list and wait until the Snackbar has completed being displayed and then do the actual delete from the database. If the user has hit the UNDO action button then add the item back into the list and don’t do the delete from the database.

The Snackbar implementation in Android does not encourage this type of implementation and in fact it doesn’t provide a callback to signal when the Snackbar view is no longer visible. The design pattern that Android wants you to follow for the example I have given is when the item is swiped from the display the item should be removed from the database immediately. You should keep the data needed to re-insert this item in the case that the user selects the UNDO action.

Positioning of the Snackbar

The Material Design specification of a Snackbar only stipulates that it is shown at the bottom of the screen. The example images in the specification show the Snackbar being horizontally centered, however the default position of the Snackbar in the Android design support library is the bottom left of the device if you do not use a CoordinatorLayout (see below). It is only possible to control the position of the Snackbar if you are using a CoordinatorLayout.

On smaller screen devices the Snackbar will take up the entire width of the screen, while on larger tablets sized screens the Snackbar will hit the maximum allowed width and not take up the entire width of the device.

Introducing CoordinatorLayout

When using many of the new elements introduced in the support library you will need to get to know the CoordinatorLayout.

CoordinatorLayout is a ViewGroup derived component that allows you to specify behaviors for child views to control how they interact with one another. If you recall one of the design rules for Snackbars was that they should not block the floating action button (FAB). With the newly released FloatingActionButton class blocking of the button is prevented by controlling the behaviors of the child views in the CoordinatorLayout.

By using a CoordinatorLayout you are also able to add padding or margins in order to move the Snackbar display position from the bottom of the screen.

Swipe to dismiss

Swipe to dismiss functionality is baked into the new Snackbar class when used in conjunction with a CoordinatorLayout. If you are finding that swiping on your Snackbar has no effect then check the type of View you are passing to the Snackbar.make() function. You don’t have to pass the CoordinatorLayout directly, passing a child view of a CoordinatorLayout is sufficient.

Duration of the Snackbar display

The Snackbar is not designed to be displayed indefinitely, but you are able to set the duration it is displayed before it is once again animated to hide it from the interface.

There are two standard lengths Snackbar.LENGTH_LONG, which is currently 2750 ms and Snackbar.LENGTH_SHORT which is currently 1500ms. It is possible to pass a custom display length in ms to the Snackbar.setDuration(int) function, and with the 22.2.1 release Snackbar.LENGTH_INDEFINITE is also a valid argument.

Adding bold text to your Snackbar message

You can add formatting such as bold to your Snackbar text using the Android Html class. The Html.fromHtml() function will generate a Spanned object that can be passed to the Snackbar.make() function:

Snackbar.make(view, Html.fromHtml("Add <b>bold</b> to Snackbar text"), Snackbar.LENGTH_LONG).show();

Adding multicolored text to your Snackbar message

You are able to add color combinations to the Snackbar text using the SpannableStringBuilder class. Using this class is also an alternative method for applying formatting such as bold to the Snackbar text.

Here is an example:

SpannableStringBuilder snackbarText = new SpannableStringBuilder();
snackbarText.append("Add ");
int boldStart = snackbarText.length();
snackbarText.append("bold color");
snackbarText.setSpan(new ForegroundColorSpan(0xFFFF0000), boldStart, snackbarText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
snackbarText.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), boldStart, snackbarText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
snackbarText.append(" to Snackbar text");

Snackbar.make(view, snackbarText, Snackbar.LENGTH_LONG).show();
Snackbar colored text

Snackbar colored text

Using the Design Support Library with ProGuard

In the initial release of the Design Support Library (22.2.0) you may hit issues with ProGuard. At this stage I would recommend you exclude all the design support library from the effects of ProGuard. This will cause some unnecessary bloat and once an update of the design support library is released you should revisit this issue and look for some official documentation. For now you can add the following to your ProGuard rules:

-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }

Bigger is not always better

In the case of a Snackbar minimizing your text length is vital. Be succinct when writing text on the Snackbar, especially the action text. While the text must contain enough information that the user understands the meaning, it can’t be so verbose that layout problems are caused on small devices.

Ensure you test the layout of the text on a range of devices. While your text may look good on your shiny new 10″ tablet, spare a thought for those on the smallest devices your app is targeting.

If it is a possibility that you may localize your app in the future then think about the size of the text now to prevent more work down the track. Consider doing some pseudo-localization testing for your app, remembering that this text could possibly be twice as long after being translated from your apps native language. I have previously blogged about how to test localization using pseudo-localization on Android.

References

Snackbar specification:

http://www.google.com/design/spec/components/snackbars-toasts.html

Snackbar class:

https://developer.android.com/reference/android/support/design/widget/Snackbar.html

CoordinatorLayout class:

http://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html

5 Comments

Filed under Android SDK, Android Studio, Material Design

Help! My custom font does not work on Android 5.0

Issue description

On Android Lollipop versions before 5.1 some custom fonts loaded using the API Typeface.createFromAsset() do not render using the correct font. This issue was fixed with the release of Android 5.1, but will still affect your users running Android Lollipop 5.0.x.

This should not cause a crash in your app, it will just cause your view to render using the default typeface rather than the custom font you have specified.

What causes the issue?

The cause of this issue is badly formed TTF font files. Minor issues in font files may be ignored or tolerated by most systems rendering the font, however the tolerance level in the early builds of Lollipop was not so high and some fonts fail to render causing the system to fall back to using the default font. It is similar to having a badly written audio file that will play in some media apps but is flagged as corrupted in others.

Is my app affected?

The first thing to check is if your app loads custom fonts. Take a look for any font files found in your Android assets/fonts folder. Then look for the code that is loading the font so you can see where in the apps UI the custom font is used. Loading a custom font from your apps Assets folder and setting it into a View is quite straight forward.

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/myfont.ttf");
myView.setTypeface(tf);

Having custom fonts doesn’t always mean your app will be affected by this issue however. The quickest way to check is to visually verify those custom fonts are being rendered correctly. Another check suggested by the Android team is to run your font through the Sanitiser for OpenType engine. To determine a potential issue look for this in the output:

WARNING at ots-read-only/src/cmap.cc:160: bad id_range_offset

Solution

The root cause of the problem is badly written font files, so it makes sense that the solution is to re-encode the offending font.

If you only have a couple of font files you would like to re-encode a great place to start is with an online converting tool such as http://www.freefontconverter.com/. Upload your dodgy font file and even if you select the same input and output font format (ie. TTF), the file will still be re-encoded and should now be able to be used in your app. This web service has successfully fixed all the non conforming fonts I have thrown at it.

However if that online tool did not help, or you have a huge repository of files you would like to re-encode you may like to use https://github.com/behdad/fonttools/ to convert your TTF to XML and then back to a TTF.

Be careful running any software that will re-encode your font files. As this process will be changing the file there may be side effects such as loss of quality. Also it is possible the tool you are using to re-encode the file will also produce non-compliant font files that fail in some environments.

Why did my Unit tests not catch this error?

If you have had to fix this error then you may be thinking to yourself, Why did my unit test not alert me to this issue? or How can I write a unit test to stop this issue next time?

Don’t be too hard on yourself; for all intents and purposes the code appears to function correctly without visually verifying the rendering. The typeface is loaded correctly and it can be set into a view without issue or complaint. Even after the view has been invalidated and rendered there is still no exceptions or warnings of an issue raised. The problem only becomes obvious on visual inspection of the View.

References

Android issue tracker for this issue:

https://code.google.com/p/android-developer-preview/issues/detail?id=608

Android Typeface documentation:

http://developer.android.com/reference/android/graphics/Typeface.html

Leave a comment

Filed under Android 5.0, Android SDK, Testing

Pseudo-localization testing in Android

Developers localizing Android apps have to contend with the same considerations and issues as with software on any other platform. This article is not a step by step guide to the internationalization process, but simply touches on a couple of Android specific tips and tricks for developing a localized version of your app. Before proceeding you should be familiar with the Android Localization practices described in the official documentation. Localizing with Resources and Localization Checklist are the best place to start.

What is Pseudo-localization?

Pseudo-localization is a method to test the internationalization of text while maintaining readability. The purpose of this testing is to expose issues regarding length and flow of text, layout issues and logic issues.

If you are getting translations done externally it can be a time consuming and expensive process so localization testing should take place long before you get any kind of translator involved. By verifying everything is correct you will save time and iterations back and forth with translators.

Testing with Pseudo-localization on Android

You can test localization in your Android app by using a special developer locale that will lengthen string lengths and add accents to characters while still maintaining readability of the original strings. While documentation from Android regarding these new locales is basically non-existent at the moment, it appears you need to be running Android 5.0+ and have developer options enabled on the device to be able to access these special locales.

On your compatible Android device navigate to the device settings and select Language & Input > Language > English (XA)

locale_english_xa sample_locale_english_xa

After setting the language to English (XA) (above left image) text will start to appear in the pseudo-localization style (above right image). You will notice how the text is still legible in English, while being substantially longer than normal, in order to simulate more verbose languages.

As a broad generalization the Romance languages can be up to 30% longer than the equivalent English, while languages such as Chinese, Japanese and Hebrew languages may be significantly shorter.

Using your Android device after making this locale change you will note that most apps will not take on the same English (XA) appearance as is displayed in the example image. The reason for this is that pseudo locale support is designed simply for testing so must be explicitly enabled for each app individually in the build process. You can do this by setting pseudoLocalesEnabled to true in your gradle build script.

buildTypes {
    debug { 
        pseudoLocalesEnabled true 
    } 
}

Note: Support for pseudoLocalesEnabled was added to the Gradle plugin version 0.14.2.

Simplifying localization using XLIFF

XLIFF is a set of standards to aid in the translations of XML documents. You can use XLIFF to prevent text being translated and also to show formatted examples of string paramters. To use XLIFF in your Android string XML files you need to include the XLIFF 1.2 namespace:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">

This example shows how you can use XLIFF to help translators by flagging text not to be translated:

<string name="website_url">
    Take a look at our website <xliff:g id="blog_address">https://androidbycode.wordpress.com</xliff:g>
</string>

This example shows how to use XLIFF to display example arguments when using String formatting. It allows translators to understand what the data that will be injected into the string will look like.

<string name="city_longitude">
    Longitude: <xliff:g id="lon" example="37.8° S>%1$s</xliff:g>
</string>

Note: Support for XLIFF is available in Android Studio 0.3 and later

Supporting Right to Left layouts

Native Android support for right to left layouts (RTL) was introduced in API 17 (Android Jelly Bean 4.2). The Android Framework Team covered the introduction of this support in some detail.

Layout Mirroring is a term used to describe the ability of software to reorder the UI elements to match the right to left flow for that locale. It is possible to achieve a mirrored layout by manually creating a layout for RTL locales, but with API 17 automatic layout mirroring was introduced. If you want your app to use layout mirroring then you need to flag this support in the <application> element in your manifest file.

 android:supportsRtl="true"

For some time Android Lint has been generating warnings in layouts to replace or duplicate left/right layout properties to new start/end equivalent properties for RTL support. For example if your layout contains layout alignments for left or right, such as:

 android:layout_alignParentRight="true"

You should also add the equivalent End element to support RTL:

 android:layout_alignParentEnd="true"

The latest versions of the Android Studio layout editor will add these in automatically when you create the items. If you are hand coding the XML or created the layout in an alternative IDE you may have to add them manually.

Mirroring drawables on RTL layouts

Drawables often need to be reversed on locales that use RTL layouts. An example of this is the Notification bar at the top of your Android device. On a RTL layout the icons, ie. signal strength, will be reversed. There are a couple of ways to achieve this.

For API 19+ you can set the the AutoMirrored Flag to indicate if a drawable should automatically be reversed when a RTL locale is selected.

For API 17+ you can specify different drawables in the same manner as you might for different densities using the qualifier “-ldrtl” or “-ldltr”. For example your resource folders may look like this:

res/
    drawable-ldrtl-xhdpi
    drawable-ldltr-xhdpi

Testing with Pseudo-localization on RTL layouts

Earlier in this article I explained how to set your device to language English (XA). There is also another locale (XB) in the languages list which allows testing of pseudo-localization using a mirrored RTL layout.

locale_xb sample_locale_xb

In the images above the Android signal strength icon is AutoMirrored once the RTL layout locale is invoked. Take some time to consider which icons should be mirrored in your app. Also note how layout mirroring has been invoked with the ActionBar to move the search and navigation views.

Summary

Translating large products is a time consuming and expensive exercise that will require at least a few iterations between developer and technical writer. By ensuring your product is fully prepared for localization prior to starting the text translations you will keep the number of iterations and costs of the process down. Add pseudo-localization, visually inspect all layouts and run your full test process to ensure your product not only functions, but looks good in anyone’s language!

2 Comments

Filed under Android SDK, Testing

Vector Graphics in Android: Converting SVG to VectorDrawable

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.

Introducing VectorDrawable

The good news is that the Android SDK now has native support for basic vector graphic definitions. With the release of API 21 (Android 5.0) came VectorDrawable.

android.graphics.drawable.VectorDrawable

The most important things to understand if you want to implement drawables in your app using VectorDrawable are:

  • VectorDrawable is not implemented in the support library, therefore it will only work in Android 5.0+ (VectorDrawable support for older APIs may be coming soon to the support library)
  • VectorDrawable supports paths using the same definition as the ‘d’ attribute in the SVG format
  • VectorDrawable does not read or support the SVG format
  • VectorDrawable does not support gradients and patterns
  • VectorDrawable does not support numbers using scientific E notation (as commonly used in SVG)

While it is important to understand that the SVG format is not supported, it doesn’t necessarily mean you can’t convert your existing simple SVG files. A VectorDrawable is specified through XML, with the format of the path data in the VectorDrawable using the same format as the specification for SVG paths. This allows us to reformat the XML in some SVG files to convert it into a VectorDrawable XML file.

If you are looking to use SVG files directly in your Android app take a look at this comparison of 3rd party solutions:

https://androidbycode.wordpress.com/2015/02/27/vector-graphics-in-android-part-1-svg/

Case Study: Converting SVG to VectorDrawable

The penguin in the image below (Attribution: Larry Ewing) has been rendered from a SVG image.  SVG images such as this can not be converted into a VectorDrawable as it uses LinearGradient in the original source.NewTux

Below is a rendered image of the flag of Ghana, it is also rendered from an SVG however as this image doesn’t have a gradient and only includes simple shapes, it is most suitable for conversion to a VectorDrawable. We will use this image as to illustrate how to convert an SVG into a VectorDrawable.

Flag of Ghana

SVG Images are described using the XML format. The above image contains 4 elements; three stripes and a star. The SVG XML source may appear as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg"
  width="450"
  height="300"
  id="svg2"
  version="1.1">
<rect
  width="450"
  height="300"
  fill="#006b3f"
  id="rect4" />
<rect
  width="450"
  height="200"
  fill="#fcd116"
  id="rect6" />
<rect
  width="450"
  height="100"
  fill="#ce1126"
  id="rect8" />
<path
  d="M225,100 L257.492,200 172.427,138.197H277.573L192.508,200z"
  fill="#000"
  id="path10" />
</svg>

If we want to create this same image as an Android VectorDrawable the first thing we need to do is ensure all items are described using paths. Remember only paths are supported in VectorDrawable.  To do this we convert each rect definition in the SVG image to use a path definition. The following XML shows the new path objects:


<path
  style="fill:#006b3f"
  d="m 0,0 450,0 0,300 -450,0 z" />
<path
  style="fill:#fcd116"
  d="m 0,0 450,0 0,200 -450,0 z" />
<path
  style="fill:#ce1126"
  d="m 0,0 450,0 0,100 -450,0 z" />

The next step is to convert the XML into Android’s new VectorDrawable format.  To do this we need to keep the path and color definitions but replace the formatting.  The XML should now look like this:


<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="450dp"
android:height="300dp"
android:viewportWidth="450"
android:viewportHeight="300">

<group>
  <path
    android:fillColor="#006b3f"
    android:pathData="M 0,0 l 450,0 0,300 -450,0 z" />
  <path
    android:fillColor="#fcd116"
    android:pathData="M 0,0 l 450,0 0,200 -450,0 z" />
  <path
    android:fillColor="#ce1126"
    android:pathData="M 0,0 l 450,0 0,100 -450,0 z" />
  <path
    android:fillColor="#000"
    android:pathData="M225,100 L257.492,200 172.427,138.197H277.573L192.508,200z" />
</group>
</vector>

This VectorDrawable file should be named with an .xml extension and placed in your drawables folder so it can be accessed in your Java source code or layout definition as you would with any other drawable.

The good news is you don’t need to step through this process by hand each time, there are tools to help you out. I have documented this process as it is important to know what and how to hand code the xml format as the conversion tools will not work all of the time so you may need to tweak the code from time to time.

To convert your SVG file to use only paths you can use Inkscape (The awesome open source SVG tool).  Open the SVG file in Inkscape and select all items you want to convert to a path.  Then from the Path menu select Object to path. If you use Adobe Illustrator then you need to convert the shapes into compound paths before saving the SVG.

To automate the conversion of an SVG file to the VectorDrawable format you can use the on-line open source svg2android tool.

VectorDrawable support pre Android 5.0

While the VectorDrawable class is only available on 5.0+ at this stage, an unofficial project has released support for older versions of Android.

Visit Mr. Vector on GitHub for the source code and usage instructions. You should note that the Vector XML used in this project is slightly different to the standard VectorDrawable specification. You can convert your simple SVG files to the Mr. Vector format using Svg2MrVector.

UPDATE MAY 2015: VectorDrawableCompat is in the process of being developed and may be added to the official support library. Once released there is no need to use the Mr. Vector project anymore, so keep an eye on the official Android Developers Blog for updates to the support library.

References:

Scalable Vector Graphics http://en.wikipedia.org/wiki/Scalable_Vector_Graphics

SVG Path Format http://www.w3.org/TR/SVG11/paths.html#PathData

VectorDrawable https://developer.android.com/reference/android/graphics/drawable/VectorDrawable.html

MrVector https://github.com/telly/MrVector

Inkscape https://inkscape.org/

“NewTux” by Larry Ewing. Licensed under Attribution via Wikimedia Commons – http://commons.wikimedia.org/wiki/File:NewTux.svg#/media/File:NewTux.svg

“Flag of Ghana”. Licensed under Public Domain via Wikimedia Commons – http://commons.wikimedia.org/wiki/File:Flag_of_Ghana.svg

2 Comments

Filed under Android SDK, Image