Tuesday, February 14, 2017

CircleCI: waiting for Android emulator with Google Play Services to fully boot

The standard circle-android wait-for-boot command works quite well for a vanilla Android image. However, when starting to use google_apis images (those which include Google Play Services, necessary to test e.g. Firebase-enabled apps), the performance of the emulator right after boot is very slow. Lots of services try to start up simultaneously, consuming all available CPU power, which is already not a lot on a free CircleCI container. This results in flaky tests because of timeouts, ANRs of the tested app because of insufficient CPU power, and crashes.

It might seem easy to resolve by saving a snapshot of a fully-booted Android emulator into CircleCI cache, but snapshots are proven to be unstable and crash the device upon load. It's not very convenient on a CI because makes the tests unnecessarily flaky.

One stable way to wait until everything has settled down is to monitor emulator logs with adb logcat command. Once the log spam goes down, it is very likely that most of the work is finished.

Below a small snippet that implements this kind of wait. As a bonus, it keeps logcat entries, which are actually related to the test, separate from that of the other services. Oh and don't forget to unlock the screen, as it might autolock while we wait, and interfere with your tests!

On an Android SDK 19 image the waiting time is about 6 minutes.

Monday, February 13, 2017

Vector Asset Studio and API level below 21

One way to add vector (i.e. slick regardless of the device screen resolution) Material icons to an Android application is to use built-in Vector Asset Studio.

The documentation mentions that if your minSdkVersion in build.gradle is below 21, the build will generate PNG for your supported screen resolutions (which may not be all possible resolutions in the wild, and also may increase the size of your APK). If you don’t want to have PNG you can add vectorDrawables.useSupportLibrary = true, which conveniently adds support for rendering vector graphics inside ImageView (and ImageButton etc).

Note that contrary to a popular myth, it is not necessary to update all layout xml files to use AppCompatImageView: only if in your Java code you inherit your own class from an ImageView (e.g. to extend its functionality), you should change it. But that doesn’t mean that you have to chase after each and every library: if a library isn’t used to display vector graphic (such as using de.hdodenhof:circleimageview to display logged in user’s photo) you don’t have to change it.

However, there’s still a small catch: if you forget to change android:src property name to app:srcCompat in at least one of your layouts, the application will crash (trying to expand the layout) and it may be very compilcated to find the reason. Watch out for new images or buttons that you add later (especially FloatingActionButton) as well.