Android Wifi Scan - BroadcastReceiver for SCAN_RESULTS_AVAILABLE_ACTION not getting called

10,805

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);
}
Share:
10,805
Ofek Agmon
Author by

Ofek Agmon

Updated on June 04, 2022

Comments

  • Ofek Agmon
    Ofek Agmon almost 2 years

    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?

  • Ofek Agmon
    Ofek Agmon over 7 years
    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?
  • Ofek Agmon
    Ofek Agmon over 7 years
    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.
  • Ofek Agmon
    Ofek Agmon over 7 years
    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 million
  • gus27
    gus27 over 7 years
    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.
  • Ofek Agmon
    Ofek Agmon over 7 years
    Got it. Thanks a lot!