6

There're some problems with the code worked on android 4.0.2..4.4.4, but doesn't really work on Android 5 and I don't know why. Basically, the code below allows to set new WiFi's IP assignment type: STATIC or DHCP. The code I used is fully covered in this answer: https://stackoverflow.com/a/10309323/876360

I'll try to put here the most important pats of the code with the output info.

...
WifiConfigurator.setIpAssignment("STATIC", wifiConf);
...

where wifiConf is

public static WifiConfiguration getCurrentWiFiConfiguration(Context context) {
    WifiConfiguration wifiConf = null;
    ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    if (networkInfo.isConnected()) {
        final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
        if (connectionInfo != null && !TextUtils.isEmpty(connectionInfo.getSSID())) {
            List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
            if(configuredNetworks != null){
                for (WifiConfiguration conf : configuredNetworks) {
                    if (conf.networkId == connectionInfo.getNetworkId()) {
                        wifiConf = conf;
                        break;
                    }
                }
            }
        }
    }
    return wifiConf;
}

So WifiConfigurator.setIpAssigment() calls the next code:

public static void setIpAssignment(String assign, WifiConfiguration wifiConf)
        throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException {

    setEnumField(wifiConf, assign, "ipAssignment");
}

public static void setEnumField(Object obj, String value, String name)
        throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
    Log.d("myApp", obj.getClass().toString());
    Field f = obj.getClass().getField(name);
    f.set(obj, Enum.valueOf((Class<Enum>) f.getType(), value));
}

But for some reason the field "ipAssignment" cannot be found:

11-30 12:40:54.343    5941-5941/com.myApp D/myApp﹕ class android.net.wifi.WifiConfiguration
11-30 12:40:54.344    5941-5941/com.myApp D/myApp﹕ Can't update network configuration. java.lang.NoSuchFieldException: ipAssignment
            at java.lang.Class.getField(Class.java:1048)
            at com.myApp.WifiConfigurator.setEnumField(WifiConfigurator.java:141)
            at com.myApp.WifiConfigurator.setIpAssignment(WifiConfigurator.java:25)
            at com.myApp.WifiConfigurator.updateWifiNetwork(WifiConfigurator.java:220)
            at com.myApp.ui.MainScreen.onAsyncTaskCompleted(MainScreen.java:251)
            at com.myApp.myAPI$UpdateIPTask.onPostExecute(myAPI.java:257)
            at com.myApp.myAPI$UpdateIPTask.onPostExecute(myAPI.java:194)
            at android.os.AsyncTask.finish(AsyncTask.java:632)
            at android.os.AsyncTask.access$600(AsyncTask.java:177)
            at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

At first, I thought google changed the field's name. Then I checked the Android L preview source code, the field is there. I'm confused why this is happening.

UPDATE

Thanks to Matiash for some input, I am able to update ipAssignment type, but I'm not able to update DNSes. To update DNSes the ipAssigment should be static. According to this Google stopped using LinkProperties for static configuration, they use StaticIpConfiguration class now.

So what I do:

public static void setDNS(InetAddress dns1, InetAddress dns2, WifiConfiguration wifiConf)
        throws SecurityException, IllegalArgumentException, NoSuchMethodException, InvocationTargetException,
        NoSuchFieldException, IllegalAccessException {

    Object linkProperties = null;
    ArrayList<InetAddress> mDnses;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        staticIpConf = wifiConf.getClass().getMethod("getStaticIpConfiguration").invoke(wifiConf);
        mDnses = (ArrayList<InetAddress>) getDeclaredField(staticIpConf, "dnsServers");
    }
    else{
        linkProperties = getField(wifiConf, "linkProperties");
        mDnses = (ArrayList<InetAddress>) getDeclaredField(linkProperties, "mDnses");
    }

    mDnses.clear();
    mDnses.add(dns1);
    mDnses.add(dns2);
}
public static Object getDeclaredField(Object obj, String name)
        throws SecurityException, NoSuchFieldException,
        IllegalArgumentException, IllegalAccessException {

    Field f = obj.getClass().getDeclaredField(name);
    f.setAccessible(true);
    Object out = f.get(obj);
    return out;
}

