/** * Funf: Open Sensing Framework * Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland. * Acknowledgments: Alan Gardner * Contact: nadav@media.mit.edu * * This file is part of Funf. * * Funf 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 (at your option) any later version. * * Funf 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 Funf. If not, see <http://www.gnu.org/licenses/>. */ package edu.mit.media.funf.probe.builtin; import java.util.ArrayList; import java.util.List; import android.Manifest; 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.net.wifi.WifiManager.WifiLock; import android.os.Bundle; import android.util.Log; import edu.mit.media.funf.Utils; import edu.mit.media.funf.probe.Probe; import edu.mit.media.funf.probe.builtin.ProbeKeys.WifiKeys; public class WifiProbe extends Probe implements WifiKeys { public static final long DEFAULT_PERIOD = 60L * 5L; private static final String TAG = WifiProbe.class.getName(); private WifiManager wifiManager; private int numberOfAttempts; private int previousWifiState; // TODO: should this be persisted to disk? private BroadcastReceiver scanResultsReceiver; private WifiLock wifiLock; @Override public Parameter[] getAvailableParameters() { return new Parameter[] { new Parameter(Parameter.Builtin.PERIOD, DEFAULT_PERIOD), new Parameter(Parameter.Builtin.START, 0L), new Parameter(Parameter.Builtin.END, 0L) }; } @Override public String[] getRequiredPermissions() { return new String[] { Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.CHANGE_WIFI_STATE, }; } @Override public String[] getRequiredFeatures() { return new String[] { "android.hardware.wifi" }; } @Override protected String getDisplayName() { return "Nearby Wifi Devices Probe"; } @Override public void sendProbeData() { Bundle data = new Bundle(); List<ScanResult> results = wifiManager.getScanResults(); ArrayList<ScanResult> nonNullResults = new ArrayList<ScanResult>(); if (results != null) { nonNullResults.addAll(results); } data.putParcelableArrayList(SCAN_RESULTS, nonNullResults); sendProbeData(Utils.getTimestamp(), data); } @Override protected void onEnable() { wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE); numberOfAttempts = 0; scanResultsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) { sendProbeData(); if (isRunning()) { stop(); } } } }; registerReceiver(scanResultsReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); } @Override protected void onDisable() { unregisterReceiver(scanResultsReceiver); } @Override public void onRun(Bundle params) { acquireWifiLock(); saveWifiStateAndRunScan(); } private void saveWifiStateAndRunScan() { int state = wifiManager.getWifiState(); if(state==WifiManager.WIFI_STATE_DISABLING ||state==WifiManager.WIFI_STATE_ENABLING){ registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context ctx, Intent i) { if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(i.getAction())) { try { unregisterReceiver(this); // TODO: sometimes this throws an IllegalArgumentException saveWifiStateAndRunScan(); } catch (IllegalArgumentException e) { Log.e(TAG, "Unregistered WIFIE_STATE_CHANGED receiver more than once."); } } } }, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); } else { previousWifiState = state; runScan(); } } private void loadPreviousWifiState() { // Enable wifi if previous sate was enabled, otherwise disable wifiManager.setWifiEnabled(previousWifiState == WifiManager.WIFI_STATE_ENABLED); } private void runScan() { numberOfAttempts += 1; int state = wifiManager.getWifiState(); Log.i(TAG, "WiFi state: " + state); if (state == WifiManager.WIFI_STATE_ENABLED) { boolean successfulStart = wifiManager.startScan(); if (successfulStart) { Log.i(TAG, "WIFI scan started succesfully"); } else { Log.e(TAG, "WIFI scan failed."); } numberOfAttempts = 0; } else if (numberOfAttempts <= 10) { // Prevent infinite recursion by keeping track of number of attempts to change wifi state // TODO: investigate what is needed to keep Service alive while waiting for wifi state Log.i(TAG, "Waiting for WiFi enabled, will retry " + (10 - numberOfAttempts) + " more times"); registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context ctx, Intent i) { if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(i.getAction())) { try { unregisterReceiver(this); runScan(); } catch (IllegalArgumentException e) { // Not sure why, but sometimes this is not registered // Probably two intents at once } } } }, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); // no use asking to enable, if already enabling if (state != WifiManager.WIFI_STATE_ENABLING) wifiManager.setWifiEnabled(true); // increasing the counter without waiting makes no sense, so we wait a second. try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { // After 10 attempts stop trying // TODO: possibly send error stop(); } } @Override public void onStop() { releaseWifiLock(); loadPreviousWifiState(); } private void acquireWifiLock() { wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, TAG); wifiLock.setReferenceCounted(false); wifiLock.acquire(); } private void releaseWifiLock() { if (wifiLock != null) { if (wifiLock.isHeld()) { wifiLock.release(); } wifiLock = null; } } }