blob: d1ef771cfc67355e0f923e73bf9cd1a437144544 [file] [log] [blame]
package com.googlecode.android_scripting.facade.wifi;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Bundle;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.facade.EventFacade;
import com.googlecode.android_scripting.facade.FacadeManager;
import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcOptional;
import com.googlecode.android_scripting.rpc.RpcParameter;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.List;
/**
* WifiManager functions.
*
*/
//TODO: make methods handle various wifi states properly
//e.g. wifi connection result will be null when flight mode is on
public class WifiManagerFacade extends RpcReceiver {
private final static String mEventType = "WiFiManager";
private final Service mService;
private final WifiManager mWifi;
private final EventFacade mEventFacade;
private final IntentFilter mScanFilter;
private final IntentFilter mStateChangeFilter;
private final WifiScanReceiver mScanFinishedReceiver;
private final WifiActionListener mWifiActionListener;
private final WifiStateChangeReceiver mStateChangeReceiver;
private WifiLock mLock;
private boolean mIsConnected;
public WifiManagerFacade(FacadeManager manager) {
super(manager);
mService = manager.getService();
mWifi = (WifiManager) mService.getSystemService(Context.WIFI_SERVICE);
mLock = null;
mEventFacade = manager.getReceiver(EventFacade.class);
mScanFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mStateChangeFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mStateChangeFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mStateChangeFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
mStateChangeFilter.setPriority(999);
mScanFinishedReceiver = new WifiScanReceiver(mEventFacade);
mWifiActionListener = new WifiActionListener(mEventFacade);
mStateChangeReceiver = new WifiStateChangeReceiver();
}
private void makeLock(int wifiMode) {
if (mLock == null) {
mLock = mWifi.createWifiLock(wifiMode, "sl4a");
mLock.acquire();
}
}
/**
* Handle Broadcast receiver for Scan Result
* @parm eventFacade
* Object of EventFacade
*/
class WifiScanReceiver extends BroadcastReceiver {
private final EventFacade mEventFacade;
private final Bundle mResults;
WifiScanReceiver(EventFacade eventFacade){
mEventFacade = eventFacade;
mResults = new Bundle();
}
@Override
public void onReceive(Context c, Intent intent) {
Log.d("Wifi connection scan finished, results available.");
mResults.putLong("Timestamp", System.currentTimeMillis()/1000);
mResults.putString("Type", "onWifiScanReceive");
mEventFacade.postEvent("WifiScanFinished", mResults.clone());
mResults.clear();
mService.unregisterReceiver(mScanFinishedReceiver);
}
}
class WifiActionListener implements WifiManager.ActionListener{
private final EventFacade mEventFacade;
private final Bundle mResults;
public WifiActionListener(EventFacade eventFacade) {
mEventFacade = eventFacade;
mResults = new Bundle();
}
@Override
public void onSuccess() {
Log.d("WifiActionListener "+ mEventType);
mResults.putString("Type", "onSuccess");
mEventFacade.postEvent(mEventType, mResults.clone());
mResults.clear();
}
@Override
public void onFailure(int reason) {
Log.d("WifiActionListener "+ mEventType);
mResults.putString("Type", "onFailure");
mEventFacade.postEvent(mEventType, mResults.clone());
mResults.clear();
}
}
public class WifiStateChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
Log.d("Wifi network state changed.");
if (intent.hasExtra(WifiManager.EXTRA_WIFI_INFO)) {
WifiInfo wInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
Bundle msg = new Bundle();
String ssid = wInfo.getSSID();
if (ssid.charAt(0)=='"' && ssid.charAt(ssid.length()-1)=='"') {
msg.putString("ssid", ssid.substring(1, ssid.length()-1));
} else {
msg.putString("ssid", ssid);
}
msg.putString("bssid", wInfo.getBSSID());
mEventFacade.postEvent("WifiNetworkConnected", msg);
}
NetworkInfo nInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
WifiInfo wInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
Log.d("NetworkInfo " + nInfo);
Log.d("WifiInfo " + wInfo);
} else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
Log.d("Supplicant connection state changed.");
mIsConnected = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
Bundle msg = new Bundle();
msg.putBoolean("Connected", mIsConnected);
mEventFacade.postEvent("SupplicantConnectionChanged", msg);
}
}
}
private WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) {
if (result == null) return null;
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + result.SSID + "\"";
if (result.capabilities.contains("WEP")) {
config.allowedKeyManagement.set(KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); //?
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
}
if (result.capabilities.contains("PSK")) {
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
}
if (result.capabilities.contains("EAP")) {
//this is probably wrong, as we don't have a way to enter the enterprise config
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
}
if (result.capabilities.length() == 5 && result.capabilities.contains("ESS")) {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
}
config.BSSID = result.BSSID;
config.scanResultCache = new HashMap<String, ScanResult>();
if (config.scanResultCache == null)
return null;
config.scanResultCache.put(result.BSSID, result);
return config;
}
private boolean matchScanResult(ScanResult result, String id) {
if (result.BSSID.equals(id) || result.SSID.equals(id)) {
return true;
}
return false;
}
@Rpc(description = "Add a network.")
public Integer wifiAddNetwork(@RpcParameter(name = "wifiId") String wifiId) {
ScanResult target = null;
for (ScanResult r : mWifi.getScanResults()) {
if (matchScanResult(r, wifiId)) {
target = r;
break;
}
}
return mWifi.addNetwork(wifiConfigurationFromScanResult(target));
}
@Rpc(description = "Checks Wifi state.", returns = "True if Wifi is enabled.")
public Boolean wifiCheckState() {
return mWifi.getWifiState() == WifiManager.WIFI_STATE_ENABLED;
}
/**
* Connects to a WPA protected wifi network
*
* @param wifiSSID
* SSID of the wifi network
* @param wifiPassword
* password for the wifi network
* @return true on success
* @throws ConnectException
*/
@Rpc(description = "Connects a wifi network by ssid",
returns = "True if the operation succeeded.")
public Boolean wifiConnectWPA(@RpcParameter(name = "wifiSSID") String wifiSSID,
@RpcParameter(name = "wifiPassword") String wifiPassword) throws ConnectException {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + wifiSSID + "\"";
if(wifiPassword == null)
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
else
wifiConfig.preSharedKey = "\"" + wifiPassword + "\"";
mWifi.addNetwork(wifiConfig);
Boolean status = false;
Boolean found = false;
for (ScanResult sr : mWifi.getScanResults()) {
if (sr.SSID.equals(wifiSSID)) {
found = true;
break;
}
}
if (found == false) {
Log.e("Could not find wifi network with ssid " + wifiSSID);
throw new ConnectException("Could not find wifi network with ssid " + wifiSSID);
}
for (WifiConfiguration conf : mWifi.getConfiguredNetworks()) {
if (conf.SSID != null && conf.SSID.equals("\"" + wifiSSID + "\"")) {
mWifi.disconnect();
mWifi.enableNetwork(conf.networkId, true);
status = mWifi.reconnect();
break;
}
}
return status;
}
@Rpc(description = "Disconnects from the currently active access point.",
returns = "True if the operation succeeded.")
public Boolean wifiDisconnect() {
return mWifi.disconnect();
}
@Rpc(description = "Enable a configured network. Initiate a connection if disableOthers is true",
returns = "True if the operation succeeded.")
public Boolean wifiEnableNetwork(@RpcParameter(name = "netId") Integer netId,
@RpcParameter(name = "disableOthers") Boolean disableOthers) {
return mWifi.enableNetwork(netId, disableOthers);
}
/**
* Forget a wifi network with priority
*
* @param networkID
* Id of wifi network
*/
@Rpc(description = "Forget a wifi network with priority")
public void wifiForgetNetwork(@RpcParameter(name = "wifiSSID") Integer newtorkId ) {
mWifi.forget(newtorkId, mWifiActionListener);
}
@Rpc(description = "Return a list of all the configured wifi networks.")
public List<WifiConfiguration> wifiGetConfiguredNetworks() {
return mWifi.getConfiguredNetworks();
}
@Rpc(description = "Returns information about the currently active access point.")
public WifiInfo wifiGetConnectionInfo() {
return mWifi.getConnectionInfo();
}
@Rpc(description = "Returns the list of access points found during the most recent Wifi scan.")
public List<ScanResult> wifiGetScanResults() {
return mWifi.getScanResults();
}
@Rpc(description = "Acquires a full Wifi lock.")
public void wifiLockAcquireFull() {
makeLock(WifiManager.WIFI_MODE_FULL);
}
@Rpc(description = "Acquires a scan only Wifi lock.")
public void wifiLockAcquireScanOnly() {
makeLock(WifiManager.WIFI_MODE_SCAN_ONLY);
}
@Rpc(description = "Releases a previously acquired Wifi lock.")
public void wifiLockRelease() {
if (mLock != null) {
mLock.release();
mLock = null;
}
}
/**
* Connects to a wifi network with priority
*
* @param wifiSSID
* SSID of the wifi network
* @param wifiPassword
* password for the wifi network
*/
@Rpc(description = "Connects a wifi network as priority by pasing ssid")
public void wifiPriorityConnect(@RpcParameter(name = "wifiSSID") String wifiSSID,
@RpcParameter(name = "wifiPassword") String wifiPassword) {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + wifiSSID + "\"";
if(wifiPassword == null)
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
else
wifiConfig.preSharedKey = "\"" + wifiPassword + "\"";
mWifi.connect(wifiConfig, mWifiActionListener);
}
@Rpc(description = "Reassociates with the currently active access point.",
returns = "True if the operation succeeded.")
public Boolean wifiReassociate() {
return mWifi.reassociate();
}
@Rpc(description = "Reconnects to the currently active access point.",
returns = "True if the operation succeeded.")
public Boolean wifiReconnect() {
return mWifi.reconnect();
}
@Rpc(description = "Remove a configured network.",
returns = "True if the operation succeeded.")
public Boolean wifiRemoveNetwork(@RpcParameter(name = "netId") Integer netId) {
return mWifi.removeNetwork(netId);
}
@Rpc(description = "Starts a scan for Wifi access points.",
returns = "True if the scan was initiated successfully.")
public Boolean wifiStartScan() {
mService.registerReceiver(mScanFinishedReceiver, mScanFilter);
return mWifi.startScan();
}
@Rpc(description = "Start receiving wifi state change related broadcasts.")
public void wifiStartTrackingStateChange() {
mService.registerReceiver(mStateChangeReceiver, mStateChangeFilter);
}
@Rpc(description = "Stop receiving wifi state change related broadcasts.")
public void wifiStopTrackingStateChange() {
mService.unregisterReceiver(mStateChangeReceiver);
}
@Rpc(description = "Toggle Wifi on and off.", returns = "True if Wifi is enabled.")
public Boolean wifiToggleState(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled) {
if (enabled == null) {
enabled = !wifiCheckState();
}
mWifi.setWifiEnabled(enabled);
return enabled;
}
@Override
public void shutdown() {
wifiLockRelease();
mService.unregisterReceiver(mStateChangeReceiver);
}
}