/** * Filename: WifiSniffer.java (in org.repin.android.net.wifi) * This file is part of the Redpin project. * * Redpin is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * any later version. * * Redpin is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Redpin. If not, see <http://www.gnu.org/licenses/>. * * (c) Copyright ETH Zurich, Arno Fiva, Philipp Bolliger, 2010, ALL RIGHTS RESERVED. * * www.redpin.org */ package org.redpin.android.net.wifi; import java.util.List; import org.redpin.android.core.Measurement; import org.redpin.android.core.measure.WiFiReading; import android.app.Service; 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.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; /** * {@link WifiSniffer} is responsible for scanning the wirless network and * gathering measurement so that the server can try to locate the client. * * @author Arno Fiva (fivaa@student.ethz.ch) * */ public class WifiSniffer extends Service { /** Action being broadcasted whenever a new measurement was retrieved */ public static String WIFI_ACTION = "org.redpin.android.net.wifi.WIFI_ACTION"; private static final String TAG = WifiManager.class.getSimpleName(); WifiManager mWifi; Measurement mLastMeasurement; boolean stop = true; /** * {@inheritDoc} */ @Override public void onCreate() { mWifi = (WifiManager) getSystemService(Context.WIFI_SERVICE); registerReceiver(mStateReceiver, new IntentFilter( WifiManager.WIFI_STATE_CHANGED_ACTION)); registerReceiver(mResultReceiver, new IntentFilter( WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); } @Override public void onDestroy() { stop = true; unregisterReceiver(mStateReceiver); unregisterReceiver(mResultReceiver); mWifi = null; } /** * Start scanning immediately */ public void forceMeasurement() { stop = false; initiateSniff(); } /** * Retrieve measurement from last scan. * * @return {@link Measurement} */ public Measurement retrieveLastMeasurement() { return mLastMeasurement; } /** * Stop scanning and broadcasting new measurements. */ public void stopMeasuring() { stop = true; } @Override public IBinder onBind(Intent intent) { return mBinder; } /** * @see Binder */ public class LocalBinder extends Binder { public WifiSniffer getService() { return WifiSniffer.this; } } private final LocalBinder mBinder = new LocalBinder(); /** * Try to enable the wifi adapter if it is not already enabled or not * currently being enabled. Otherwise start the scanning directly. */ private void initiateSniff() { if (!mWifi.isWifiEnabled()) { if (mWifi.getWifiState() != WifiManager.WIFI_STATE_ENABLING) { if (!mWifi.setWifiEnabled(true)) return; } } else { mHandler.dispatchMessage(mHandler.obtainMessage(START_SCAN_MSG)); } } /** * {@link BroadcastReceiver} for reacting on the current wifi state. If the * wifi adapter is enabled, start a scan. */ private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mWifi.isWifiEnabled() && !stop) initiateSniff(); } }; /** * {@link BroadcastReceiver} for retrieving scanning results and to creating * a new {@link Measurement}. The measurement is then stored in * {@link mLastMeasurement}. */ private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //Do not listen to broadcast when not initiated scan //When no network is available, broadcasts are sent every few seconds if(stop) { Log.d(TAG, "Received not requested scan result"); return; } List<ScanResult> results = mWifi.getScanResults(); Measurement measurement = new Measurement(); for (ScanResult result : results) { WiFiReading reading = new WiFiReading(); reading.setBssid(result.BSSID); reading.setSsid(result.SSID); reading.setRssi(result.level); reading.setInfrastructure(result.capabilities .contains("[IBSS]")); reading.setWepEnabled(result.capabilities.contains("WEP") || result.capabilities.contains("WPA") || result.capabilities.contains("-EAP-")); measurement.addWiFiReading(reading); } mLastMeasurement = measurement; Intent wifiIntent = new Intent(WIFI_ACTION); sendBroadcast(wifiIntent); } }; private static final int START_SCAN_MSG = 1; private static final int SCAN_INTERVAL = 30; /** * The {@link WifiSniffer.mHandler} is responsible for initiating the actual * scanning and scheduling the next scan {@link SCAN_INTERVAL} seconds * later. */ private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (mWifi == null) { return; } if (stop) { Log.d(TAG, "Scanning stopped, skiping scan"); return; } if (msg.what == START_SCAN_MSG) { Log.i(TAG, "Starting scan"); mWifi.startScan(); /* * Remove any pending messages but make sure we are called back * after SCAN_INTERVAL seconds */ removeMessages(START_SCAN_MSG); sendMessageDelayed(obtainMessage(START_SCAN_MSG), SCAN_INTERVAL * 1000); } else { super.handleMessage(msg); } } }; }