[HOWTO] Enable 2G/3G Toggle from Statusbar/Launcher

Search This thread

hansip87

Senior Member
Jan 14, 2011
2,916
2,242
Jakarta
Hi again lads/gents,

Today i want to share to you how to enable 2G/3G Toggle feature that was commonly found on CyanogenMod and/or AOKP into your custom Android ROM. My code is based from Xperia Ray but shouldn't be too different between different phone version, because the concept in essence is to bring up the default toggle hidden in Settings menu to be switchable with external app or button.

The common problem when we try to implement this kind of mod is that Android system prevents system changes from outside system's apk, and added to the fact that the only apk allowed for Network Mode changes is the one with uid set as "phone" at its AndroidManifest.xml. When you thought it's a part of Settings.apk, actually Settings.apk only calls for Phone.apk Settings page.

So to do a workaround for that, you need to alter the phone.apk itself to be able to receive custom Broadcast from external apk and then switch the mode when required.

This is what you need:
1. Rooted phone
2. Phone.apk (or in my case SemcPhone.apk)
3. Basic Knowledge of Android Broadcast and Receiver concept
4. Custom toggle app/Status Bar Widget (in my case, i'll use lidroid's Power Button on Status Bar as a toggle utility)
5. Any APK Manager, preferably one that can be set to not decode resource file.

The steps are:
1. Place the Receiver files inside Phone.apk
2. Register the Receiver at runtime through Phone Application smali file
3. Compile Phone.apk
4. Implement Toggle mechanism for 2G/3G on Toggling app

