Working with Android Shape Drawables

Recently I’ve been working with Shape Drawables in Android and have found them to be quite handy to utilize for certain areas of your Android UI. Shape drawables are basic shapes that you can define using XML. They’re useful for many reasons:

  • They ‘just work’ with multiple device densities.
  • No need for bitmap resources, which saves space in your app.
  • They’re flexible to any screen size, so you don’t have to deal with those pesky 9-patches.

Over the past few months I’ve been responsible for implementing a redesign of the Notifications view in WordPress for Android. The design included special borders for when you are viewing a comment reply:

comment-reply-shape-drawable-background

The background for the comment needed to meet the following qualifications:

  • Contain a left margin so that the bar on the left appeared indented.
  • Have a thick border on the left, and a thin border at the bottom (but no border on the top and right side).
  • Work with multiple colors, since an unapproved comment will show a yellow background.

So I got to work on the shape drawable. After a few issues getting the borders to line up correctly, this is the XML that I ended up with:

comment_reply_background.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
        </shape>
    </item>
    <item
        android:left="@dimen/margin_extra_large"
        android:right="@dimen/margin_extra_large"
        android:top="@dimen/margin_large">
        <shape android:shape="rectangle">
            <solid android:color="@color/blue_light" />
            <padding
                android:bottom="1dp"
                android:left="20dp" />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
        </shape>
    </item>
</layer-list>

The most interesting part of the XML is the second item in the layer-list, which is what takes care of drawing the borders. Note the left, right and top margins that indent the borders. Next, a rectangle is drawn that includes a 1dp padding for the bottom border, and pads by 20dp on the left side which when accounted for @dimen/margin_extra_large (which is 16dp) will give us a visible 4dp border.

The last rectangle shape in the layer-list will fill in the rest of the non-bordered area in with white. Bingo!

Doing the yellow version for unapproved comments was as easy as swapping out the colors and removing the indent because it wasn’t needed for unapproved comments:

comment_reply_unapproved_background.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
        </shape>
    </item>
    <item
        android:left="@dimen/margin_extra_large">
        <shape android:shape="rectangle">
            <solid android:color="@color/orange" />
            <padding
                android:bottom="1dp"
                android:left="20dp" />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/orange_light" />
        </shape>
    </item>
</layer-list>

Shape drawables certainly don’t work for every element in your Android UI, but they are very handy when they do. Keep them in mind as you are constructing the UI in your app!

If you’re interested in seeing other examples of shape drawables, there’s plenty more in the WordPress for Android repo on GitHub.

Android Developers: Take the Low-End Device Challenge

As a developer I’ve always been lucky enough to have access to fast, high-end devices that provide the best experience that you can get with Android. Recently I’ve been using a low-end device to see what things are like on the other side of the fence, and I’ve learned quite a few lessons that I think can help me create better experiences for all users.

Firstly, here’s a wee bit of background. About a month ago, I had the unfortunate experience of dropping my Galaxy S4 on the pavement, shattering its screen and rendering it useless. I needed to replace the device quickly but getting a device during the mid-summer generally isn’t a great idea as a lot of new devices come out in the early fall.

I had a look at some analytics for Simplenote and saw that one of the more popular devices was the Moto G, a fairly new device that you can pick up for $199 off-contract.

Looks nice enough, right?
Looks nice enough, right?

I ordered one from Amazon and it arrived in two days (yay for Prime!). I popped my SIM and SD cards in and started using it right away. Overall the device felt fine at first, a bit clunky in size and weight but you can’t expect much at that price point. After using it for a few weeks now as my ‘daily driver’, it has really helped me get a better understanding of what pain points users of these low-end devices face.

Everything is Slower

The first thing I noticed was that this device was much slower at doing things I expected would be fast on most Android devices. The app switcher is especially slow, but there is also a huge delay when returning to the launcher from any app. It looks to me like the launcher is being restarted because due to lack of memory:

home-screen-delay
It takes 6 seconds to show the home screen after a home button tap.

I found myself leaving/uninstalling apps that were taking too long to load. As a user I find this frustrating, and it has motivated me to make sure that the apps I’m building can respond quickly, no matter what.

Crappy Camera Kills Creativity

I really love snapping photos from my phone so that I can share them with friends and family on my blog and Instagram. Since getting the Moto G, I haven’t done hardly any of that because the camera is completely awful.

IMG_20140818_174111
Focus? Nope. Sharpness? See problem with focus. Color reproduction? Awful.

Pictures are dull, usually out of focus, and overall just something that you wouldn’t want to share with anyone. Not even the fancy post-processing that Google+ Photos applies could save any of the photos. The only hope was to apply filters in Instagram to try and salvage the shots.

The camera was so bad that I simply stopped taking pictures. I wonder as a developer how many users of low-end devices are expecting filters in all of the apps they use because of the poor results they get from a stock camera app shot. I’m thinking some filters might be nice to add to WordPress for Android.

LTE Doesn’t Equal Fast

The G has the same LTE capabilities as my shattered S4, but comparing page loads in the browser were significantly slower in the Moto G. Even outside of the browser in other apps it felt like I was tapping my foot more than I used to waiting for content to load.

Optimizing network performance is a must if you want users of your app to stick around. Content placeholders (Like the ‘Fetching posts’ animation you see when first loading the WordPress Reader) seem even more important after using this device.

Take the Challenge!

If you are an Android developer, I challenge you to switch to a low-end device for at least two weeks. The Moto G isn’t even the lowest of the totem-pole. You can even pick up prepaid devices for around $40 if you are feeling brave! I promise you’ll learn a lot.

I’m looking forward to September arriving which will most likely be when I upgrade back up to a high-end device. The Moto X+1 is looking nice ;)

Have you already taken the challenge or use a mid to low range device? Let me know your thoughts!

Android Apps, GPS, and Google Play

Here’s a little tip if your Android app makes use of location based services but doesn’t require them. We were getting a few emails from users that the app wasn’t available in Google Play on their devices. Most of the devices were more obscure tablets and low-end phones that didn’t have GPS functionality.

It seemed to be related to the fact that our app uses GPS and/or network location in order to geotag posts. This is not a required feature so we had this line in our AndroidManifest.xml file:

<uses-feature
        android:name="android.hardware.location"
        android:required="false" />

Turns out this was not good enough, as you need to be a bit more detailed about what your app is using but is not required:

<uses-feature
        android:name="android.hardware.location"
        android:required="false" />
<uses-feature
        android:name="android.hardware.location.gps"
        android:required="false" />
<uses-feature
        android:name="android.hardware.location.network"
        android:required="false" />

After we published that change to the manifest file, the app was available to 160 more devices. Woo!