[Galaxy S III Android Development] Goldie:
Coloring Stuff:

Text Colors

There is a ton of stuff in alliance that can be colored, from text to images or backgrounds. Text works by using the setTextColor method and images and backgrounds use setColorFilter to lay a color over the top of an image ot setBackgroundColor to fill the entire background. I will cover one of each in this section starting with text color. The 3 methods use similar code and text color is the easiest to start with.

So….you decide you want to change the color of some text using a picker. For this example I will use the dropdown date. Where do you start? As you probably know dropdown stuff is dealt with by SystemUI.apk. When you decompile that you are faced with a ton of smali files. The best way to start is to use a handy function in Notepad++ called “Find in Files” which will search for certain text within files. Funnily enough its under the Search menu at the top!!

In this case the first port of call would be to search for the obvious word “date”. This returns a ton of results and you should see an obvious file called DateView.smali. If your search doesn’t return much for your specific choice of text then you have a couple of options:

1) look in the layout xml and find the id for the view you want to change. Look the id up in public.xml and then search that using “Find in Files” again. If you are unsure of the text view id then use hierarchy viewer from the tools folder of the sdk which will show you all the views on your screen

2) look through the smali files manually for anything that sounds like it might contain your target

So you think you found the right smali. Open it and search for “setText(Ljava/lang/CharSequence;)V”. This will hopefully return a line something like this:

invoke-virtual {p0, v5}, Lcom/android/systemui/statusbar/policy/DateView;->setText(Ljava/lang/CharSequence;)V

Scroll up until you see the name of the method. This should give you a good idea if you have the right text. In this case that line was in .method private final updateClock()V which sounds about right!

What this line is doing is calling settext with the parameter Ljava/lang/CharSequence which is the date string. Invoke virtual calls the method and the bit in the brackets {p0, v5} is the date view (p0 means “this file”) and the string (v5). The v is a register. Registers are used to store things. A few lines up in the method you will see something similar to this:

