Friday, November 23, 2012

How to make a well performing live wallpaper for Android.

Along the way of getting myself familiar with the landscape of all the things one needs to become a successful Android developer (and yes, that includes making money with Android - more on that later), I decided to get into a new and fun project: Frozen Window, a live wallpaper for Android. Last year, it was still an original, but then the week I wanted to release, someone else came up with the same idea. With the exact same title. Ah, competition, what would we do without you? And so it happened that I didn't release the wallpaper last year at all.

This year though, I thought it would be nice to have another attempt at a good release. It's almost December again, the source code was still waiting on my disk drive and it didn't make sense to keep it there while I've been spending quite some sleepless nights on it, so I started to shape up things for a release.

Because there still had to be at least one nice, new and original feature in the live wallpaper, I decided to spend some extra time on it by adding support for blurry backgrounds, to make the fake frosted window appear more realistic. But I didn't want to stop there. It had to be dynamic and support custom user images as well. And, oh boy.. did that open up a can of worms...

To sum up, here's a list of issues I got into:
  • Availability of memory on mobile devices is limited.
  • Availability of memory for a background app is even more limited.
  • The user can pick a custom image, including very (I mean, very!) large images. And they need to be blurred as well (being an expensive operation, that's not something you'd like to do for big images on a mobile device).
  • For realtime sharp to blurry images and the other way around, multiple images have to be saved, but the required amount of memory is usually not available.
  • Earlier versions of Android did not quickly release bitmap memory (usually later on, sometimes not at all), making things even harder.
  • Repainting of the wallpaper. Repainting multiple background bitmaps and moving elements is slow!
Luckily, the repainting part was quite easy to solve. The wallpaper used to be very time consuming to (re)draw and stutter a lot, but a temporary screen buffer solved things quickly here. Now, when you switch from one to another home screen, only this temp buffer will be moved around. With this in place, some small animations for droplets or finger painting would become much cheaper and the result would remain silky smooth. Without OpenGL.

As you can probably guess by now, memory was the biggest issue. For preprocessing the blurry image I used an algorithm to apply a separate vertical and horizontal gaussian blur, which looks much better than a simple box blur. A lens blur would have been nicer, but the image needs to be preprocessed each time when the user loads a new image (not when changing weather patterns), so the gaussian blurring made a nice tradeoff. In addition to that, the blurred image can be saved on a lower resolution and stretched when it needs to be drawn, which proofed to be a great optimisation in terms of memory usage while keeping the visual stuff interesting.

Another important thing to optimize is memory usage while running another app in front of the wallpaper. The (scaled) background image and temp buffer aren't visible here, so the use of memory can be largely cut out by temporarily releasing the Bitmap memory altogether. It appears that Android can quickly save Bitmaps to PNG image files within the internal memory (SD card would be slow), thus it became a possibility to do nice things while looking at the wallpaper and still have all memory available for real apps when switching to one of those.

So that would make up for a nicely behaving live wallpaper background, if it wouldn't be for Android to make things a little odd by adding the requirement of strategically recycling Bitmap memory where possible. Otherwise, the wallpaper would usually run out of memory by loading just two screen sized bitmaps.

While browsing the Google Play Store I've seen lots of live wallpapers that didn't do things "right". They did not release memory, or huge background images were used without even attempting to optimize them. Some of them just randomly black out because they're out of memory, others just crash. With this blog post, I'm hoping (even though I'm no expert by any means) to motivate other developers to take a better look at these things. I love the many great live wallpapers the Play Store has to offer, but have seen them many a times getting ruined (and uninstalled) by the memory usage. Dear fellow developers: please do check your memory and please do release as much of it as you can when you don't need to have these allocations. Thank you!

If you're curious to see the result: you can download the live wallpaper for free from the following location:
https://play.google.com/store/apps/details?id=com.stripeymilk.frozenwinlwp

A cookie goes to the person who finds the rather big programming mistake I made and tried to hide ;)

Got any questions on how to optimize your own live wallpaper? Feel free to post!

7 comments:

  1. Hi. It was a nice and beautiful wallpaper. However I'm not very fond of ads so will where be a payed for version?

    ReplyDelete
    Replies
    1. Hi Johan,

      Thanks!

      I'm currently working on an update that should fix some issues and will definitely make a paid version without ads to go along with it as well.

      If things go well, you should be able to download the new version (including paid) within a few days!

      Delete
    2. Hi again, I've just uploaded the paid version:
      https://play.google.com/store/apps/details?id=com.stripeymilk.frozenwinlwp_full

      Hope this helps!

      Delete
  2. The terms and conditions in the free version are horrendous! I've never seen a page like that without a "decline" button. :( I feel violated.

    ReplyDelete
    Replies
    1. Hello,

      I'd like to clear up a small misunderstanding. It is true that your info _can_ be sold to advertisers (in this case that would be LeadBolt), but this is definitely _not_ something that just happens upon installing or using the app. Selling of information only happens when _you_ yourself give in by doing things like signing up for some offer, even after agreeing with the T&Cs. This requires not only to click through the T&Cs, but further confirmation as well.

      There's also a "decline" button, it's just named differently ("Close"). For that I am sorry, but it's not my choice because the screen comes from the advertising network.

      Truth to be told, though, you are mostly right that this T&C screen is not user friendly and neither are the ads associated with it. Because of this, I've uploaded an update for the live wallpaper that removes all of the ads that (could) sell user information, including the associated permissions for the app and the T&C screen. The only ads left are Admob banners and Appbrain links to the Google Play Store. Both of these ad types are user friendly and don't have anything to do with selling of information.

      I hope you can forgive me for the bad ad types and that the recent update will be good enough to satisfy your wishes!

      Delete
    2. Removed 1 star rating, now 5 star. Thanks for clearing that up! I've bought the full version too. Keep up the awesome work, and thanks for this blog! A+ developer! One further q: do you plan to support Open GL for the new range of devices that support it? Im thinking the only thing missing is smooth screen transitions (very slightly choppy). Considering the resolution it's handling Im not surprised. I was thinking offloading the screen to a GL texture would allow for a much smoother transition for highend tabletd, and may also keep you from having to reload the wallpaper when the tablet is rotated. High marks, and thanks for taking the time to respond!

      Delete
    3. Wow, thank you for everything, that's very kind of you!

      About the smoothness: yes, totally agree. As I'm currently a very happy owner of a Nexus 7 as well, making things (including transitions) as smooth as possible for tablets is definitely a high target on my todo list. A smooth OS deserves to have smooth apps.

      And you've actually found the issue I was referencing to in the blog post (good find!). The app really needs either a threaded image builder or a faster Gaussian blur inside a pixel shader, among other things.

      Can't promise there will be support for OpenGL yet, but will definitely play with it to see if it's the right choice.

      I'll use the image cache (the one that holds a copy of both the sharp and blurry image) for screen rotations in the next update. That way, they at least won't have to be recalculated when turning the device around. Should make things in that area feel a lot more polished already.

      Thanks for thinking along!

      Delete