1. Place the Receiver files inside Phone.apk
This is used as a Receiver of Broadcast Message from User App to start Toggling the Network Mode. There are 3 files you need to put on decompiled Phone.apk:
  1. smali\com\android\phone\NetworkModeReceiver.smali -> The Main Code
    Code:
    .class public Lcom/android/phone/NetworkModeReceiver;
    .super Landroid/content/BroadcastReceiver;
    .source "NetworkModeReceiver.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/MemberClasses;
        value = {
            Lcom/android/phone/NetworkModeReceiver$1;,
            Lcom/android/phone/NetworkModeReceiver$MyHandler;
        }
    .end annotation
    
    
    # static fields
    .field private static final TAG:Ljava/lang/String; = "NetworkModeReceiver"
    
    
    # instance fields
    .field private mHandler:Lcom/android/phone/NetworkModeReceiver$MyHandler;
    
    
    # direct methods
    .method public constructor <init>()V
        .locals 2
    
        .prologue
        .line 31
        invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
    
        new-instance v0, Lcom/android/phone/NetworkModeReceiver$MyHandler;
    
        const/4 v1, 0x0
    
        invoke-direct {v0, p0, v1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;-><init>(Lcom/android/phone/NetworkModeReceiver;Lcom/android/phone/NetworkModeReceiver$1;)V
    
        iput-object v0, p0, Lcom/android/phone/NetworkModeReceiver;->mHandler:Lcom/android/phone/NetworkModeReceiver$MyHandler;
    
        return-void
    .end method
    
    
    # virtual methods
    .method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
        .locals 5
        .parameter "context"
        .parameter "intent"
    
        const-string v0, "com.android.phone.CHANGE_NETWORK_MODE"
    
        .line 41
        invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
    
        move-result-object v1
    
        invoke-virtual {v1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    
        move-result v1
    
        if-eqz v1, :cond_0
    
        .line 43
        const-string v0, "com.android.phone.NEW_NETWORK_MODE"
    
        const v1, 0x0
    
        invoke-virtual {p2, v0, v1}, Landroid/content/Intent;->getIntExtra(Ljava/lang/String;I)I
    
        move-result v1
    
        .line 44
        new-instance v0, Ljava/lang/StringBuilder;
    
        invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
    
        const-string v3, "Receive Network Mode "
    
        invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    
        move-result-object v0
    
        invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
    
        move-result-object v0
    
        invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
    
        move-result-object v0
    
        sget-object v2, Lcom/android/phone/NetworkModeReceiver;->TAG:Ljava/lang/String;
    
        .line 45
        invoke-static {v2, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    
        .line 46
        invoke-virtual {p1}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;
    
        move-result-object v3
    
        const-string v2, "preferred_network_mode"
    
        invoke-static {v3, v2, v1}, Landroid/provider/Settings$Secure;->putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z
    
        iget-object v4, p0, Lcom/android/phone/NetworkModeReceiver;->mHandler:Lcom/android/phone/NetworkModeReceiver$MyHandler;
    
        .line 48
        const/4 v3, 0x1
    
        invoke-virtual {v4, v3}, Lcom/android/phone/NetworkModeReceiver$MyHandler;->obtainMessage(I)Landroid/os/Message;
    
        move-result-object v4
    
        .line 49
        invoke-static {}, Lcom/android/internal/telephony/PhoneFactory;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
    
        move-result-object v3
    
        invoke-interface {v3, v1, v4}, Lcom/android/internal/telephony/Phone;->setPreferredNetworkType(ILandroid/os/Message;)V
    
        :cond_0
        return-void
    .end method

    As you can see, We will use Intent named as "com.android.phone.CHANGE_NETWORK_MODE" with the Extras(or attribute as a layman's term) named as "com.android.phone.NEW_NETWORK_MODE"
  2. smali\com\android\phone\NetworkModeReceiver$1.smali -> Helper Class for MyHandler inner class.

    Code:
    .class synthetic Lcom/android/phone/NetworkModeReceiver$1;
    .super Ljava/lang/Object;
    .source "NetworkModeReceiver.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/android/phone/NetworkModeReceiver;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x1008
        name = null
    .end annotation
  3. smali\com\android\phone\NetworkModeReceiver$MyHandler.smali -> Does nothing, only used for Receiving a rollback message from system for UI element - which in this method is not quite usable. But it's there for compatibility reason.
    Code:
    .class Lcom/android/phone/NetworkModeReceiver$MyHandler;
    .super Landroid/os/Handler;
    .source "NetworkModeReceiver.java"
    
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingClass;
        value = Lcom/android/phone/NetworkModeReceiver;
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x2
        name = "MyHandler"
    .end annotation
    
    
    # instance fields
    .field final synthetic this$0:Lcom/android/phone/NetworkModeReceiver;
    
    
    # direct methods
    .method private constructor <init>(Lcom/android/phone/NetworkModeReceiver;)V
        .locals 0
        .parameter
    
        .prologue
        .line 628
        iput-object p1, p0, Lcom/android/phone/NetworkModeReceiver$MyHandler;->this$0:Lcom/android/phone/NetworkModeReceiver;
    
        invoke-direct {p0}, Landroid/os/Handler;-><init>()V
    
        return-void
    .end method
    
    .method synthetic constructor <init>(Lcom/android/phone/NetworkModeReceiver;Lcom/android/phone/NetworkModeReceiver$1;)V
        .locals 0
        .parameter "x0"
        .parameter "x1"
    
        .prologue
        .line 628
        invoke-direct {p0, p1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;-><init>(Lcom/android/phone/NetworkModeReceiver;)V
    
        return-void
    .end method
    
    .method private handleGetPreferredNetworkTypeResponse(Landroid/os/Message;)V
        .locals 9
        .parameter "msg"
    
        return-void
    .end method
    
    .method private handleSetPreferredNetworkTypeResponse(Landroid/os/Message;)V
        .locals 2
        .parameter "msg"
    
        return-void
    .end method
    
    .method private resetNetworkModeToDefault()V
        .locals 3
    
        .prologue
        return-void
    .end method
    
    
    # virtual methods
    .method public handleMessage(Landroid/os/Message;)V
        .locals 1
        .parameter "msg"
    
        .prologue
        .line 635
        iget v0, p1, Landroid/os/Message;->what:I
    
        packed-switch v0, :pswitch_data_0
    
        .line 643
        :goto_0
        return-void
    
        .line 637
        :pswitch_0
        invoke-direct {p0, p1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;->handleGetPreferredNetworkTypeResponse(Landroid/os/Message;)V
    
        goto :goto_0
    
        .line 640
        :pswitch_1
        invoke-direct {p0, p1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;->handleSetPreferredNetworkTypeResponse(Landroid/os/Message;)V
    
        goto :goto_0
    
        .line 635
        :pswitch_data_0
        .packed-switch 0x0
            :pswitch_0
            :pswitch_1
        .end packed-switch
    .end method
You need to download from the attachment and put them into smali\com\android\phone folder.

2. Register the Receiver at runtime through Phone Application smali file
Now you have the Receiver installed, you need to initiate and register the Receiver at phone app startup. There are 2 methods available:
  1. Add another line to AndroidManifest.xml -> The simplest one but not practical for system app of stock ROM since the AndroidManifest.xml requires to be signed to be functional.
  2. Alter PhoneApp.smali (it can be named something else->The point is you need Phone's Application main code to be altered) to register the receiver when it's called -> This is the way to go.

This is how you alter the PhoneApp.smali:
  1. Give a space to store the Receiver inside the PhoneApp.smali, named as mModeReceiver (Insert the Bold Line)
    Code:
    .field mLastPhoneState:Lcom/android/internal/telephony/Phone$State;
    
    .field private final mMediaButtonReceiver:Landroid/content/BroadcastReceiver;
    
    [B].field private final mModeReceiver:Landroid/content/BroadcastReceiver;[/B]
    
    .field private mNationalRoamingSettings:I
    
    .field private mNationalRoamingSupported:Z
  2. Initiate the Receiver Object and store it into the available space (Insert the Bold Line)
    Code:
    .method public constructor <init>()V
     .
     .
        .line 233
        new-instance v0, Lcom/android/phone/PhoneApp$PhoneAppBroadcastReceiver;
    
        const/4 v1, 0x0
    
        invoke-direct {v0, p0, v1}, Lcom/android/phone/PhoneApp$PhoneAppBroadcastReceiver;-><init>(Lcom/android/phone/PhoneApp;Lcom/android/phone/PhoneApp$1;)V
    
        iput-object v0, p0, Lcom/android/phone/PhoneApp;->mReceiver:Landroid/content/BroadcastReceiver;
    
    [B]    .line 236
        new-instance v0, Lcom/android/phone/NetworkModeReceiver;
    
        invoke-direct {v0}, Lcom/android/phone/NetworkModeReceiver;-><init>()V
    
        iput-object v0, p0, Lcom/android/phone/PhoneApp;->mModeReceiver:Landroid/content/BroadcastReceiver;[/B]
    
        .line 238
        new-instance v0, Lcom/android/phone/SemcMediaButtonBroadcastReceiver;
    
        invoke-direct {v0}, Lcom/android/phone/SemcMediaButtonBroadcastReceiver;-><init>()V
    
        iput-object v0, p0, Lcom/android/phone/PhoneApp;->mMediaButtonReceiver:Landroid/content/BroadcastReceiver;
      
        .
        .
    .end method
  3. Register the Receiver
    The following is to register the Receiver when the Phone app is created (onCreate). When registered, It will start listening to the phone activity so later it can receive a toggle message from toggle app. And not just any message that this receiver can read, We limit this Receiver to only hear a filtered Intent with name of "com.android.phone.CHANGE_NETWORK_MODE" as explained above.

    Code:
    .method public onCreate()V
        .
        .
        .line 630
        const-string v1, "com.android.phone.intent.ACTION_DATA_TRAFFIC_SWITCH"
    
        invoke-virtual {v0, v1}, Landroid/content/IntentFilter;->addAction(Ljava/lang/String;)V
    
        .line 631
        iget-object v1, p0, Lcom/android/phone/PhoneApp;->mReceiver:Landroid/content/BroadcastReceiver;
    
        invoke-virtual {p0, v1, v0}, Lcom/android/phone/PhoneApp;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;
    
    [B]    .line 633
        new-instance v0, Landroid/content/IntentFilter;
    
        const-string v1, "com.android.phone.CHANGE_NETWORK_MODE"
    
        invoke-direct {v0, v1}, Landroid/content/IntentFilter;-><init>(Ljava/lang/String;)V
    
        iget-object v1, p0, Lcom/android/phone/PhoneApp;->mModeReceiver:Landroid/content/BroadcastReceiver;
    
        invoke-virtual {p0, v1, v0}, Lcom/android/phone/PhoneApp;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;[/B]
    
        .line 638
        new-instance v0, Landroid/content/IntentFilter;
    
        const-string v1, "android.intent.action.MEDIA_BUTTON"
    
        invoke-direct {v0, v1}, Landroid/content/IntentFilter;-><init>(Ljava/lang/String;)V
    
        .line 642
        const/16 v1, 0x3e0
    
        invoke-virtual {v0, v1}, Landroid/content/IntentFilter;->setPriority(I)V
    
        .line 645
        iget-object v1, p0, Lcom/android/phone/PhoneApp;->mMediaButtonReceiver:Landroid/content/BroadcastReceiver;
    
        invoke-virtual {p0, v1, v0}, Lcom/android/phone/PhoneApp;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;
    
        .
        .
    .end method

3. Compile the Phone.apk
You need to compile the phone app back. As it was with Sony's code, it was clear that i need to decompile ONLY the source, but not the resource part of the apk because when compiled back it will be broken. So try to decompile it at the source only.

4. Implement the Toggle App to send a Broadcast Intent
Now this is the part where you have to determine what mode is supported by your phone. This is the value of Android supported value that will be sent as a Broadcast Intent:

Code:
     int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */

     int NETWORK_MODE_GSM_ONLY       = 1; /* GSM only */

     int NETWORK_MODE_WCDMA_ONLY     = 2; /* WCDMA only */

     int NETWORK_MODE_GSM_UMTS       = 3; /* GSM/WCDMA (auto mode, according to PRL) AVAILABLE Application Settings menu*/

     int NETWORK_MODE_CDMA           = 4; /* CDMA and EvDo (auto mode, according to PRL) AVAILABLE Application Settings menu*/

     int NETWORK_MODE_CDMA_NO_EVDO   = 5; /* CDMA only */

     int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */

     int NETWORK_MODE_GLOBAL         = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) AVAILABLE Application Settings menu*/

So if your phone only supports WCDMA(3G) as max, you should use value 0,1, and 2 only.

The following is my 2G/3G simple toggle mode from Lidroid's Status Bar Widget code. You should adapt the code yourself if you're using something else. But as a guide, this is the logic:
  1. create a new Intent with name "com.android.phone.CHANGE_NETWORK_MODE"
  2. take current mode
  3. Apply the next value into the newly created Intent as Extra named "com.android.phone.NEW_NETWORK_MODE"
  4. Broadcast the Intent to the System (which will be read by Phone.apk).

The logic above can be observed in the method toggleState() on the following code:

Code:
.class public Lcom/lidroid/systemui/quickpanel/NetworkModeButton;
.super Lcom/lidroid/systemui/quickpanel/PowerButton;
.source "NetworkModeButton.java"


# static fields
.field private static final CM_MODE_3GSM_ONLY:I = 0x1

.field private static final CM_MODE_3G_ONLY:I = 0x0

.field private static final CM_MODE_3G_PREFERRED:I = 0x2

.field private static final OBSERVED_URIS:Ljava/util/List; = null
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "Ljava/util/List",
            "<",
            "Landroid/net/Uri;",
            ">;"
        }
    .end annotation
.end field

.field private static final TAG:Ljava/lang/String; = "NetworkModeButton"


# direct methods
.method static constructor <clinit>()V
    .locals 3

    .prologue
    const/16 v2, 0x0

    .line 21
    new-instance v0, Ljava/util/ArrayList;

    invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V

    sput-object v0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->OBSERVED_URIS:Ljava/util/List;

    .line 23
    sget-object v0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->OBSERVED_URIS:Ljava/util/List;

    const-string v1, "preferred_network_mode"

    invoke-static {v1}, Landroid/provider/Settings$Secure;->getUriFor(Ljava/lang/String;)Landroid/net/Uri;

    move-result-object v1

    invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    return-void
.end method

.method public constructor <init>()V
    .locals 2

    .prologue
    .line 43
    invoke-direct {p0}, Lcom/lidroid/systemui/quickpanel/PowerButton;-><init>()V

    const-string v0, "toggleNetworkMode"

    iput-object v0, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mType:Ljava/lang/String;

    return-void
.end method

.method private static getCurrentNetworkMode(Landroid/content/Context;)I
    .locals 3
    .parameter "context"

    .prologue
    .line 167
    const/16 v0, 0x0

    .line 169
    .local v0, state:I
    :try_start_0
    invoke-virtual {p0}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;

    move-result-object v1

    const-string v2, "preferred_network_mode"

    invoke-static {v1, v2}, Landroid/provider/Settings$Secure;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;)I
    :try_end_0
    .catch Landroid/provider/Settings$SettingNotFoundException; {:try_start_0 .. :try_end_0} :catch_0

    move-result v0

    .line 173
    :goto_0
    return v0

    .line 171
    :catch_0
    move-exception v1

    goto :goto_0
.end method


# virtual methods
.method protected getObservedUris()Ljava/util/List;
    .locals 1
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "()",
            "Ljava/util/List",
            "<",
            "Landroid/net/Uri;",
            ">;"
        }
    .end annotation

    .prologue
    .line 163
    sget-object v0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->OBSERVED_URIS:Ljava/util/List;

    return-object v0
.end method

.method protected getText()I
    .locals 1

    .prologue
    .line 93
    const v0, 0x7f08007d

    return v0
.end method

.method protected handleLongClick()Z
    .locals 3

    .prologue
    .line 126
    new-instance v0, Landroid/content/Intent;

    const-string v1, "android.intent.action.MAIN"

    invoke-direct {v0, v1}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V

    .line 127
    .local v0, intent:Landroid/content/Intent;
    const-string v1, "com.android.phone"

    const-string v2, "com.android.phone.Settings"

    invoke-virtual {v0, v1, v2}, Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;

    .line 128
    const/high16 v1, 0x1000

    invoke-virtual {v0, v1}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;

    .line 129
    iget-object v1, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;

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

    move-result-object v1

    invoke-virtual {v1, v0}, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V

    .line 130
    const/4 v1, 0x1

    return v1
.end method

[B].method protected toggleState()V
    .locals 5

    .prologue
    const/4 v4, 0x2

    const/4 v1, 0x1

    const-string v2, "com.android.phone.CHANGE_NETWORK_MODE"

    .line 83
    iget-object v3, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;

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

    move-result-object v3

    .line 84
    .local v3, context:Landroid/content/Context;
    invoke-static {v3}, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->getCurrentNetworkMode(Landroid/content/Context;)I

    move-result v0

    .line 85
    add-int v0, v0, v1

    if-le v0, v4, :cond_0

    const/4 v0, 0x0

    .line 86
    :cond_0
    new-instance v4, Landroid/content/Intent;

    invoke-direct {v4, v2}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V

    const-string v2, "com.android.phone.NEW_NETWORK_MODE"

    invoke-virtual {v4, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;I)Landroid/content/Intent;

    invoke-virtual {v3, v4}, Landroid/content/Context;->sendBroadcast(Landroid/content/Intent;)V

    return-void
.end method[/B]

.method protected updateState()V
    .locals 3

    .line 90
    iget-object v1, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;

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

    move-result-object v1

    invoke-static {v1}, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->getCurrentNetworkMode(Landroid/content/Context;)I

    move-result v0

    .line 92
    const v1, 0x0

    if-ne v0, v1, :cond_0

    const v2, 0x7f0200d4

    iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mIcon:I

    const/4 v2, 0x1

    iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mState:I

    .line 93
    :goto_0
    return-void

    .line 94
    :cond_0
    const v1, 0x1

    if-ne v0, v1, :cond_1

    const v2, 0x7f0200d3

    iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mIcon:I

    const/4 v2, 0x2

    iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mState:I

    goto :goto_0

    .line 96
    :cond_1
    const v2, 0x7f0200d5

    iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mIcon:I

    const/4 v2, 0x1

    iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mState:I

    goto :goto_0
.end method

Or you could download from attachment if you happen to use Lidroid's code too.
Compile back your apk and voila! ;)

Hope this tutorial helps :) Any question, please reply and i'll help as best as i can. :)
 

Attachments

  • NetworkModeReceiverPacket.zip
    2.1 KB · Views: 1,441
  • NetworkModeButton.rar
    1.5 KB · Views: 1,033
Last edited:

zcop

Senior Member
Nov 17, 2011
282
505
Hanoi
First - Thank you, very good job

Second, i would like to add new receiver in Androidmanifest.xml
so is that correct
Code:
	<receiver android:name="NetworkModeReceiver">
            <intent-filter>
                <action android:name="com.android.phone.CHANGE_NETWORK_MODE" />
                <action android:name="com.android.phone.NEW_NETWORK_MODE" />
            </intent-filter>
        </receiver>

is it enough?

-------------------------------------------

Yes found it enoughs
 
Last edited:
  • Like
Reactions: janarthanan.v

hansip87

Senior Member
Jan 14, 2011
2,916
2,242
Jakarta
First - Thank you, very good job

Second, i would like to add new receiver in Androidmanifest.xml
so is that correct
Code:
	<receiver android:name="NetworkModeReceiver">
            <intent-filter>
                <action android:name="com.android.phone.CHANGE_NETWORK_MODE" />
                <action android:name="com.android.phone.NEW_NETWORK_MODE" />
            </intent-filter>
        </receiver>

is it enough?

-------------------------------------------

Yes found it enoughs
Well if you can sign it at AndroidManifest level, yes you don't have to edit the smali.
 
  • Like
Reactions: janarthanan.v

zozor

Senior Member
Jun 30, 2011
658
35
Wuhan
Does it work with another devices whose get the world phone capabilities ?
Thanks
 

hansip87

Senior Member
Jan 14, 2011
2,916
2,242
Jakarta
Does it work with another devices whose get the world phone capabilities ?
Thanks

Yes it will, you just have to know what's the integer number that represents the code of the network that is available to be used. IIRC you can look for it on the Phone.apk/res/values/arrays.xml

This's useful thread. Can we use 3G only mode using this method?
Yes, it was designed to switch from 3G-3G/2G-2G (0-1-2) If you like to change the sequence, you need to look at the updateState method above and change the basic sequencing act with additional conditional if.
 

zozor

Senior Member
Jun 30, 2011
658
35
Wuhan
Yes it will, you just have to know what's the integer number that represents the code of the network that is available to be used. IIRC you can look for it on the Phone.apk/res/values/arrays.xml

I looked out the values on the Phone.apk/res/values/arrays.xml it's really different ,that's may cause the first one come from the stock sense 3.6 and another for a port of sense 4.
My goal is to mod the sense phone.apk to get world capabilities enable .
Other one tell me that if the phone.apk is mod I should also mod the framework.telephony ,isnt it? But at this stage I am a kind of confuse.

Back to my question ,in the arrays.xml ,some string name are apktool,is it a bug ?
In the Sense 4, the arrays invoke use this form @com.htc:string/st_automatic,while the sense 3.6 xml invoke a string. Is it where the issue is located ?

I also notice that the public.xml (completely ) and the string.xml are different .

Thanks enough for your help with the xml , I can have a big idea now of want the smali does ...
 

hansip87

Senior Member
Jan 14, 2011
2,916
2,242
Jakarta
I looked out the values on the Phone.apk/res/values/arrays.xml it's really different ,that's may cause the first one come from the stock sense 3.6 and another for a port of sense 4.
My goal is to mod the sense phone.apk to get world capabilities enable .
Other one tell me that if the phone.apk is mod I should also mod the framework.telephony ,isnt it? But at this stage I am a kind of confuse.

Back to my question ,in the arrays.xml ,some string name are apktool,is it a bug ?
In the Sense 4, the arrays invoke use this form @com.htc:string/st_automatic,while the sense 3.6 xml invoke a string. Is it where the issue is located ?

I also notice that the public.xml (completely ) and the string.xml are different .

Thanks enough for your help with the xml , I can have a big idea now of want the smali does ...

Well, actually the apk will decide based on phone's hardware configuration, so this mod is not a smart one unfortunately (aka, only playing statically between 0-1-2 regardless on what configuration), so you have to research further to find out how the phone takes the correct array. but since it is per phone mod so i haven't research it further to enable such technique.

In my Phone app, the used array values inside /res/values/array.xml are the following:
Code:
<string-array name="clh_preferred_network_mode_values"> // this is the real value for each radio box inside Network Mode checkboxes inside Settings.
        <item>2</item>
        <item>1</item>
        <item>0</item>
    </string-array>
.
.
.
    <string-array name="clh_preferred_network_mode_choices"> //This one is used for Settings app display name for each gsm network.
        <item>WCDMA only</item>
        <item>GSM only</item>
        <item>WCDMA (preferred)/GSM</item>
    </string-array>

Those arrays correspond to my setting like this:



That is the value shown when i select the mode through Android setting menu, so if you can find the array containing the same label with the one on your Settings menu, just take the value that corresponds to that label (e.g. the above sample tells me that no 2 corresponds to WCDMA only, 1 to GSM only, and so on), and then thru NetworkModeButton.smali, you just have to change the logic from normal sequence (0-1-2-0-1-2-....) like i did to anything that fits your need. :)
 
Last edited:

zozor

Senior Member
Jun 30, 2011
658
35
Wuhan
This is a portion part of the array code
Code:
<string-array name="clir_display_values">
        <item>Network default</item>
        <item>Hide number</item>
        <item>Show number</item>
    </string-array>
    <string-array name="clir_values">
        <item>DEFAULT</item>
        <item>HIDE</item>
        <item>SHOW</item>
    </string-array>
    <string-array name="preferred_network_mode_choices">
        <item>Global</item>
        <item>EvDo only</item>
        <item>CDMA w/o EvDo</item>
        <item>CDMA / EvDo auto</item>
        <item>GSM / WCDMA auto</item>
        <item>WCDMA only</item>
        <item>GSM only</item>
        <item>GSM / WCDMA preferred</item>
    </string-array>
    <string-array name="preferred_network_mode_values">
        <item>7</item>
        <item>6</item>
        <item>5</item>
        <item>4</item>
        <item>3</item>
        <item>2</item>
        <item>1</item>
        <item>0</item>
    </string-array>

But it doesn't seems to work when I am on CDMA mode . Can load this setting or the same picture as you .
And the sim-card can't be read.
I have attache the two arrays Sense4 & sense 3.6 with the word phone capacities enable,if you can help me to sort out this issue.
 

Attachments

  • arrays.zip
    56.1 KB · Views: 34

hansip87

Senior Member
Jan 14, 2011
2,916
2,242
Jakarta
This is a portion part of the array code
Code:
<string-array name="clir_display_values">
        <item>Network default</item>
        <item>Hide number</item>
        <item>Show number</item>
    </string-array>
    <string-array name="clir_values">
        <item>DEFAULT</item>
        <item>HIDE</item>
        <item>SHOW</item>
    </string-array>
    <string-array name="preferred_network_mode_choices">
        <item>Global</item>
        <item>EvDo only</item>
        <item>CDMA w/o EvDo</item>
        <item>CDMA / EvDo auto</item>
        <item>GSM / WCDMA auto</item>
        <item>WCDMA only</item>
        <item>GSM only</item>
        <item>GSM / WCDMA preferred</item>
    </string-array>
    <string-array name="preferred_network_mode_values">
        <item>7</item>
        <item>6</item>
        <item>5</item>
        <item>4</item>
        <item>3</item>
        <item>2</item>
        <item>1</item>
        <item>0</item>
    </string-array>

But it doesn't seems to work when I am on CDMA mode . Can load this setting or the same picture as you .
And the sim-card can't be read.
I have attache the two arrays Sense4 & sense 3.6 with the word phone capacities enable,if you can help me to sort out this issue.
Umm, are you sure you have all those 8 choices on Settings menu?
 

zozor

Senior Member
Jun 30, 2011
658
35
Wuhan
I don't have it , lol .
When I am on cdma , I have any of them. The option is unavailable
 

mewzik86

Senior Member
Aug 13, 2010
91
32
Redmi Note 10 Pro
Google Pixel 7
Force closing phone.apk

@hansip87
Hi, Thanks alot for posting this tutorial. I have been trying this mod on the samsung galaxy beam (gt-i8530), but have not had any luck. I get a force close of the phone.apk upon booting into the system. My phone runs the stock touchwiz4 interface, and i have successfully deodexed the system and implemented the 14 toggle mod by lidroid. The error i get in my logcat is as follows:

W/dalvikvm( 1949): VFY: rejecting opcode 0x59 at 0x000f
W/dalvikvm( 1949): VFY: rejected Lcom/android/phone/PhoneApp;.<init> ()V
W/dalvikvm( 1949): Verifier rejected class Lcom/android/phone/PhoneApp;
W/dalvikvm( 1949): Class init failed in newInstance call (Lcom/android/phone/PhoneApp;)
W/dalvikvm( 1949): threadid=1: thread exiting with uncaught exception (group=0x4001e578)
E/AndroidRuntime( 1949): FATAL EXCEPTION: main
E/AndroidRuntime( 1949): java.lang.VerifyError: com.android.phone.PhoneApp

Can you please point me in the right direction?

I get no faults from the systemui.apk, but no options appear in the quickpanelsettings.apk for the network mode, so do I have to modify the quickpanelsettings.apk that comes with the lidroid mod?
 

Qeemi

Senior Member
May 31, 2012
512
335
Rieti
Ok.but now I need the icons for the toggle in statusbar right? How many? 3 right? I've WCDMA GSM GSM-WCDMA. So I need 3 icons. Names of the icons?
 

hansip87

Senior Member
Jan 14, 2011
2,916
2,242
Jakarta
@hansip87
Hi, Thanks alot for posting this tutorial. I have been trying this mod on the samsung galaxy beam (gt-i8530), but have not had any luck. I get a force close of the phone.apk upon booting into the system. My phone runs the stock touchwiz4 interface, and i have successfully deodexed the system and implemented the 14 toggle mod by lidroid. The error i get in my logcat is as follows:

W/dalvikvm( 1949): VFY: rejecting opcode 0x59 at 0x000f
W/dalvikvm( 1949): VFY: rejected Lcom/android/phone/PhoneApp;.<init> ()V
W/dalvikvm( 1949): Verifier rejected class Lcom/android/phone/PhoneApp;
W/dalvikvm( 1949): Class init failed in newInstance call (Lcom/android/phone/PhoneApp;)
W/dalvikvm( 1949): threadid=1: thread exiting with uncaught exception (group=0x4001e578)
E/AndroidRuntime( 1949): FATAL EXCEPTION: main
E/AndroidRuntime( 1949): java.lang.VerifyError: com.android.phone.PhoneApp

Can you please point me in the right direction?

I get no faults from the systemui.apk, but no options appear in the quickpanelsettings.apk for the network mode, so do I have to modify the quickpanelsettings.apk that comes with the lidroid mod?

The error might be caused by the incorrect placed code on the PhoneApp.smali. Maybe the incorrect named class inside there.

To make it able to be displayed on QuickPanelSettings.apk, yes you need to add a line or two there. I forgot which smali, but you'll find it fast by searching for other button's registration (read:written) code on the smalis.
 

TheDelta

Senior Member
Nov 5, 2012
245
55
Using Manual Intents

Hi,

I modified the Phone.apk for my RAZR xt910, and since it has not crashed or anything, i take that i did everything right.
But i dont wish to use the status bar toggle, instead i want to trigger it through broadcast intent through apps like LLama or Manual intent shortcuts.
Will it work for the intents? and if yes then can you tell me how i should write the intents. I am new to all of this so didnt know how to check it using the intents.

Thanks in advance
 

Top Liked Posts

  • There are no posts matching your filters.
  • 25
    Hi again lads/gents,

    Today i want to share to you how to enable 2G/3G Toggle feature that was commonly found on CyanogenMod and/or AOKP into your custom Android ROM. My code is based from Xperia Ray but shouldn't be too different between different phone version, because the concept in essence is to bring up the default toggle hidden in Settings menu to be switchable with external app or button.

    The common problem when we try to implement this kind of mod is that Android system prevents system changes from outside system's apk, and added to the fact that the only apk allowed for Network Mode changes is the one with uid set as "phone" at its AndroidManifest.xml. When you thought it's a part of Settings.apk, actually Settings.apk only calls for Phone.apk Settings page.

    So to do a workaround for that, you need to alter the phone.apk itself to be able to receive custom Broadcast from external apk and then switch the mode when required.

    This is what you need:
    1. Rooted phone
    2. Phone.apk (or in my case SemcPhone.apk)
    3. Basic Knowledge of Android Broadcast and Receiver concept
    4. Custom toggle app/Status Bar Widget (in my case, i'll use lidroid's Power Button on Status Bar as a toggle utility)
    5. Any APK Manager, preferably one that can be set to not decode resource file.

    The steps are:
    1. Place the Receiver files inside Phone.apk
    2. Register the Receiver at runtime through Phone Application smali file
    3. Compile Phone.apk
    4. Implement Toggle mechanism for 2G/3G on Toggling app

    1. Place the Receiver files inside Phone.apk
    This is used as a Receiver of Broadcast Message from User App to start Toggling the Network Mode. There are 3 files you need to put on decompiled Phone.apk:
    1. smali\com\android\phone\NetworkModeReceiver.smali -> The Main Code
      Code:
      .class public Lcom/android/phone/NetworkModeReceiver;
      .super Landroid/content/BroadcastReceiver;
      .source "NetworkModeReceiver.java"
      
      
      # annotations
      .annotation system Ldalvik/annotation/MemberClasses;
          value = {
              Lcom/android/phone/NetworkModeReceiver$1;,
              Lcom/android/phone/NetworkModeReceiver$MyHandler;
          }
      .end annotation
      
      
      # static fields
      .field private static final TAG:Ljava/lang/String; = "NetworkModeReceiver"
      
      
      # instance fields
      .field private mHandler:Lcom/android/phone/NetworkModeReceiver$MyHandler;
      
      
      # direct methods
      .method public constructor <init>()V
          .locals 2
      
          .prologue
          .line 31
          invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
      
          new-instance v0, Lcom/android/phone/NetworkModeReceiver$MyHandler;
      
          const/4 v1, 0x0
      
          invoke-direct {v0, p0, v1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;-><init>(Lcom/android/phone/NetworkModeReceiver;Lcom/android/phone/NetworkModeReceiver$1;)V
      
          iput-object v0, p0, Lcom/android/phone/NetworkModeReceiver;->mHandler:Lcom/android/phone/NetworkModeReceiver$MyHandler;
      
          return-void
      .end method
      
      
      # virtual methods
      .method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
          .locals 5
          .parameter "context"
          .parameter "intent"
      
          const-string v0, "com.android.phone.CHANGE_NETWORK_MODE"
      
          .line 41
          invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
      
          move-result-object v1
      
          invoke-virtual {v1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
      
          move-result v1
      
          if-eqz v1, :cond_0
      
          .line 43
          const-string v0, "com.android.phone.NEW_NETWORK_MODE"
      
          const v1, 0x0
      
          invoke-virtual {p2, v0, v1}, Landroid/content/Intent;->getIntExtra(Ljava/lang/String;I)I
      
          move-result v1
      
          .line 44
          new-instance v0, Ljava/lang/StringBuilder;
      
          invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
      
          const-string v3, "Receive Network Mode "
      
          invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
      
          move-result-object v0
      
          invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
      
          move-result-object v0
      
          invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
      
          move-result-object v0
      
          sget-object v2, Lcom/android/phone/NetworkModeReceiver;->TAG:Ljava/lang/String;
      
          .line 45
          invoke-static {v2, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
      
          .line 46
          invoke-virtual {p1}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;
      
          move-result-object v3
      
          const-string v2, "preferred_network_mode"
      
          invoke-static {v3, v2, v1}, Landroid/provider/Settings$Secure;->putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z
      
          iget-object v4, p0, Lcom/android/phone/NetworkModeReceiver;->mHandler:Lcom/android/phone/NetworkModeReceiver$MyHandler;
      
          .line 48
          const/4 v3, 0x1
      
          invoke-virtual {v4, v3}, Lcom/android/phone/NetworkModeReceiver$MyHandler;->obtainMessage(I)Landroid/os/Message;
      
          move-result-object v4
      
          .line 49
          invoke-static {}, Lcom/android/internal/telephony/PhoneFactory;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
      
          move-result-object v3
      
          invoke-interface {v3, v1, v4}, Lcom/android/internal/telephony/Phone;->setPreferredNetworkType(ILandroid/os/Message;)V
      
          :cond_0
          return-void
      .end method

      As you can see, We will use Intent named as "com.android.phone.CHANGE_NETWORK_MODE" with the Extras(or attribute as a layman's term) named as "com.android.phone.NEW_NETWORK_MODE"
    2. smali\com\android\phone\NetworkModeReceiver$1.smali -> Helper Class for MyHandler inner class.

      Code:
      .class synthetic Lcom/android/phone/NetworkModeReceiver$1;
      .super Ljava/lang/Object;
      .source "NetworkModeReceiver.java"
      
      
      # annotations
      .annotation system Ldalvik/annotation/EnclosingClass;
          value = Lcom/android/phone/NetworkModeReceiver;
      .end annotation
      
      .annotation system Ldalvik/annotation/InnerClass;
          accessFlags = 0x1008
          name = null
      .end annotation
    3. smali\com\android\phone\NetworkModeReceiver$MyHandler.smali -> Does nothing, only used for Receiving a rollback message from system for UI element - which in this method is not quite usable. But it's there for compatibility reason.
      Code:
      .class Lcom/android/phone/NetworkModeReceiver$MyHandler;
      .super Landroid/os/Handler;
      .source "NetworkModeReceiver.java"
      
      
      # annotations
      .annotation system Ldalvik/annotation/EnclosingClass;
          value = Lcom/android/phone/NetworkModeReceiver;
      .end annotation
      
      .annotation system Ldalvik/annotation/InnerClass;
          accessFlags = 0x2
          name = "MyHandler"
      .end annotation
      
      
      # instance fields
      .field final synthetic this$0:Lcom/android/phone/NetworkModeReceiver;
      
      
      # direct methods
      .method private constructor <init>(Lcom/android/phone/NetworkModeReceiver;)V
          .locals 0
          .parameter
      
          .prologue
          .line 628
          iput-object p1, p0, Lcom/android/phone/NetworkModeReceiver$MyHandler;->this$0:Lcom/android/phone/NetworkModeReceiver;
      
          invoke-direct {p0}, Landroid/os/Handler;-><init>()V
      
          return-void
      .end method
      
      .method synthetic constructor <init>(Lcom/android/phone/NetworkModeReceiver;Lcom/android/phone/NetworkModeReceiver$1;)V
          .locals 0
          .parameter "x0"
          .parameter "x1"
      
          .prologue
          .line 628
          invoke-direct {p0, p1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;-><init>(Lcom/android/phone/NetworkModeReceiver;)V
      
          return-void
      .end method
      
      .method private handleGetPreferredNetworkTypeResponse(Landroid/os/Message;)V
          .locals 9
          .parameter "msg"
      
          return-void
      .end method
      
      .method private handleSetPreferredNetworkTypeResponse(Landroid/os/Message;)V
          .locals 2
          .parameter "msg"
      
          return-void
      .end method
      
      .method private resetNetworkModeToDefault()V
          .locals 3
      
          .prologue
          return-void
      .end method
      
      
      # virtual methods
      .method public handleMessage(Landroid/os/Message;)V
          .locals 1
          .parameter "msg"
      
          .prologue
          .line 635
          iget v0, p1, Landroid/os/Message;->what:I
      
          packed-switch v0, :pswitch_data_0
      
          .line 643
          :goto_0
          return-void
      
          .line 637
          :pswitch_0
          invoke-direct {p0, p1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;->handleGetPreferredNetworkTypeResponse(Landroid/os/Message;)V
      
          goto :goto_0
      
          .line 640
          :pswitch_1
          invoke-direct {p0, p1}, Lcom/android/phone/NetworkModeReceiver$MyHandler;->handleSetPreferredNetworkTypeResponse(Landroid/os/Message;)V
      
          goto :goto_0
      
          .line 635
          :pswitch_data_0
          .packed-switch 0x0
              :pswitch_0
              :pswitch_1
          .end packed-switch
      .end method
    You need to download from the attachment and put them into smali\com\android\phone folder.

    2. Register the Receiver at runtime through Phone Application smali file
    Now you have the Receiver installed, you need to initiate and register the Receiver at phone app startup. There are 2 methods available:
    1. Add another line to AndroidManifest.xml -> The simplest one but not practical for system app of stock ROM since the AndroidManifest.xml requires to be signed to be functional.
    2. Alter PhoneApp.smali (it can be named something else->The point is you need Phone's Application main code to be altered) to register the receiver when it's called -> This is the way to go.

    This is how you alter the PhoneApp.smali:
    1. Give a space to store the Receiver inside the PhoneApp.smali, named as mModeReceiver (Insert the Bold Line)
      Code:
      .field mLastPhoneState:Lcom/android/internal/telephony/Phone$State;
      
      .field private final mMediaButtonReceiver:Landroid/content/BroadcastReceiver;
      
      [B].field private final mModeReceiver:Landroid/content/BroadcastReceiver;[/B]
      
      .field private mNationalRoamingSettings:I
      
      .field private mNationalRoamingSupported:Z
    2. Initiate the Receiver Object and store it into the available space (Insert the Bold Line)
      Code:
      .method public constructor <init>()V
       .
       .
          .line 233
          new-instance v0, Lcom/android/phone/PhoneApp$PhoneAppBroadcastReceiver;
      
          const/4 v1, 0x0
      
          invoke-direct {v0, p0, v1}, Lcom/android/phone/PhoneApp$PhoneAppBroadcastReceiver;-><init>(Lcom/android/phone/PhoneApp;Lcom/android/phone/PhoneApp$1;)V
      
          iput-object v0, p0, Lcom/android/phone/PhoneApp;->mReceiver:Landroid/content/BroadcastReceiver;
      
      [B]    .line 236
          new-instance v0, Lcom/android/phone/NetworkModeReceiver;
      
          invoke-direct {v0}, Lcom/android/phone/NetworkModeReceiver;-><init>()V
      
          iput-object v0, p0, Lcom/android/phone/PhoneApp;->mModeReceiver:Landroid/content/BroadcastReceiver;[/B]
      
          .line 238
          new-instance v0, Lcom/android/phone/SemcMediaButtonBroadcastReceiver;
      
          invoke-direct {v0}, Lcom/android/phone/SemcMediaButtonBroadcastReceiver;-><init>()V
      
          iput-object v0, p0, Lcom/android/phone/PhoneApp;->mMediaButtonReceiver:Landroid/content/BroadcastReceiver;
        
          .
          .
      .end method
    3. Register the Receiver
      The following is to register the Receiver when the Phone app is created (onCreate). When registered, It will start listening to the phone activity so later it can receive a toggle message from toggle app. And not just any message that this receiver can read, We limit this Receiver to only hear a filtered Intent with name of "com.android.phone.CHANGE_NETWORK_MODE" as explained above.

      Code:
      .method public onCreate()V
          .
          .
          .line 630
          const-string v1, "com.android.phone.intent.ACTION_DATA_TRAFFIC_SWITCH"
      
          invoke-virtual {v0, v1}, Landroid/content/IntentFilter;->addAction(Ljava/lang/String;)V
      
          .line 631
          iget-object v1, p0, Lcom/android/phone/PhoneApp;->mReceiver:Landroid/content/BroadcastReceiver;
      
          invoke-virtual {p0, v1, v0}, Lcom/android/phone/PhoneApp;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;
      
      [B]    .line 633
          new-instance v0, Landroid/content/IntentFilter;
      
          const-string v1, "com.android.phone.CHANGE_NETWORK_MODE"
      
          invoke-direct {v0, v1}, Landroid/content/IntentFilter;-><init>(Ljava/lang/String;)V
      
          iget-object v1, p0, Lcom/android/phone/PhoneApp;->mModeReceiver:Landroid/content/BroadcastReceiver;
      
          invoke-virtual {p0, v1, v0}, Lcom/android/phone/PhoneApp;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;[/B]
      
          .line 638
          new-instance v0, Landroid/content/IntentFilter;
      
          const-string v1, "android.intent.action.MEDIA_BUTTON"
      
          invoke-direct {v0, v1}, Landroid/content/IntentFilter;-><init>(Ljava/lang/String;)V
      
          .line 642
          const/16 v1, 0x3e0
      
          invoke-virtual {v0, v1}, Landroid/content/IntentFilter;->setPriority(I)V
      
          .line 645
          iget-object v1, p0, Lcom/android/phone/PhoneApp;->mMediaButtonReceiver:Landroid/content/BroadcastReceiver;
      
          invoke-virtual {p0, v1, v0}, Lcom/android/phone/PhoneApp;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;
      
          .
          .
      .end method

    3. Compile the Phone.apk
    You need to compile the phone app back. As it was with Sony's code, it was clear that i need to decompile ONLY the source, but not the resource part of the apk because when compiled back it will be broken. So try to decompile it at the source only.

    4. Implement the Toggle App to send a Broadcast Intent
    Now this is the part where you have to determine what mode is supported by your phone. This is the value of Android supported value that will be sent as a Broadcast Intent:

    Code:
         int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
    
         int NETWORK_MODE_GSM_ONLY       = 1; /* GSM only */
    
         int NETWORK_MODE_WCDMA_ONLY     = 2; /* WCDMA only */
    
         int NETWORK_MODE_GSM_UMTS       = 3; /* GSM/WCDMA (auto mode, according to PRL) AVAILABLE Application Settings menu*/
    
         int NETWORK_MODE_CDMA           = 4; /* CDMA and EvDo (auto mode, according to PRL) AVAILABLE Application Settings menu*/
    
         int NETWORK_MODE_CDMA_NO_EVDO   = 5; /* CDMA only */
    
         int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */
    
         int NETWORK_MODE_GLOBAL         = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) AVAILABLE Application Settings menu*/

    So if your phone only supports WCDMA(3G) as max, you should use value 0,1, and 2 only.

    The following is my 2G/3G simple toggle mode from Lidroid's Status Bar Widget code. You should adapt the code yourself if you're using something else. But as a guide, this is the logic:
    1. create a new Intent with name "com.android.phone.CHANGE_NETWORK_MODE"
    2. take current mode
    3. Apply the next value into the newly created Intent as Extra named "com.android.phone.NEW_NETWORK_MODE"
    4. Broadcast the Intent to the System (which will be read by Phone.apk).

    The logic above can be observed in the method toggleState() on the following code:

    Code:
    .class public Lcom/lidroid/systemui/quickpanel/NetworkModeButton;
    .super Lcom/lidroid/systemui/quickpanel/PowerButton;
    .source "NetworkModeButton.java"
    
    
    # static fields
    .field private static final CM_MODE_3GSM_ONLY:I = 0x1
    
    .field private static final CM_MODE_3G_ONLY:I = 0x0
    
    .field private static final CM_MODE_3G_PREFERRED:I = 0x2
    
    .field private static final OBSERVED_URIS:Ljava/util/List; = null
        .annotation system Ldalvik/annotation/Signature;
            value = {
                "Ljava/util/List",
                "<",
                "Landroid/net/Uri;",
                ">;"
            }
        .end annotation
    .end field
    
    .field private static final TAG:Ljava/lang/String; = "NetworkModeButton"
    
    
    # direct methods
    .method static constructor <clinit>()V
        .locals 3
    
        .prologue
        const/16 v2, 0x0
    
        .line 21
        new-instance v0, Ljava/util/ArrayList;
    
        invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V
    
        sput-object v0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->OBSERVED_URIS:Ljava/util/List;
    
        .line 23
        sget-object v0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->OBSERVED_URIS:Ljava/util/List;
    
        const-string v1, "preferred_network_mode"
    
        invoke-static {v1}, Landroid/provider/Settings$Secure;->getUriFor(Ljava/lang/String;)Landroid/net/Uri;
    
        move-result-object v1
    
        invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z
    
        return-void
    .end method
    
    .method public constructor <init>()V
        .locals 2
    
        .prologue
        .line 43
        invoke-direct {p0}, Lcom/lidroid/systemui/quickpanel/PowerButton;-><init>()V
    
        const-string v0, "toggleNetworkMode"
    
        iput-object v0, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mType:Ljava/lang/String;
    
        return-void
    .end method
    
    .method private static getCurrentNetworkMode(Landroid/content/Context;)I
        .locals 3
        .parameter "context"
    
        .prologue
        .line 167
        const/16 v0, 0x0
    
        .line 169
        .local v0, state:I
        :try_start_0
        invoke-virtual {p0}, Landroid/content/Context;->getContentResolver()Landroid/content/ContentResolver;
    
        move-result-object v1
    
        const-string v2, "preferred_network_mode"
    
        invoke-static {v1, v2}, Landroid/provider/Settings$Secure;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;)I
        :try_end_0
        .catch Landroid/provider/Settings$SettingNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
    
        move-result v0
    
        .line 173
        :goto_0
        return v0
    
        .line 171
        :catch_0
        move-exception v1
    
        goto :goto_0
    .end method
    
    
    # virtual methods
    .method protected getObservedUris()Ljava/util/List;
        .locals 1
        .annotation system Ldalvik/annotation/Signature;
            value = {
                "()",
                "Ljava/util/List",
                "<",
                "Landroid/net/Uri;",
                ">;"
            }
        .end annotation
    
        .prologue
        .line 163
        sget-object v0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->OBSERVED_URIS:Ljava/util/List;
    
        return-object v0
    .end method
    
    .method protected getText()I
        .locals 1
    
        .prologue
        .line 93
        const v0, 0x7f08007d
    
        return v0
    .end method
    
    .method protected handleLongClick()Z
        .locals 3
    
        .prologue
        .line 126
        new-instance v0, Landroid/content/Intent;
    
        const-string v1, "android.intent.action.MAIN"
    
        invoke-direct {v0, v1}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
    
        .line 127
        .local v0, intent:Landroid/content/Intent;
        const-string v1, "com.android.phone"
    
        const-string v2, "com.android.phone.Settings"
    
        invoke-virtual {v0, v1, v2}, Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
    
        .line 128
        const/high16 v1, 0x1000
    
        invoke-virtual {v0, v1}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;
    
        .line 129
        iget-object v1, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;
    
        invoke-virtual {v1}, Landroid/view/View;->getContext()Landroid/content/Context;
    
        move-result-object v1
    
        invoke-virtual {v1, v0}, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V
    
        .line 130
        const/4 v1, 0x1
    
        return v1
    .end method
    
    [B].method protected toggleState()V
        .locals 5
    
        .prologue
        const/4 v4, 0x2
    
        const/4 v1, 0x1
    
        const-string v2, "com.android.phone.CHANGE_NETWORK_MODE"
    
        .line 83
        iget-object v3, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;
    
        invoke-virtual {v3}, Landroid/view/View;->getContext()Landroid/content/Context;
    
        move-result-object v3
    
        .line 84
        .local v3, context:Landroid/content/Context;
        invoke-static {v3}, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->getCurrentNetworkMode(Landroid/content/Context;)I
    
        move-result v0
    
        .line 85
        add-int v0, v0, v1
    
        if-le v0, v4, :cond_0
    
        const/4 v0, 0x0
    
        .line 86
        :cond_0
        new-instance v4, Landroid/content/Intent;
    
        invoke-direct {v4, v2}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
    
        const-string v2, "com.android.phone.NEW_NETWORK_MODE"
    
        invoke-virtual {v4, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;I)Landroid/content/Intent;
    
        invoke-virtual {v3, v4}, Landroid/content/Context;->sendBroadcast(Landroid/content/Intent;)V
    
        return-void
    .end method[/B]
    
    .method protected updateState()V
        .locals 3
    
        .line 90
        iget-object v1, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;
    
        invoke-virtual {v1}, Landroid/view/View;->getContext()Landroid/content/Context;
    
        move-result-object v1
    
        invoke-static {v1}, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->getCurrentNetworkMode(Landroid/content/Context;)I
    
        move-result v0
    
        .line 92
        const v1, 0x0
    
        if-ne v0, v1, :cond_0
    
        const v2, 0x7f0200d4
    
        iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mIcon:I
    
        const/4 v2, 0x1
    
        iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mState:I
    
        .line 93
        :goto_0
        return-void
    
        .line 94
        :cond_0
        const v1, 0x1
    
        if-ne v0, v1, :cond_1
    
        const v2, 0x7f0200d3
    
        iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mIcon:I
    
        const/4 v2, 0x2
    
        iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mState:I
    
        goto :goto_0
    
        .line 96
        :cond_1
        const v2, 0x7f0200d5
    
        iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mIcon:I
    
        const/4 v2, 0x1
    
        iput v2, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mState:I
    
        goto :goto_0
    .end method

    Or you could download from attachment if you happen to use Lidroid's code too.
    Compile back your apk and voila! ;)

    Hope this tutorial helps :) Any question, please reply and i'll help as best as i can. :)
    6
    hansip87, first off all thanks for awesome guide!!!

    I´ve managed it working without patching Phone.apk!!! Just by adding the Receiver inside SystemUI.apk and by changing it´s AndroidManifest.xml.

    The trick is:

    1. Add red lines to SystemUI.apk AndroidManifest.xml:
    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest android:sharedUserId="android.uid.system" android:process="system" android:versionCode="15" android:versionName="4.0.4-tL1_3w" package="com.android.systemui" coreApp="true"
      xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" />
        <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
        <uses-permission android:name="android.permission.BLUETOOTH" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
        <uses-permission android:name="android.permission.GET_TASKS" />
        <uses-permission android:name="android.permission.MANAGE_USB" />
        <application android:label="@string/app_label" android:icon="@drawable/ic_launcher_settings" android:allowClearUserData="false" android:persistent="true" android:allowBackup="false" android:hardwareAccelerated="true">
            <service android:name="SystemUIService" android:exported="true" />
            <service android:name=".screenshot.TakeScreenshotService" android:exported="false" android:process=":screenshot" />
            <service android:name=".LoadAverageService" android:exported="true" />
            <service android:name=".ImageWallpaper" android:permission="android.permission.BIND_WALLPAPER" android:exported="true" />
            <receiver android:name=".BootReceiver">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                </intent-filter>
            </receiver>
            <activity android:label="@android:string/usb_storage_activity_title" android:name=".usb.UsbStorageActivity" android:excludeFromRecents="true" />
            <activity android:theme="@android:style/Theme.Dialog.Alert" android:name="com.android.internal.app.ExternalMediaFormatActivity" android:excludeFromRecents="true" />
            <activity android:theme="@android:style/Theme.Holo.Dialog.Alert" android:name=".usb.UsbConfirmActivity" android:permission="android.permission.MANAGE_USB" android:exported="true" android:excludeFromRecents="true" android:finishOnCloseSystemDialogs="true" />
            <activity android:theme="@android:style/Theme.Holo.Dialog.Alert" android:name=".usb.UsbPermissionActivity" android:permission="android.permission.MANAGE_USB" android:exported="true" android:excludeFromRecents="true" android:finishOnCloseSystemDialogs="true" />
            <activity android:theme="@android:style/Theme.Holo.Dialog.Alert" android:name=".usb.UsbResolverActivity" android:permission="android.permission.MANAGE_USB" android:exported="true" android:excludeFromRecents="true" android:finishOnCloseSystemDialogs="true" />
            <activity android:theme="@android:style/Theme.Holo.Dialog.Alert" android:name=".usb.UsbAccessoryUriActivity" android:permission="android.permission.MANAGE_USB" android:exported="true" android:excludeFromRecents="true" android:finishOnCloseSystemDialogs="true" />
            <activity android:theme="@android:style/Theme.Holo.Panel" android:name=".net.NetworkOverLimitActivity" android:permission="android.permission.MANAGE_NETWORK_POLICY" android:exported="true" android:taskAffinity="com.android.systemui.net" android:excludeFromRecents="true" android:launchMode="singleTop" android:finishOnCloseSystemDialogs="true" />
            <activity android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:label="Nyandroid" android:icon="@drawable/nyandroid04" android:name=".Nyandroid" android:exported="true" android:excludeFromRecents="true" android:launchMode="singleInstance" android:hardwareAccelerated="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
            [COLOR="red"]<receiver android:name="com.lidroid.systemui.quickpanel.NetworkModeReceiver" android:process="com.android.phone">
                <intent-filter>
                    <action android:name="com.serajr.powertoggles.POWERTOGGLES_CHANGE_NETWORK_MODE" />
                    <action android:name="com.serajr.powertoggles.POWERTOGGLES_NEW_NETWORK_MODE" />
                </intent-filter>
            </receiver>[/COLOR]
        </application>
    </manifest>

    See what google docs say about android : process: "The name of the process in which the broadcast receiver should run"
    Here we´re linking our receiver with "com.android.phone" process, so it´ll run there!! And no other permission is required!!!


    2. Add receiver files (attached) into lidroid package folder, so we´ll have:

    SystemUI.apk\smali\com\lidroid\systemui\quickpanel\NetworkModeReceiver$MyHandler.smali
    SystemUI.apk\smali\com\lidroid\systemui\quickpanel\NetworkModeReceiver.smali


    3. Change the broadcast intent inside NetworkModeButton.smali file to (red lines under toggleState() method) :
    Code:
    .method protected toggleState()V
        .locals 5
    
        .prologue
        const/4 v4, 0x2
    
        const/4 v1, 0x1
    
        const-string v2, "[COLOR="red"]com.serajr.powertoggles.POWERTOGGLES_CHANGE_NETWORK_MODE[/COLOR]"
    
        .line 83
        iget-object v3, p0, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->mView:Landroid/view/View;
    
        invoke-virtual {v3}, Landroid/view/View;->getContext()Landroid/content/Context;
    
        move-result-object v3
    
        .line 84
        .local v0, context:Landroid/content/Context;
        invoke-static {v3}, Lcom/lidroid/systemui/quickpanel/NetworkModeButton;->getCurrentNetworkMode(Landroid/content/Context;)I
    
        move-result v0
    
        .line 85
        add-int v0, v0, v1
    
        if-le v0, v4, :cond_0
    
        const/4 v0, 0x0
    
        .line 86
        :cond_0
        new-instance v4, Landroid/content/Intent;
    
        invoke-direct {v4, v2}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V
    
        const-string v2, "[COLOR="red"]com.serajr.powertoggles.POWERTOGGLES_NEW_NETWORK_MODE[/COLOR]"
    
        invoke-virtual {v4, v2, v0}, Landroid/content/Intent;->putExtra(Ljava/lang/String;I)Landroid/content/Intent;
    
        invoke-virtual {v3, v4}, Landroid/content/Context;->sendBroadcast(Landroid/content/Intent;)V
    
        return-void
    .end method


    Remember, by changing AndroidManifest.xml file contents require you to replace it exclusively through recovery (cwm)!
    And of course I´ve changed the intents texts to not interfere with the already existing ones!


    That´s it!!! ;)
    .
    .
    2
    im using galaxy note. succed???
    try it first gan.
    1
    First - Thank you, very good job

    Second, i would like to add new receiver in Androidmanifest.xml
    so is that correct
    Code:
    	<receiver android:name="NetworkModeReceiver">
                <intent-filter>
                    <action android:name="com.android.phone.CHANGE_NETWORK_MODE" />
                    <action android:name="com.android.phone.NEW_NETWORK_MODE" />
                </intent-filter>
            </receiver>

    is it enough?

    -------------------------------------------

    Yes found it enoughs
    1
    last question, I swear:

    when I click in the toggle, the network switch and change the icon. Normal and ok


    the problem:
    when i switch the network on "menu/definition/ Network Mode" the icon in the toggle does not follow the change. Always gets the same icon.

    there is a solution?

    It seems a bug. On every device can switch only from 2G to 3G and never in auto-mode.