invoke-virtual {v0, v9, v5}, Landroid/content/Context;->getString(I[Ljava/lang/Object;)Ljava/lang/String;

move-result-object v5

What that is doing is using getString to get the date and moving it into the register v5. This v5 is then used in our setText call.

So now we have identified our text view in the smali we can use setTextColor to change its color.

A bit of background is useful here. Color pickers do not act directly on any smali. Your phone has a database where it stores its settings. It is located in data/data/com.android.providers.settings/databases/settings.db. You can open it with Root Explorer and take a look. You will see a standard database with entries and values. What color picker code does is put an entry in this database with a “key” and a hex code. The smali then uses this key to look up the hex color it needs to set.

Now we need to add some code to look up that entry and return the color to the smali. There are 3 elements to this:

The ContentResolver

This is used to resolve the entry in the database. In order to use the content resolver we must put it into a register as we mentioned earlier. At the top of the method you will see .locals X where X is a number. This is the number of registers used in the method. So if it says .locals 5 there will be v0,v1,v2,v3 and v4. We need to add 3 to this value as we will be using 3 new registers. One for the resolver, one for the default color (in case there is no entry in the database it needs to have a color to set) and one for the key.

Now we need context in order to get the content resolver. There are a few ways to do this. A lot of files have a field called mContext. This can be used directly like this:

iget-object v5, p0, Lcom/android/systemui/statusbar/policy/BrightnessController;->mContext:Landroid/content/Context;

This is using iget-object to put mContext into v5. As mentioned earlier the p0 mean “this”.

The v5 should be the first of the new registers you added. So if previously .locals was 5 and you changed it to 8 then this would be v5 as v0 to v4 already exist. You can reuse registers but you can run into problems if it is needed further through the code so it is advisable to add new.

Alternatively, smali files whose .super is a view (look at the top of the smali for .super) like the date view we are working with here can use getcontext to get context like this:

invoke-virtual {p0}, Lcom/android/systemui/statusbar/policy/DateView;->getContext()Landroid/content/Context;

move-result-object v5

Now we have context we can use it to get the content resolver and put it into the register using this line:

invoke-virtual {v5}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;

move-result-object v5

The Key

Next we need the key that we want to look up in the database. This is as simple as :

const-string v6, "date_color"

This just puts the constant string “date_color” into v6. The text inside the “” can be anything you like but cannot have spaces and the key must match the picker key we will add later.

The Default Value

Next we need a default color for in case there is no entry in the database. For example on a fresh install or after a wipe. The value is hex but in reverse preceded with -0x so ICS blue 33b5e5 becomes -0xcc4a1a because 0 = F, 1 = E, 2 = D etc

0 = F

1 = E

2 = D

3 = C

4 = B

5 = A

6 = 9

7 = 8

8 = 7

9 = 6

A = 5

B = 4

C = 3

D = 2

E = 1

F = 0

We put that into our 3rd new register v7 using:

const v7, -0xcc4a1a

Now we have all the needed elements we can use them to return the color to the smali from the database using:

invoke-static {v5, v6, v7}, Landroid/provider/Settings$System;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I

move-result v5

This uses the getInt method with our parameters. I have colored them so you can see how the registers relate to the getInt method. V5 is the content resolver, v6 is the string and v7 is the integer of the color.

The resultant color from the database is then moved into v5. We can use v5 register again as we no longer need the content resolver.

The color from the database is now stored in v5. From the settext line we found earlier we can see that the text view is referred to as p0:

invoke-virtual {p0, v5}, Lcom/android/systemui/statusbar/policy/DateView;->setText(Ljava/lang/CharSequence;)V

The first item in the brackets is the text view. This wont be p0 in all cases. Its only p0 here because we are working with a smali that has a view as its super so the smali is effectively the text view. If working with something like ToggleSlider for example we may have something like:

invoke-virtual {v2, v3}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

So in this case the text view is in v2.

We can now use setTextColor on our date which is p0 with the color which we put in v5:

invoke-virtual {p0, v5}, Lcom/android/systemui/statusbar/policy/DateView;->setTextColor(I)V

The full code looks like this:

invoke-virtual {p0, v3}, Lcom/android/systemui/statusbar/policy/DateView;->setText(Ljava/lang/CharSequence;)V

invoke-virtual {p0}, Lcom/android/systemui/statusbar/policy/DateView;->getContext()Landroid/content/Context;

move-result-object v5

invoke-virtual {v5}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;

move-result-object v5

const-string v6, "date_color"

const v7, -0xcc4a1a

invoke-static {v5, v6, v7}, Landroid/provider/Settings$System;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I

move-result v5

invoke-virtual {p0, v5}, Lcom/android/systemui/statusbar/policy/DateView;->setTextColor(I)V

Oh and just so you know the big V at the end of lines like ;->setText(Ljava/lang/CharSequence;)V and ;->setTextColor(I)V means the method returns void or nothing.

Hopefully the apk will now compile and you can test the result. In order for something to change immediately you need observers but I wont go into that here. This will only change when the updateClock method runs. A reboot will also trigger it to update the color.

I know I have written a lot to take in here. But hopefully this will give you a good basic understanding of how methods are called with parameters in smali.

Next stop…..choosing the color!

Thanks to ficeto this part is REALLY easy!

Decompile the attached apk. You will find a file called preferences.xml in the xml folder. Open it with Notepad++. Each instance of this line will add another picker…

<com.ficeto.colorpicker.ColorPickerPreference android:title="Dropdown Date Color" android:key="date_color" android:summary="Select Color" android:dialogTitle="Select Color" />

Change the android:title to what you want your picker to be called and change android:key=“date_color” to whatever the key you used earlier was. So if your smali was....

const-string v6, "clock_color"

Then the android:key would be “clock_color”.

That’s it. Compile and push the apk or install as a system app and it will show in your app drawer as custom settings. Now go test your new mod!!

Any questions or problems please ask (with logs and files if possible) as its impossible to cover all eventualities in a guide.

:)