package interdroid.swan.sensors.impl;
import interdroid.swan.R;
import interdroid.swan.sensors.AbstractConfigurationActivity;
import interdroid.swan.sensors.AbstractSwanSensor;
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
/**
* A sensor for available Wifi networks.
*
* @author nick <palmer@cs.vu.nl>
*
*/
public class WifiSensor extends AbstractSwanSensor {
// wifi:ssid{ANY,1000} == test && wifi:level?ssid=test > 10
// wifi:level?bssid=A:B:C:D > 10
// wifi:level{MAX,1000} > 10
private static final String TAG = "WiFi Sensor";
/**
* Configuration activity for this sensor.
*
* @author nick <palmer@cs.vu.nl>
*
*/
public static class ConfigurationActivity extends
AbstractConfigurationActivity {
@Override
public final int getPreferencesXML() {
return R.xml.wifi_preferences;
}
}
/**
* The network identifier field.
*/
public static final String SSID_FIELD = "ssid";
/**
* The base station identifier field.
*/
public static final String BSSID_FIELD = "bssid";
/**
* The level seen.
*/
public static final String LEVEL_FIELD = "level";
/**
* The discovery interval.
*/
public static final String DISCOVERY_INTERVAL = "discovery_interval";
/**
* The interval at which to run discovery.
*/
public static final long DEFAULT_DISCOVERY_INTERVAL = 60 * 1000;
/**
* true if we should stop polling and shutdown.
*/
private boolean stopPolling = false;
/**
* The wifi manager we access wifi info with.
*/
private WifiManager wifiManager;
/**
* The receiver we use to get wifi notifications.
*/
private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
long now = System.currentTimeMillis();
List<ScanResult> results = wifiManager.getScanResults();
for (ScanResult scanResult : results) {
Log.d(TAG, "Got WiFi: " + scanResult.level + ", "
+ scanResult.SSID + ", " + scanResult.BSSID);
if (expressionIdsPerValuePath.containsKey(SSID_FIELD)) {
putValueTrimSize(SSID_FIELD, null, now, scanResult.SSID);
}
if (expressionIdsPerValuePath.containsKey(BSSID_FIELD)) {
putValueTrimSize(BSSID_FIELD, null, now, scanResult.BSSID);
}
if (expressionIdsPerValuePath.containsKey(LEVEL_FIELD)) {
for (String id : registeredConfigurations.keySet()) {
boolean matching = true;
if (registeredConfigurations.get(id).containsKey(
SSID_FIELD)) {
matching = matching
&& (registeredConfigurations.get(id)
.getString(SSID_FIELD)
.equals(scanResult.SSID));
}
if (registeredConfigurations.get(id).containsKey(
BSSID_FIELD)) {
matching = matching
&& (registeredConfigurations.get(id)
.getString(BSSID_FIELD)
.equals(scanResult.BSSID));
}
if (matching) {
Log.w(TAG, "matching result found!");
putValueTrimSize(LEVEL_FIELD, null, now, scanResult.level);
} else {
Log.d(TAG, "No matching result found!");
}
}
}
}
}
};
/**
* The thread we use to poll wifi.
*/
private Thread wifiPoller = new Thread() {
public void run() {
while (!stopPolling) {
long start = System.currentTimeMillis();
if (registeredConfigurations.size() > 0) {
Log.d(TAG, "Starting WiFi scan.");
wifiManager.startScan();
}
try {
long waitTime = Math.max(
1,
start
+ currentConfiguration
.getLong(DISCOVERY_INTERVAL)
- System.currentTimeMillis());
Log.d(TAG, "Waiting for " + waitTime + " ms.");
synchronized (wifiPoller) {
wifiPoller.wait(waitTime);
}
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while waiting.", e);
}
}
}
};
@Override
public final String[] getValuePaths() {
return new String[] { SSID_FIELD, BSSID_FIELD, LEVEL_FIELD };
}
@Override
public final void initDefaultConfiguration(final Bundle defaults) {
defaults.putLong(DISCOVERY_INTERVAL, DEFAULT_DISCOVERY_INTERVAL);
}
@Override
public final void onConnected() {
SENSOR_NAME = "WiFi Sensor";
wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
}
@Override
public final void register(final String id, final String valuePath,
final Bundle configuration) {
if (registeredConfigurations.size() == 1) {
registerReceiver(wifiReceiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
if (!wifiPoller.isAlive()) {
wifiPoller.start();
} else {
synchronized (wifiPoller) {
wifiPoller.notifyAll();
}
}
}
updatePollRate();
}
/**
* Updates the polling rate when we get a new registration.
*/
private void updatePollRate() {
boolean keepDefault = true;
long updatedPollRate = Long.MAX_VALUE;
for (Bundle configuration : registeredConfigurations.values()) {
if (configuration.containsKey(DISCOVERY_INTERVAL)) {
keepDefault = false;
updatedPollRate = Math.min(updatedPollRate,
configuration.getLong(DISCOVERY_INTERVAL));
}
}
if (keepDefault) {
currentConfiguration.putLong(DISCOVERY_INTERVAL,
DEFAULT_DISCOVERY_INTERVAL);
} else {
currentConfiguration.putLong(DISCOVERY_INTERVAL, updatedPollRate);
}
}
@Override
public final void unregister(final String id) {
if (registeredConfigurations.size() == 0) {
unregisterReceiver(wifiReceiver);
}
updatePollRate();
}
@Override
public void onDestroySensor() {
try {
unregisterReceiver(wifiReceiver);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Error unregistering", e);
}
stopPolling = true;
wifiPoller.interrupt();
super.onDestroySensor();
}
}