Android Wifi Scan - BroadcastReceiver for SCAN_RESULTS_AVAILABLE_ACTION not getting called
Asked Answered
U

1

6

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?

  1. Does wifiManager.startScan(); runs the scan only once? or it is a function that keeps listening to incoming "Scan Results"?

  2. And obviously, why does the receiver doesn't get called?

Ulcer answered 12/9, 2016 at 17:33 Comment(1)
did u find any solution??Torry
P
14

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);
}
Plastid answered 12/9, 2016 at 17:50 Comment(5)
what I meant by asking if its a "single scan" was - will I keep getting notified in onResponse when Wifi networks are updating? it seems that it does - because when I run the code and just go to the Settings -> Wifi Settings, the onResponse is getting called multiple times. so, just to make sure, it is not necessary to call startScan() multiple times , once is enough, correct?Ulcer
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.Ulcer
thanks for your answer. so, as far as you know, it can't be done without calling it repeatedly? my goal is actually to listen to changes in availability for only one Specific network with a Specific SSID. I asked about the whole network list because I figured that's the only way to do it (go over the list and check my specific network), but maybe there is a way to listen to availability changes for a specific network? thanks a millionUlcer
Yes, considering the xxx_ACTIONs the Android Wifi API provides I don't think there's any other way but scanning repeatedly. You can listen for changes of the current connected network with NETWORK_STATE_CHANGED_ACTION but you can't restrict this to a specific SSID.Plastid
Got it. Thanks a lot!Ulcer

© 2022 - 2024 — McMap. All rights reserved.