Java tutorial
/* * 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.cooee.cordova.plugins; import org.apache.cordova.*; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.WifiManager; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.content.Context; import android.util.Log; public class WifiWizard extends CordovaPlugin { private static final String LOG_TAG = "WifiWizardPlugin"; 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 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 WifiManager wifiManager; private CallbackContext callbackContext; @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); if (cordova.getActivity() != null) { this.wifiManager = (WifiManager) cordova.getActivity().getSystemService(Context.WIFI_SERVICE); } else if (cordova.getContext() != null) { this.wifiManager = (WifiManager) cordova.getContext().getSystemService(Context.WIFI_SERVICE); } IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); if (cordova.getActivity() != null) { cordova.getActivity().registerReceiver(mReceiver, filter); } else if (cordova.getContext() != null) { cordova.getContext().registerReceiver(mReceiver, filter); } } @Override public void onDestroy() { super.onDestroy(); if (cordova.getActivity() != null) { cordova.getActivity().unregisterReceiver(mReceiver); } else if (cordova.getContext() != null) { cordova.getContext().unregisterReceiver(mReceiver); } } @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(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. * * @return true if add successful, false if add fails * @params callbackContext A Cordova callback context. * @params data JSON Array with [0] == SSID, [1] == password */ private boolean addNetwork(CallbackContext callbackContext, JSONArray data) { // Initialize the WifiConfiguration object WifiConfiguration wifi = new WifiConfiguration(); Log.d(LOG_TAG, "WifiWizard: addNetwork entered."); try { // data's order for ANY object is 0: ssid, 1: authentication algorithm, // 2+: authentication information. String authType = data.getString(1); if (authType.equals("WPA")) { // WPA Data format: // 0: ssid // 1: auth // 2: password String newSSID = data.getString(0); wifi.SSID = newSSID; String newPass = data.getString(2); wifi.preSharedKey = newPass; 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); wifi.networkId = ssidToNetworkId(newSSID); if (wifi.networkId == -1) { wifiManager.addNetwork(wifi); callbackContext.success(newSSID + " successfully added."); } else { wifiManager.updateNetwork(wifi); callbackContext.success(newSSID + " successfully updated."); } wifiManager.saveConfiguration(); return true; } else if (authType.equals("WEP")) { // TODO: connect/configure for WEP Log.d(LOG_TAG, "WEP unsupported."); callbackContext.error("WEP unsupported"); return false; } else if (authType.equals("NONE")) { String newSSID = data.getString(0); wifi.SSID = newSSID; wifi.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); wifi.networkId = ssidToNetworkId(newSSID); if (wifi.networkId == -1) { wifiManager.addNetwork(wifi); callbackContext.success(newSSID + " successfully added."); } else { wifiManager.updateNetwork(wifi); callbackContext.success(newSSID + " successfully updated."); } wifiManager.saveConfiguration(); return true; } // TODO: Add more authentications as necessary else { Log.d(LOG_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(LOG_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(LOG_TAG, "WifiWizard: removeNetwork entered."); if (!validateData(data)) { callbackContext.error("WifiWizard: removeNetwork data invalid"); Log.d(LOG_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(LOG_TAG, "WifiWizard: Network not found, can't remove."); return false; } } catch (Exception e) { callbackContext.error(e.getMessage()); Log.d(LOG_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(LOG_TAG, "WifiWizard: connectNetwork entered."); if (!validateData(data)) { callbackContext.error("WifiWizard: connectNetwork invalid data"); Log.d(LOG_TAG, "WifiWizard: connectNetwork invalid data."); return false; } String ssidToConnect = ""; try { ssidToConnect = data.getString(0); } catch (Exception e) { callbackContext.error(e.getMessage()); Log.d(LOG_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(LOG_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(LOG_TAG, "WifiWizard: disconnectNetwork entered."); if (!validateData(data)) { callbackContext.error("WifiWizard: disconnectNetwork invalid data"); Log.d(LOG_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(LOG_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(LOG_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(LOG_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(LOG_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); lvl.put("frequency", scan.frequency); lvl.put("capabilities", scan.capabilities); lvl.put("timestamp", scan.timestamp); 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; } /** * 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(LOG_TAG, "WifiWizard: disconnectNetwork invalid data"); return false; } String status = ""; try { status = data.getString(0); } catch (Exception e) { callbackContext.error(e.getMessage()); Log.d(LOG_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; } private void sendJS(final String js) { if (cordova.getActivity() != null) { cordova.getActivity().runOnUiThread(new Runnable() { @Override public void run() { webView.loadUrl(js); } }); } else if (cordova.getCordovaWrap() != null) { cordova.getCordovaWrap().runOnUiThread(new Runnable() { @Override public void run() { webView.loadUrl(js); } }); } } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { if (wifiManager == null) { Log.e(LOG_TAG, "Wifi was not available !"); } else { if (wifiManager.isWifiEnabled()) { Log.e(LOG_TAG, "Wifi was enabled !"); // sendJS("javascript:onWifiStateChanged(true);"); } else { Log.e(LOG_TAG, "Wifi was disabled !"); // sendJS("javascript:onWifiStateChanged(false);"); } } } } }; }