One of my favorite new devices from Google is the Chromecast. I have 3 throughout my house, and one for travel. It’s great to have a cheap device that anyone can stream to.
I’ve also had the pleasure of integrating Google Cast support on several apps in my freelancing business. These are usually pretty cut and dry, but I recently had a client who needed a custom Google Cast action item which was one of many colors, depending on where you are in the app.
This makes for a really cool user experience, but isn’t exactly straight forward using the media support libraries. Below, I’ll walk you through the common solution to this, and how I was able to support truly custom colors throughout my app.
First, lets talk about how the Google Cast action item is displayed on the screen. You might think that the cast icon you see in the toolbar is simply another icon, but it’s much more than that.
Think about everything the cast icon has to do. It has to convey the state of the Google Cast connection, showing no icon when no Google Cast devices are available, showing a connected or disconnected icon, or showing an animated icon while connecting to a device. In addition to just showing current state, when the user taps the icon different things happen depending on that state.
From a development perspective, this is great, as I don’t want to spend my time worrying about all of these little details. Unfortunately, this also means that customizing that icon isn’t quite as easy as replacing a drawable.
Common Styling Mechanisms
Current solutions online tend to involve replacing the drawables that the support library uses draw the icon. This works in some cases, but falls apart when you need any more than two colors (light and dark). In the past I would have considered that a ridiculous requirement, but, particularly with the new Material design push, using color for your branding and identity adds a whole new dimension to your app. And in some apps, like sports apps, having sections of the app have entirely different color palettes really adds a personal touch to delight the user.
Android has great style and theme support built in, so why doesn’t this portion of the support library make better use of that?
The Support Library Implementation
If, like me, you immediately dive into the library source code to look for a good way to solve problems, you will have discovered some very promising comments, like this one from MediaRouteActionProvider.
1 2 3 4 5 6 7 8 9
Well that looks great, especially since the constructor for MediaRouteButton uses the style attribute
externalRouteEnabledDrawable to set the icon. That means that styling the icon is as simple as creating a different theme resource for each Activity that needs a different color, and overriding the
externalRouteEnabledDrawable value with our custom icon. Time to tell the client it’ll be a 15 minute fix and ship it, right?
After finding this to mysteriously not work as expected, I looked a little closer and noticed this:
super(MediaRouterThemeHelper.createThemedContext(context, false), attrs, defStyleAttr);. If you take a closer look at MediaRouterThemeHelper, you’ll find this:
1 2 3 4 5 6 7 8 9
It turns out that the theme is being set to one of two static values in the
MediaRouteButton constructor. In most cases this probably isn’t an issue, but in my case, where I need the icon to be more than one of two different colors, this just doesn’t work.
This explains why the existing solutions involve simply creating a drawable resource with the same name as the one referenced by these styles, so that Gradle will overwrite it when you build your app. This is a poor solution that doesn’t make good use of Android’s excellent styling support.
mRemoteIndicator has private access in the MediaRouteButton, my only course of action was to subclass the support library’s implementation, and replace every reference to that Drawable with my own. To take it a step further, and relieve some strain from my designers, I decided that setting the color in the style, as opposed to using a different drawable for every item, made a lot of sense.
The first step was to create a custom ThemeableMediaRouteButton. I simply subclassed the support library’s
MediaRouteButton, and replaced all references to
mRemoteIndicator drawable with my own. This basically amounted to a lot of copying and pasting.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Notice how I use a
setColorFilter on the drawable to color it using the
As we saw from the comments in
MediaRouteActionProvider, we know exactly what to change in our subclass to return our custom button.
1 2 3 4 5 6 7 8 9 10
As you can see, I’m relying on some styles from a styleable resource, so that needs to be declared in my attrs.xml file.
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
The last step is to use our custom ActionProvider in the cast menu, this is as simple as replacing the existing menu item with our custom implementation:
1 2 3 4 5 6 7 8 9 10 11
With that, you should now have a fully customized Google Cast icon to fit your app theme. To see the full solution, check out this Gist.
The Ideal Solution
Ideally the support library would make use of default values, instead of relying on hard coded styles, so that we could easily override the colors of the icon. That being said, I also understand that the support library has to work easily for 95% of users, so perhaps there are some edge cases that I’ve overlooked.
All in all, this may not be a super simple solution, but it’s a great way to delight users by going that extra mile to create a really unique experience.