How does "?android:attr/activatedBackgroundIndicator" work?

Solution 1:

If you are in a forensic mood here is how to dig and find out what is going on.

android:background="?android:attr/activatedBackgroundIndicator"?

Intuitively this means set the background to some drawable.

But lets decompose this further to see how we get to our mysterious drawable.

To be precise it means "set the background attribute to what the attribute "activatedBackgroundIndicator" refers to in the current theme.

If you understand "refers to in the current theme" part, you have basically understood everything that is going on behind the covers.

Basically, activatedBackgroundIndicator is not an actual drawable but a reference to a drawable. So where is "activateBackgroundIndictor" attribute actually defined?

Its defined in your sdk directory in a file name attrs.xml. For example:

path_to_android_sdk/platforms/android-17/data/res/values/attrs.xml

If you open that file, you will the declaration as follows:

<attr name="activatedBackgroundIndicator" format="reference" />

attrs.xml is where you declare all the attributes that you are later going to use in your view xml. Note we are declaring the attribute and its type and not actually assigning a value here.

The actual value is assigned in themes.xml. This file is located at:

path_to_android_sdk/platforms/android-17/data/res/values/themes.xml

If you open that file, you will see the multiple definitions depending on what theme you are using. For example, here are the definitions for themes name Theme, Theme.Light, Theme.Holo, Theme.Holo.Light respectively:

<item name="activatedBackgroundIndicator">@android:drawable/activated_background</item>
<item name="activatedBackgroundIndicator">@android:drawable/activated_background_light</item>
<item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_dark</item>
<item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_light</item>

Now we have our mysterious drawables. If you pick the first one, it is defined in the drawable folder at:

path_to_android_sdk/platforms/android-17/data/res/drawable/activated_background.xml

If you open that file you will see the definition of the drawable which is important to understanding what is going on.

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_activated="true" android:drawable="@android:drawable/list_selector_background_selected" />
    <item android:drawable="@color/transparent" />
</selector>

Here we are defining a drawable with two states - default state is just transparent background and if the state is "state_activated" then our drawable is "list_selector_background_selected".

see this link for background information on on drawables and states.

"list_selector_background_selected" is a 9 patch png file that is located in the drawable-hdpi folder.

Now you can see why we defined activatedBackgroundIndicator as a reference rather than linking directly to the drawable file - it allows you to pick the right drawable depending on your theme.

Solution 2:

I wondered this as well at one point. A large amount of the Android resources seem to be like a black-box and can't see them directly. I may be missing them someplace, but I can't find them in the SDK source code. Here is what I do know.

  • android:background will take a drawable.
  • The syntax is in the style

    Must be a reference to another resource, in the form "@[+][package:]type:name" or to a theme attribute in the form "?[package:][type:]name"

In this case the ? signifies to look at a theme in package android and it is of type attr where the name is activatedBackgroundIndicator.

You should be able to access this in the code-behind with android.R.attr.activatedBackgroundIndicator as well.

A list of Android attr properties can be found at R.attr

  • activatedBackgroundIndicator is a defined drawable in Android 3.0+ as

    Drawable used as a background for activated items.

It's basically just a standard item defined in the OS. I can't seem to find in in the Android source, but here is a link to the documentation. activatedBackgroundIndicator

Solution 3:

This is a form of attaching a value from a theme. The value is technically not known during resource compilation because the theme values may not be known at that point. Instead the value is resolved at runtime based on the actual theme taken from (most commonly) ContextThemeWrapper.

This provides a way of reusing resource values. I'm not talking performance-wise here, but rather organization and maintenance-wise. The attribute acts as it were a variable with the promise that it will hold an actual value at runtime.

This approach also allows for greater customization - instead of hardcoding the value of e.g. window background drawable it gets the actual drawable from a theme, supplying a chosen attribute as the key. This lets you override the value for that attribute. You simply need to:

  1. Create your own theme (which is just a fancy name for a "style" resource), most commonly deriving from one of default themes.
  2. Supply your own value for the attribute in question.

The platform will automatically use your value provided that you have specified your theme for an activity or application. You do this like described in the question. The general syntax of theme-attribute references is described here: Referencing style attributes. You will also find an example and description of the whole mechanism there.

Edit

One thing that should be noted is the actual attribute names and their existence in various platform versions. It's fairly common for new attributes to be introduced in next platform versions - for example some were added in version 3.0 for the purpose of ActionBar styling.

You should treat attribute names as part of the API - in other words, they are part of the contract you are allowed to use. This is very similar to classes and their signatures - you use LocationManager class for the purpose of obtaining last device location because you know from some source (tutorials, reference, official guides, etc.) what's the purpose of this class. Similarly, the attribute names and their purpose are (sometimes well, sometimes miserably) defined in the Android Platform documentation.