Friday, August 10, 2018

Dynamically changing Android app icons, for the rest of us (literally)

What

If you’re an android user, you’ve probably noticed how the Google Calendar app icon behaves:

There’s that little blue (#A7C5F8 for the skeptical) circle just sitting there, maybe signaling that there’s been something going on in the calendar app since the last time you have checked. This is not the story of that little blueish dot.

It is, however the story of the pair of digits that you can see in the center of the above image, which happen to mysteriously coincide with today’s date (July 29th).


Why

Google calendar is probably the best calendar app (or service) that you will find out there, because one, it syncs painlessly on all your devices, and two, it’s icon has those friendly little digits on that nice blue (a number of colors are involved including #3764D0) background which correctly shows the day of the month, whenever you take a look at it, and this fancy, mysterious little feature, is what I’m gonna try to figure out. I got sucked into this while trying to implement the exact same feature for Persian Calendar.

How

Alright so let’s get to work. I found a Google Calendar APK on the internet (I’m not putting it here because copyright and stuff) and decompiled it.
Next I tried something as simple as:
Please note: Code excerpts are incomplete. I have only copied the relevant parts.
Here’s an important part of the output:
Now here’s an important portion of that file:
Now let’s have a look at res/drawable-v26/logo_calendar_03_adaptive.xml:
Quite self explanatory right? Each of those resources are pngs containing exactly what you’re thinking: The adaptive_base:

And the calendar_date_03_adaptive:

After that, I took a dive into .smali files and also browsed the remains of the actual code after converting the apk to jar using dex2jar (I used jd-gui).
After hours of navigating the code I hadn’t found a single reference to any of these drawables that I mentioned above.
This is why I set the calendar app aside and went diving into pixel launcher’s source code. Here’s what you can find there in a class called DyanmicIconProvider:
And all of a sudden, everything makes sense if you take a glimpse on other parts of this file:
Note the action class paths.
I also found this c.class with barely even readable decompiled function/class names which is probably responsible for updating the face of the clock app (deskclock). Here are some interesting parts:
It is also interesting to note the difference between the design decisions in case of the calendar app and the deskclock app adaptive icons. To further understand this, let’s have a look at a part of launcher_clock.xml from deskclock:
And apart from this, there is no other reference to launcher_clock_second in the codebase.
Interestingly enough, we can see two very different solutions for a fairly similar problem: dynamic launcher icons.
Due to the complications of online text rendering, the authors have decided to pre-cook all the required icons in case of the calendar app. In the case of deskclock however, there would just be too many icons if they were to create the drawables beforehand, which has resulted in bringing this seemingly unrelated (as far as a launcher is concerned) logic into the code of the pixel launcher:

So

This is where my search ends. This is bad news for you if you wanted this fancy little feature in your app too. With the launcher handling all the workload here and not even providing an internal API, we are probably not likely to see this feature be available to public anytime soon.
Let’s go back to widgets.


Update 1: Thank you Ebrahim for finding this piece of code. This is most likely the actual source code of the part that I was investigating, from LIFE-OS, under com.google.android.apps.nexuslauncher;