Here is my code:
public class FloatWifiManager implements IWifiManager {
private WifiManager wifiManager;
private BroadcastReceiver wifiScanReceiver;
public FloatWifiManager(Context context) {
...
wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// Registering Wifi Receiver
wifiScanReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context c, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
// not getting called, only after running app and manually going to the wifi settings in android
}
}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
context.registerReceiver(wifiScanReceiver, intentFilter);
wifiManager.startScan();
}
I registered the BroadcastReceiver
exactly like I saw in all the examples, and did startScan
.
What happens is, the wifi list is changing (for sure, I tested), but onReceive
is not called if I just stay in the app.
What makes onReceive
finally to be called - is to launch the app, leave it running, and going in the android phone to Settings -> Wifi settings. when going there, all of the sudden the List is updating and onReceive
is called.
What's the problem here?
Does wifiManager.startScan();
runs the scan only once? or it is a function that keeps listening to incoming "Scan Results"?
And obviously, why does the receiver doesn't get called?
Yes, startScan()
requests only one single scan.
You can get rid of the if (intent.getAction().equals(..))
condition. Anything else seems to be ok.
just to make it clear - my goal to have a receiver that will get called every time the Wifi networks list are changing, without having to click a "start scan" button.
AFAIK it is not possible to get notified whenever any of the wifi networks change. You can only request a scan with startScan
- and of course you can call startScan
repeatedly using a Thread or Handler.
The docs say that SCAN_RESULTS_AVAILABLE_ACTION
is called when "an access point scan has completed, and results are available from the supplicant". How and when a scan is proceeded depends on the implemention of the supplicant. Elenkov writes, that "Android devices rarely include the original wpa_supplicant code; the included implementation is often modified for better compatibility with the underlying SoC".
Scan for access points
This example scans for available access points and ad hoc networks. btnScan
activates a scan initiated by the WifiManager.startScan()
method. After the scan, WifiManager
calls the SCAN_RESULTS_AVAILABLE_ACTION
intent and the WifiScanReceiver
class processes the scan result. The results are displayed in a TextView
.
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
TextView txtWifiInfo;
WifiManager wifi;
WifiScanReceiver wifiReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wifi=(WifiManager)getSystemService(Context.WIFI_SERVICE);
wifiReceiver = new WifiScanReceiver();
txtWifiInfo = (TextView)findViewById(R.id.txtWifiInfo);
Button btnScan = (Button)findViewById(R.id.btnScan);
btnScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "Start scan...");
wifi.startScan();
}
});
}
protected void onPause() {
unregisterReceiver(wifiReceiver);
super.onPause();
}
protected void onResume() {
registerReceiver(
wifiReceiver,
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
);
super.onResume();
}
private class WifiScanReceiver extends BroadcastReceiver {
public void onReceive(Context c, Intent intent) {
List<ScanResult> wifiScanList = wifi.getScanResults();
txtWifiInfo.setText("");
for(int i = 0; i < wifiScanList.size(); i++){
String info = ((wifiScanList.get(i)).toString());
txtWifiInfo.append(info+"\n\n");
}
}
}
}
Permissions
The following permissions need to be defined in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
android.permission.ACCESS_WIFI_STATE
is necessary for calling WifiManager.getScanResults()
. Without android.permission.CHANGE_WIFI_STATE
you cannot initiate a scan with WifiManager.startScan()
.
When compiling the project for api level 23 or greater (Android 6.0 and up), either android.permission.ACCESS_FINE_LOCATION
or android.permission.ACCESS_COARSE_LOCATION
must be inserted. Furthermore that permission needs to be requested, e.g. in the onCreate
method of your main activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
String[] PERMS_INITIAL={
Manifest.permission.ACCESS_FINE_LOCATION,
};
ActivityCompat.requestPermissions(this, PERMS_INITIAL, 127);
}