The next I see in error log:

12-22 09:00:49.854  25815-25815/com.myapp D/myapp﹕ Can't update network configuration. java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
            at com.myapp.WifiConfigurator.getDeclaredField(WifiConfigurator.java:245)
            at com.myapp.WifiConfigurator.setDNS(WifiConfigurator.java:78)
            at com.myapp.WifiConfigurator.updateWifiNetwork(WifiConfigurator.java:356)

My guess is staticIpConfiguration doesn't exists when I call it. I have to initialize it somehow. Any ideas how to update DNSes?

Community
  • 1
  • 1
KennyPowers
  • 4,925
  • 8
  • 36
  • 51
  • Just to make sure you're looking at the correct source code, maybe you could try reading all fields from that class in a quick test and see what fields it has. – Ingo Bürk Dec 02 '14 at 18:36

1 Answers1

7

Although the ipAssignment field was still present in the L preview (at least the version in grepcode), it's not in the released version, as you can see in the "master" branch of the source code or in the Github mirror.

Both the Enum definition and the field are now inside an inner object, of type IpConfiguration (also new). These are the dangers of using reflection to access undocumented waters... :)

However, it's simple to tweak the code to access it by reflection and set it there:

public static void setIpAssignment(String assign, WifiConfiguration wifiConf)
        throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Object ipConfiguration = wifiConf.getClass().getMethod("getIpConfiguration").invoke(wifiConf);
        setEnumField(ipConfiguration, assign, "ipAssignment");
    } else {
        setEnumField(wifiConf, assign, "ipAssignment");
    }
}

This code "works" (in the sense that it does not throw an exception) but I haven't tested it any further.


See How to configure a static IP address, netmask, gateway, DNS programmatically on Android 5.x (Lollipop) for Wi-Fi connection for a more detailed solution.

Community
  • 1
  • 1
matiash
  • 54,791
  • 16
  • 125
  • 154
  • it works, thanks for this. you'll get your bounty :). But I have more problems with the code. This code used to change wi-fi settings (DNS IPs are the most important settings for me). If you have any ideas how to change DNS IPs on Android L - please let me know :) – KennyPowers Dec 03 '14 at 19:18
  • Now I got `java.lang.NoSuchFieldException: linkProperties` and I bet I'll get more. I can't find the right replacement for this in Android L code. – KennyPowers Dec 03 '14 at 19:20
  • @KennyPowers From [this](https://github.com/android/platform_frameworks_base/commit/0a82e80073e193725a9d4c84a93db8a04b2456b9) it would seem that `LinkProperties` was more or less substituted by `IpConfiguration`/`StaticIpConfiguration`. Perhaps you could look over there? – matiash Dec 03 '14 at 19:30
  • sorry, but still don't understand. Lack of experience :(. Can you give me an example? – KennyPowers Dec 22 '14 at 13:19
  • @KennyPowers I meant that these classes were reorganized, and some fields that previously were in LinkProperties now seem to be in the mentioned classes. And that, perhaps, by looking at them, you could find where the stuff you were using is now. – matiash Dec 22 '14 at 15:41
  • yeah I understand that, I have found they moved mostly everything to StaticIpConfiguration class, but I have faced another problem. If you have time please check the update I made for this question. – KennyPowers Dec 22 '14 at 16:51
  • @KennyPowers I gave another go at this after all, posted an answer to the other question. Cheers! :) – matiash Dec 29 '14 at 13:38
  • @matiash Could anyone make it to work with StaticIpConfiguration? I am stuck with the same problem on android 5.0. Thanks for any help. Can you share the link to other question where the answer was posted? – Sushil Jan 14 '16 at 09:55
  • @matiash.. thanks for your reply. That was really helful – Sushil Jan 14 '16 at 16:12