[Galaxy S II Android Development] Goldie:
Toggles

You have learnt how to get a value from the database creating a toggle is pretty straightforward. For this example I will use toggling the text on lidroid toggles but you can use this on anything from settings button in statusbar to things stopping auto scroll on toggles etc.

Again we start by finiding the method we need to mod. Look at the top of smali files for the field names. This may help you to find the item you wish to toggle. Method names will also help you find your place. In this example we can see in PowerButton smali there is a method called:

.method protected updateText()V

Obvious huh! It wont always be that easy to find so i will cover how to call something by it's ID later in this post.

In this method you can see that the text is set by calling the setText method. There are two ways to do this. The obvious thing to do is not to run this line so the text will not be set. This is the first way i will cover and it is the way that things are toggled such as ink effect or crt etc rather than showing/hiding things. I will get to that later. :)

TURNING THINGS ON/OFF

We need to read that value into our smali. This is done in exactly the same way as a color so if you are not sure please go back and read those posts.

This would be added the line before the setText call....

iget-object v3, p0, Lcom/alliance/systemui/quickpanel/PowerButton;->mView:Landroid/view/View;

invoke-virtual {v3}, Landroid/view/View;->getContext()Landroid/content/Context;

move-result-object v3

...dont forget to add to .locals if you are using a new register!! That gets us context so now we can...

const-string v4, "toggle_text"

const v5, 0x1

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

move-result v3

...which gets the value from the database which will be 1 or 0 for on/off and puts it into v3.

To toggle something we then act on that value. The if-eqz checks if a value is zero. So the next line would be:

if-eqz v3, :cond_skip_text

....as you can see, if v3 is zero then it goes to the condition skip_text.

All we need to do now is make a new cond called skip_text after the setText line so it effectively does just that.....skips the setText. Right before return-void put:

:cond_skip_text

That's it. All you have to do with a toggle to turn something on or off is skip the chunk of text that does what you want to stop. So as long as your new cond comes after it then it should work :)

SHOWING/HIDING

This works in exactly the same way as above but instead of skipping code you are going to use setVisibility(I)V method.

We have got the value from the database as we did before:

iget-object v3, p0, Lcom/alliance/systemui/quickpanel/PowerButton;->mView:Landroid/view/View;

invoke-virtual {v3}, Landroid/view/View;->getContext()Landroid/content/Context;

move-result-object v3

const-string v4, "toggle_text"

const v5, 0x1

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

move-result v3

if-nez v3, :cond_show_text

To hide something we must set visibility of the item to "gone". The value for this is 0x8. Visible is 0x1. If the database value returns 0 then the item is unchecked and so should be hidden. If it returns 1 then the item should be visible.

If the value from the database was 1 and the checkbox was ticked then you can use the value in v3 as the value for setVisibility. If it was 0 then the value needs to be set to 0x8 for "gone". We can put 0x8 into v4 here because the line will be skipped if the checkbox was checked:

const v3, 0x8

....now we add the new cond:

:cond_show_text

and invoke the set visibility which now has either 0x1 or 0x8 in it.

invoke-virtual {v1, v3}, Landroid/widget/TextView;->setVisibility(I)V

This tells the code to find the place labelled :goto_new so we add that straight after the code that sets visibility to shown. The full code would look like this....

iget-object v3, p0, Lcom/alliance/systemui/quickpanel/PowerButton;->mView:Landroid/view/View;

invoke-virtual {v3}, Landroid/view/View;->getContext()Landroid/content/Context;

move-result-object v3

const-string v4, "toggle_text"

const v5, 0x1

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

move-result v3

if-nez v3, :cond_show_text

const v4, 0x8

:cond_show_text

invoke-virtual {v1, v4}, Landroid/widget/TextView;->setVisibility(I)V

Thats it! :)

CALLING THINGS BY ID

Say you wanted to make a show/hide for the recents button that can be added to dropdown header. You can call it by it's public ID and then use setvisibility. Create a new method like you did for coloring images (refer to that guide if unsure), get a value from the database, test for non-zero and skip to cond. You can use mCcontext here from in Phonestatusbar:

.method Update_recents()V
.locals 6

iget-object v1, p0, Lcom/android/systemui/SystemUI;->mContext:Landroid/content/Context;

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

move-result-object v1

const-string v2, "recents_button"

const/4 v3, 0x1

invoke-static {v1, v2, v3}, Landroid/provider/Settings$System;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I

move-result v3

if-nez v3, :cond_1

const v3, 0x8

Now to get the image we can use findViewById method. In order to use it we need the parent view that contains the image. In Phonestatusbar you can get to most stuff by using the field mStatusBarWindow.

iget-object v4, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->mStatusBarWindow:Lcom/android/systemui/statusbar/phone/StatusBarWindowView;

Now we get the id of the image from public.xml and put it into a register:

const v5, 0x7f0d0014

....and then findViewById. This method expects an integer as a parameter which we have in v5...

invoke-virtual {v4, v5}, Lcom/android/systemui/statusbar/phone/StatusBarWindowView;->findViewById(I)Landroid/view/View;

move-result-object v4

Now we have the item we can setVisibility with the value in v3:

:cond_1

invoke-virtual {v4, v3}, Landroid/widget/LinearLayout;->setVisibility(I)V

In this case I used LinearLayout but you can use imageView or whatever depending what you are doing. The full method would look like this:

.method Update_recents()V
.locals 6

iget-object v1, p0, Lcom/android/systemui/SystemUI;->mContext:Landroid/content/Context;

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

move-result-object v1

const-string v2, "recents_button"

const/4 v3, 0x1

invoke-static {v1, v2, v3}, Landroid/provider/Settings$System;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I

move-result v3

if-nez v3, :cond_1

const/4 v3, 0x8

:cond_1

iget-object v5, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->mStatusBarWindow:Lcom/android/systemui/statusbar/phone/StatusBarWindowView;

const v6, 0x7f0d0014

invoke-virtual {v5, v6}, Lcom/android/systemui/statusbar/phone/StatusBarWindowView;->findViewById(I)Landroid/view/View;

move-result-object v4

invoke-virtual {v4, v3}, Landroid/widget/LinearLayout;->setVisibility(I)V

return-void

.end method

All we need to do now is to call the method. The best place for this is during makestatusbarview. I put it right after the settings button is set but you can put it in loads of places. It just invokes update_recents_button in p0 (this file):

iget-object v9, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->mSettingsButton:Landroid/widget/ImageView;

iget-object v10, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->mSettingsButtonListener:Landroid/view/View$OnClickListener;

invoke-virtual {v9, v10}, Landroid/widget/ImageView;->setOnClickListener(Landroid/view/View$OnClickListener;)V

[COLOR="Red"] invoke-virtual {p0}, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->update_recents_button()V[/COLOR]

Thats all for now :)