com.simplec.wifiwizard.WifiWizard.java Source code

Java tutorial

Introduction

Here is the source code for com.simplec.wifiwizard.WifiWizard.java

Source

/*
 * Copyright 2015 Matt Parsons
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.simplec.wifiwizard;

import java.math.BigInteger;
import java.util.List;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;

public class WifiWizard extends CordovaPlugin {

    private static final String ADD_NETWORK = "addNetwork";
    private static final String REMOVE_NETWORK = "removeNetwork";
    private static final String CONNECT_NETWORK = "connectNetwork";
    private static final String DISCONNECT_NETWORK = "disconnectNetwork";
    private static final String DISCONNECT = "disconnect";
    private static final String LIST_NETWORKS = "listNetworks";
    private static final String START_SCAN = "startScan";
    private static final String SIGNAL_STRENGTH = "wifiSignalStrength";
    private static final String GET_SCAN_RESULTS = "getScanResults";
    private static final String GET_CONNECTED_SSID = "getConnectedSSID";
    private static final String IS_WIFI_ENABLED = "isWifiEnabled";
    private static final String SET_WIFI_ENABLED = "setWifiEnabled";
    private static final String TAG = "WifiWizard";

    private WifiManager wifiManager;
    private CallbackContext callbackContext;

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        Log.e(TAG, "WifiWizard: initialize.");
        super.initialize(cordova, webView);
        this.wifiManager = (WifiManager) cordova.getActivity().getSystemService(Context.WIFI_SERVICE);
    }

    @Override
    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {

        this.callbackContext = callbackContext;

        if (action.equals(IS_WIFI_ENABLED)) {
            return this.isWifiEnabled(callbackContext);
        } else if (action.equals(SIGNAL_STRENGTH)) {
            return this.getWifiSignalStrength(callbackContext);
        } else if (action.equals(SET_WIFI_ENABLED)) {
            return this.setWifiEnabled(callbackContext, data);
        } else if (!wifiManager.isWifiEnabled()) {
            callbackContext.error("Wifi is not enabled.");
            return false;
        } else if (action.equals(ADD_NETWORK)) {
            return this.addNetwork(callbackContext, data);
        } else if (action.equals(REMOVE_NETWORK)) {
            return this.removeNetwork(callbackContext, data);
        } else if (action.equals(CONNECT_NETWORK)) {
            return this.connectNetwork(callbackContext, data);
        } else if (action.equals(DISCONNECT_NETWORK)) {
            return this.disconnectNetwork(callbackContext, data);
        } else if (action.equals(LIST_NETWORKS)) {
            return this.listNetworks(callbackContext);
        } else if (action.equals(START_SCAN)) {
            return this.startScan(callbackContext);
        } else if (action.equals(GET_SCAN_RESULTS)) {
            return this.getScanResults(callbackContext, data);
        } else if (action.equals(DISCONNECT)) {
            return this.disconnect(callbackContext);
        } else if (action.equals(GET_CONNECTED_SSID)) {
            return this.getConnectedSSID(callbackContext);
        } else {
            callbackContext.error("Incorrect action parameter: " + action);
        }

        return false;
    }

    /**
     * This methods adds a network to the list of available WiFi networks. If
     * the network already exists, then it updates it.
     *
     * @params callbackContext A Cordova callback context.
     * @params data JSON Array with [0] == SSID, [1] == password
     * @return true if add successful, false if add fails
     */
    private boolean addNetwork(CallbackContext callbackContext, JSONArray data) {
        // Initialize the WifiConfiguration object
        Log.d(TAG, "WifiWizard: addNetwork entered.");

        try {
            // data's order for ANY object is 0: ssid, 1: authentication
            // algorithm,
            // 2+: authentication information.
            String newSSID = data.getString(0); // needs to be in quotes
            String authType = data.getString(1);
            String newPass = data.getString(2);
            boolean isHidden = data.length() > 3 ? data.getBoolean(3) : false;

            Log.e(TAG, "AddNetwork:  " + authType + " " + newSSID + "  " + newPass);

            if (authType.equals("WPA")) {
                WifiConfiguration wifi = new WifiConfiguration();

                wifi.SSID = newSSID;
                wifi.preSharedKey = newPass;
                wifi.hiddenSSID = isHidden;

                wifi.status = WifiConfiguration.Status.ENABLED;
                wifi.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                wifi.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
                wifi.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
                wifi.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                wifi.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

                boolean res1 = wifiManager.setWifiEnabled(true);
                wifi.networkId = ssidToNetworkId(newSSID);
                int res = 0;
                if (wifi.networkId == -1) {
                    res = wifiManager.addNetwork(wifi);
                    Log.e(TAG, newSSID + " successfully add returned " + res);
                } else {
                    res = wifiManager.updateNetwork(wifi);
                    Log.e(TAG, newSSID + " successfully update returned " + res);
                }
                if (res < 0) {
                    callbackContext.error(newSSID + " was not added.");
                } else {
                    boolean es = wifiManager.saveConfiguration();
                    Log.d("WifiPreference", "saveConfiguration returned " + es);
                    boolean b = wifiManager.enableNetwork(res, false);
                    Log.d("WifiPreference", "enableNetwork returned " + b);

                    if (b) {
                        callbackContext.success(newSSID + " successfully added.");
                    } else {
                        callbackContext.error(newSSID + " failed to be added.");
                    }
                }

                wifiManager.saveConfiguration();
                return true;
            } else if (authType.equals("WEP")) {
                WifiConfiguration wifi = new WifiConfiguration();
                wifi.SSID = newSSID; // IMP! This should be in Quotes!!
                wifi.hiddenSSID = isHidden;
                wifi.status = WifiConfiguration.Status.ENABLED;

                wifi.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
                wifi.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
                wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                wifi.wepTxKeyIndex = 0;

                if (newPass.length() == 5 || newPass.length() == 13) {
                    newPass = String.format("%040x", new BigInteger(1, newPass.getBytes(/*YOUR_CHARSET?*/)));
                    Log.i("WifiPreference", "wep key converted to " + newPass);
                }

                if (newPass.length() != 10 && newPass.length() != 13) {
                    callbackContext.error(newSSID + " failed to be added.  Invalid key.");
                }

                wifi.wepKeys[0] = newPass; // This is the WEP Password
                wifi.wepTxKeyIndex = 0;

                boolean res1 = wifiManager.setWifiEnabled(true);
                wifi.networkId = ssidToNetworkId(newSSID);
                int res = 0;
                if (wifi.networkId == -1) {
                    res = wifiManager.addNetwork(wifi);
                    Log.e(TAG, newSSID + " successfully add returned " + res);
                } else {
                    res = wifiManager.updateNetwork(wifi);
                    Log.e(TAG, newSSID + " successfully update returned " + res);
                }
                if (res < 0) {
                    callbackContext.error(newSSID + " was not added.");
                } else {
                    boolean es = wifiManager.saveConfiguration();
                    Log.d("WifiPreference", "saveConfiguration returned " + es);
                    boolean b = wifiManager.enableNetwork(res, false);
                    Log.d("WifiPreference", "enableNetwork returned " + b);

                    if (b) {
                        callbackContext.success(newSSID + " successfully added.");
                    } else {
                        callbackContext.error(newSSID + " failed to be added.");
                    }
                }

                return true;
            } else if (authType.equals("EAP")) {/*
                                                * WifiEnterpriseConfig
                                                * enterpriseConfig = new
                                                * WifiEnterpriseConfig();
                                                * WifiConfiguration wifi = new
                                                * WifiConfiguration(); wifi =
                                                * new WifiConfiguration();
                                                * wifi.SSID = newSSID;
                                                * wifi.hiddenSSID = isHidden;
                                                * wifi
                                                * .allowedKeyManagement.set(
                                                * KeyMgmt.WPA_EAP);
                                                * wifi.allowedKeyManagement
                                                * .set(KeyMgmt.IEEE8021X);
                                                * 
                                                * if (newPass.indexOf("/")<0) {
                                                * callbackContext.error(newSSID
                                                * +
                                                * " could not be added. EAP requires username/password format in the password field."
                                                * ); }
                                                * 
                                                * String userName =
                                                * newPass.substring(0,
                                                * newPass.indexOf("/")); String
                                                * passWord =
                                                * newPass.substring(newPass
                                                * .indexOf("/")+1);
                                                * enterpriseConfig
                                                * .setIdentity(userName);
                                                * enterpriseConfig
                                                * .setPassword(passWord);
                                                * enterpriseConfig
                                                * .setEapMethod(
                                                * WifiEnterpriseConfig
                                                * .Eap.PEAP);
                                                * 
                                                * wifi.enterpriseConfig =
                                                * enterpriseConfig;
                                                * 
                                                * boolean res1 =
                                                * wifiManager.setWifiEnabled
                                                * (true); wifi.networkId =
                                                * ssidToNetworkId(newSSID); int
                                                * res = 0; if (wifi.networkId
                                                * == -1) { res =
                                                * wifiManager.addNetwork(wifi);
                                                * Log.e(TAG, newSSID +
                                                * " successfully add returned "
                                                * +res); } else { res =
                                                * wifiManager
                                                * .updateNetwork(wifi);
                                                * Log.e(TAG, newSSID +
                                                * " successfully update returned "
                                                * +res); } if (res<0) {
                                                * callbackContext.error(newSSID
                                                * + " was not added."); } else
                                                * { boolean es =
                                                * wifiManager.saveConfiguration
                                                * (); Log.d("WifiPreference",
                                                * "saveConfiguration returned "
                                                * + es); boolean b =
                                                * wifiManager
                                                * .enableNetwork(res, true);
                                                * Log.d("WifiPreference",
                                                * "enableNetwork returned " +
                                                * b);
                                                * 
                                                * if (b) {
                                                * callbackContext.success
                                                * (newSSID +
                                                * " successfully added."); }
                                                * else {
                                                * callbackContext.error(newSSID
                                                * + " failed to be added."); }
                                                * }
                                                * 
                                                * return true;
                                                */
                return false;
            } else if (authType.equals("NONE")) {
                WifiConfiguration wifi = new WifiConfiguration();

                wifi.SSID = newSSID;
                wifi.hiddenSSID = isHidden;
                wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                boolean res1 = wifiManager.setWifiEnabled(true);
                wifi.networkId = ssidToNetworkId(newSSID);
                int res = 0;
                if (wifi.networkId == -1) {
                    res = wifiManager.addNetwork(wifi);
                    Log.e(TAG, newSSID + " successfully add returned " + res);
                } else {
                    res = wifiManager.updateNetwork(wifi);
                    Log.e(TAG, newSSID + " successfully update returned " + res);
                }
                if (res < 0) {
                    callbackContext.error(newSSID + " was not added.");
                } else {
                    boolean es = wifiManager.saveConfiguration();
                    Log.d("WifiPreference", "saveConfiguration returned " + es);
                    boolean b = wifiManager.enableNetwork(res, false);
                    Log.d("WifiPreference", "enableNetwork returned " + b);

                    if (b) {
                        callbackContext.success(newSSID + " successfully added.");
                    } else {
                        callbackContext.error(newSSID + " failed to be added.");
                    }
                }

                return true;
            }
            // TODO: Add more authentications as necessary
            else {
                Log.d(TAG, "Wifi Authentication Type Not Supported.");
                callbackContext.error("Wifi Authentication Type Not Supported: " + authType);
                return false;
            }
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
            Log.d(TAG, e.getMessage());
            return false;
        }
    }

    /**
     * This method removes a network from the list of configured networks.
     *
     * @param callbackContext
     *            A Cordova callback context
     * @param data
     *            JSON Array, with [0] being SSID to remove
     * @return true if network removed, false if failed
     */
    private boolean removeNetwork(CallbackContext callbackContext, JSONArray data) {
        Log.d(TAG, "WifiWizard: removeNetwork entered.");

        if (!validateData(data)) {
            callbackContext.error("WifiWizard: removeNetwork data invalid");
            Log.d(TAG, "WifiWizard: removeNetwork data invalid");
            return false;
        }

        // TODO: Verify the type of data!
        try {
            String ssidToDisconnect = data.getString(0);

            int networkIdToRemove = ssidToNetworkId(ssidToDisconnect);

            if (networkIdToRemove >= 0) {
                wifiManager.removeNetwork(networkIdToRemove);
                wifiManager.saveConfiguration();
                callbackContext.success("Network removed.");
                return true;
            } else {
                callbackContext.error("Network not found.");
                Log.d(TAG, "WifiWizard: Network not found, can't remove.");
                return false;
            }
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
            Log.d(TAG, e.getMessage());
            return false;
        }
    }

    /**
     * This method connects a network.
     *
     * @param callbackContext
     *            A Cordova callback context
     * @param data
     *            JSON Array, with [0] being SSID to connect
     * @return true if network connected, false if failed
     */
    private boolean connectNetwork(CallbackContext callbackContext, JSONArray data) {
        Log.d(TAG, "WifiWizard: connectNetwork entered.");
        if (!validateData(data)) {
            callbackContext.error("WifiWizard: connectNetwork invalid data");
            Log.d(TAG, "WifiWizard: connectNetwork invalid data.");
            return false;
        }
        String ssidToConnect = "";

        try {
            ssidToConnect = data.getString(0);
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
            Log.d(TAG, e.getMessage());
            return false;
        }

        int networkIdToConnect = ssidToNetworkId(ssidToConnect);

        if (networkIdToConnect >= 0) {
            // We disable the network before connecting, because if this was the
            // last connection before
            // a disconnect(), this will not reconnect.
            wifiManager.disableNetwork(networkIdToConnect);
            wifiManager.enableNetwork(networkIdToConnect, true);
            callbackContext.success("Network " + ssidToConnect + " connected!");
            return true;
        } else {
            callbackContext.error("Network " + ssidToConnect + " not found!");
            Log.d(TAG, "WifiWizard: Network not found to connect.");
            return false;
        }
    }

    /**
     * This method disconnects a network.
     *
     * @param callbackContext
     *            A Cordova callback context
     * @param data
     *            JSON Array, with [0] being SSID to connect
     * @return true if network disconnected, false if failed
     */
    private boolean disconnectNetwork(CallbackContext callbackContext, JSONArray data) {
        Log.d(TAG, "WifiWizard: disconnectNetwork entered.");
        if (!validateData(data)) {
            callbackContext.error("WifiWizard: disconnectNetwork invalid data");
            Log.d(TAG, "WifiWizard: disconnectNetwork invalid data");
            return false;
        }
        String ssidToDisconnect = "";
        // TODO: Verify type of data here!
        try {
            ssidToDisconnect = data.getString(0);
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
            Log.d(TAG, e.getMessage());
            return false;
        }

        int networkIdToDisconnect = ssidToNetworkId(ssidToDisconnect);

        if (networkIdToDisconnect > 0) {
            wifiManager.disableNetwork(networkIdToDisconnect);
            callbackContext.success("Network " + ssidToDisconnect + " disconnected!");
            return true;
        } else {
            callbackContext.error("Network " + ssidToDisconnect + " not found!");
            Log.d(TAG, "WifiWizard: Network not found to disconnect.");
            return false;
        }
    }

    /**
     * This method disconnects current network.
     *
     * @param callbackContext
     *            A Cordova callback context
     * @return true if network disconnected, false if failed
     */
    private boolean disconnect(CallbackContext callbackContext) {
        Log.d(TAG, "WifiWizard: disconnect entered.");
        if (wifiManager.disconnect()) {
            callbackContext.success("Disconnected from current network");
            return true;
        } else {
            callbackContext.error("Unable to disconnect from the current network");
            return false;
        }
    }

    /**
     * This method uses the callbackContext.success method to send a JSONArray
     * of the currently configured networks.
     *
     * @param callbackContext
     *            A Cordova callback context
     * @param data
     *            JSON Array, with [0] being SSID to connect
     * @return true if network disconnected, false if failed
     */
    private boolean listNetworks(CallbackContext callbackContext) {
        Log.d(TAG, "WifiWizard: listNetworks entered.");
        List<WifiConfiguration> wifiList = wifiManager.getConfiguredNetworks();

        JSONArray returnList = new JSONArray();

        for (WifiConfiguration wifi : wifiList) {
            returnList.put(wifi.SSID);
        }

        callbackContext.success(returnList);

        return true;
    }

    /**
     * This method uses the callbackContext.success method to send a JSONArray
     * of the scanned networks.
     *
     * @param callbackContext
     *            A Cordova callback context
     * @param data
     *            JSONArray with [0] == JSONObject
     * @return true
     */
    private boolean getScanResults(CallbackContext callbackContext, JSONArray data) {
        List<ScanResult> scanResults = wifiManager.getScanResults();

        JSONArray returnList = new JSONArray();

        Integer numLevels = null;

        if (!data.isNull(0)) {
            try {
                JSONObject options = data.getJSONObject(0);

                if (options.has("numLevels")) {
                    Integer levels = options.optInt("numLevels");

                    if (levels > 0) {
                        numLevels = levels;
                    } else if (options.optBoolean("numLevels", false)) {
                        // use previous default for {numLevels: true}
                        numLevels = 5;
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        for (ScanResult scan : scanResults) {
            /*
             * @todo - breaking change, remove this notice when tidying new
             * release and explain changes, e.g.: 0.y.z includes a breaking
             * change to WifiWizard.getScanResults(). Earlier versions set
             * scans' level attributes to a number derived from
             * wifiManager.calculateSignalLevel. This update returns scans' raw
             * RSSI value as the level, per Android spec / APIs. If your
             * application depends on the previous behaviour, we have added an
             * options object that will modify behaviour: - if `(n == true || n
             * < 2)`, `*.getScanResults({numLevels: n})` will return data as
             * before, split in 5 levels; - if `(n > 1)`,
             * `*.getScanResults({numLevels: n})` will calculate the signal
             * level, split in n levels; - if `(n == false)`,
             * `*.getScanResults({numLevels: n})` will use the raw signal level;
             */

            int level;

            if (numLevels == null) {
                level = scan.level;
            } else {
                level = wifiManager.calculateSignalLevel(scan.level, numLevels);
            }

            JSONObject lvl = new JSONObject();
            try {
                lvl.put("level", level);
                lvl.put("SSID", scan.SSID);
                lvl.put("BSSID", scan.BSSID);
                returnList.put(lvl);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        callbackContext.success(returnList);
        return true;
    }

    /**
     * This method uses the callbackContext.success method. It starts a wifi
     * scanning
     *
     * @param callbackContext
     *            A Cordova callback context
     * @return true if started was successful
     */
    private boolean startScan(CallbackContext callbackContext) {
        if (wifiManager.startScan()) {
            callbackContext.success();
            return true;
        } else {
            callbackContext.error("Scan failed");
            return false;
        }
    }

    /**
     * This method retrieves the SSID for the currently connected network
     *
     * @param callbackContext
     *            A Cordova callback context
     * @return true if SSID found, false if not.
     */
    private boolean getConnectedSSID(CallbackContext callbackContext) {
        if (!wifiManager.isWifiEnabled()) {
            callbackContext.error("Wifi is disabled");
            return false;
        }

        WifiInfo info = wifiManager.getConnectionInfo();

        if (info == null) {
            callbackContext.error("Unable to read wifi info");
            return false;
        }

        String ssid = info.getSSID();
        if (ssid.isEmpty()) {
            ssid = info.getBSSID();
        }
        if (ssid.isEmpty()) {
            callbackContext.error("SSID is empty");
            return false;
        }

        callbackContext.success(ssid);
        return true;
    }

    /**
     * This method retrieves the current WiFi status
     *
     * @param callbackContext
     *            A Cordova callback context
     * @return true if WiFi is enabled, fail will be called if not.
     */
    private boolean isWifiEnabled(CallbackContext callbackContext) {
        boolean isEnabled = wifiManager.isWifiEnabled();
        callbackContext.success(isEnabled ? "1" : "0");
        return isEnabled;
    }

    private boolean getWifiSignalStrength(CallbackContext callbackContext) {
        int linkSpeed = wifiManager.getConnectionInfo().getRssi();
        callbackContext.success("" + linkSpeed);
        return true;
    }

    /**
     * This method takes a given String, searches the current list of configured
     * WiFi networks, and returns the networkId for the network if the SSID
     * matches. If not, it returns -1.
     */
    private int ssidToNetworkId(String ssid) {
        List<WifiConfiguration> currentNetworks = wifiManager.getConfiguredNetworks();
        int networkId = -1;

        // For each network in the list, compare the SSID with the given one
        for (WifiConfiguration test : currentNetworks) {
            if (test.SSID.equals(ssid)) {
                networkId = test.networkId;
            }
        }

        return networkId;
    }

    /**
     * This method enables or disables the wifi
     */
    private boolean setWifiEnabled(CallbackContext callbackContext, JSONArray data) {
        if (!validateData(data)) {
            callbackContext.error("WifiWizard: disconnectNetwork invalid data");
            Log.d(TAG, "WifiWizard: disconnectNetwork invalid data");
            return false;
        }

        String status = "";

        try {
            status = data.getString(0);
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
            Log.d(TAG, e.getMessage());
            return false;
        }

        if (wifiManager.setWifiEnabled(status.equals("true"))) {
            callbackContext.success();
            return true;
        } else {
            callbackContext.error("Cannot enable wifi");
            return false;
        }
    }

    private boolean validateData(JSONArray data) {
        try {
            if (data == null || data.get(0) == null) {
                callbackContext.error("Data is null.");
                return false;
            }
            return true;
        } catch (Exception e) {
            callbackContext.error(e.getMessage());
        }
        return false;
    }

}