I am working with Android. I have a service that is getting data from a wifi network. I would like to alert the user if they lose connection to that wifi address. I have been trying to work it out, and I think I have narrowed it down to using a BroadcastReceiver. Here is my implementation so far...
WifiReceiver receiverWifi;
protected void onCreate(Bundle savedInstanceState) {
receiverWifi = new WifiReceiver();
registerReceiver(receiverWifi, new IntentFilter(
WifiManager.NETWORK_STATE_CHANGED_ACTION));
}
class WifiReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//Does this get executed when the network changes?
}
}
Specifically, my question is, how can I edit my code to run in my service that will let the user know through a notification that the wifi they were connected to was lost or was changed? Thank you for any help.
Related
In my application I have to get notified whenever the device connects or disconnects from a WIFI network. For this I have to use a BroadcastReceiver but after reading through different articles and questions here on SO I'm a bit confused which Broadcast action I should use for this. In my opinion I have three choices:
SUPPLICANT_CONNECTION_CHANGE_ACTION
NETWORK_STATE_CHANGED_ACTION
CONNECTIVITY_ACTION
To reduce resources I really only want to get notified whenever the device is CONNECTED to a WIFI network (and it has received an IP address) or when the device has DISCONNECTED from one. I do not care about the other states like CONNECTING etc.
So what do you think is the best Broadcast action I should use for this? And do I have to manully filter the events (because I receieve more then CONNECTED and DISCONNECTED) in onReceive?
EDIT: As I pointed out in a comment below I think SUPPLICANT_CONNECTION_CHANGE_ACTION would be the best choice for me but it is never fired or received by my application. Others have the same problem with this broadcast but a real solution for this is never proposed (in fact other broadcasts are used). Any ideas for this?
You can go for WifiManager.NETWORK_STATE_CHANGED_ACTION works.
Register receiver with WifiManager.NETWORK_STATE_CHANGED_ACTION Action, either in Manifest or Fragment or Activity, which ever suited for you.
Override receiver :
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean connected = info.isConnected();
if (connected)
//call your method
}
}
Please try
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction("android.net.wifi.STATE_CHANGE");
registerReceiver(networkChangeReceiver, filter);
}
#Override
protected void onDestroy() {
unregisterReceiver(networkChangeReceiver);
super.onDestroy();
}
and
BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (!AppUtils.hasNetworkConnection(context)) {
showSnackBarToast(getNetworkErrorMessage());
}
}
};
I am using this and it is working for me. Hope it will help you out.
I am fairly new to android application development. I am working on an android application to ping access points to access their RSSI values to estimate a user's location.
While I currently have this 'working', I believe there to be a bug within my implementation that is creating too many calls to "onReceive()". Over the life of the application, the amount of calls to this function ramps up on a linear scale.
My goal with the code I'm about to post is to simply scan WiFi access points, get their RSSI values and then continuously loop. Battery life is no issue, performance is a much more important metric.
MainActivity.java:
Handler handler = new Handler();
final Runnable locationUpdate = new Runnable() {
#Override
public void run() {
getLocation();
//customView.setLocation(getX_pixel(curLocation.getX()), getY_pixel(curLocation.getY()));
//customView.invalidate();
handler.postDelayed(locationUpdate, 1000);
}
};
private void getLocation() {
Context context = getApplicationContext();
WifiScanReceiver wifiReceiver = new WifiScanReceiver();
registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiManager.startScan();
Log.d("START SCAN CALLED", "");
}
Then in the same file, in the onCreate() method:
handler.post(locationUpdate);
Then in the same file, outside of the onCreate() method:
class WifiScanReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent intent) {
WifiManager wifiManager = (WifiManager) c.getSystemService(Context.WIFI_SERVICE);
List<ScanResult> scan = wifiManager.getScanResults();
// Application specific code:
sortScan(scan);
count+= 1;
System.out.println("Count: " + count);
}
}
};
I confirmed the ramping/thread problem because I incremented and output to the console when the program reaches "sortScan(scan)", and you can clearly see that the results are linearly ramping.
Like I said early, my intention is to simply re-scan as soon as the first scan finishes and loop it for the entire life of the application.
Any help will be greatly appreciated, thank you.
You are repeatedly registering your receiver which is not necessary.Just register the WifiScanReceiver only once in onCreate(). Then call start scan in the getLocation() function.
WifiManager wifiManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
Context context = getApplicationContext();
WifiScanReceiver wifiReceiver = new WifiScanReceiver();
registerReceiver(wifiReceiver, new
IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
wifiManager =
(WifiManager)context.getSystemService(Context.WIFI_SERVICE);
Handler handler = new Handler();
final Runnable locationUpdate = new Runnable() {
#Override
public void run() {
getLocation();
//This line will continuously call this Runnable with 1000 milliseconds gap
handler.postDelayed(locationUpdate, 1000);
}
};
private void getLocation() {
wifiManager.startScan();
Log.d("START SCAN CALLED", "");
}
}
class WifiScanReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent intent) {
if(intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)){
//New scan results are available. Arrange a callback to the activity here.
}
}
}
You should not do heavy processing in the onReceive(). Arrange a callback to the Activity to do that.
You're creating a new broadcast receiver every time you run getLocation(). Every one of those receivers gets the WifiManager.SCAN_RESULTS_AVAILABLE_ACTION broadcast. Try allocating and registering the receiver once in an appropriate context, and only calling startScan() in getLocation().
The best way to continuously loop a scan for RSSI values for WiFi APs is to simply start the first scan in the OnCreate. Then in the onReceive callback from the BroadcastReceiver, call start scan again.
I am writing a simple activity that programmatically joins a WiFi network. Here is my code:
public class WiFiSettings extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wi_fi_settings);
WifiManager oWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
configure(oWifiManager, "my-wifi", "1234", "WPA");//wrote this method myself. I know that it works. The phone is able to join the network.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
Poop bigone = new Poop();
registerReceiver(bigone, intentFilter);
}
private class Poop extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
Log.i("it worked", "!");
}
}
}
Why is the onReceive method not being called back? The configure method works and is able to successfully join a given network, but upon joining or failing to join a network, the onReceive method doesn't get called.
Fixed the problem by changing the intent filter...
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
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);
}
I have Googled and find many sites saying about 'disabling Wifi radio'. But in my case, I just want the android device to disconnect from a specific wifi network(SSID preknown) without switching OFF the WiFi radio. Please give me some insights on this issue
Wow this shouldn't have taken a month to be answered.
Here's the easiest way that I usually use:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.disconnect();
discon = new DisconnectWifi();
registerReceiver(discon, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
Where DisconnectWifi is just a small class the extends BroadcastReceiver:
public class DisconnectWifi extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent intent) {
if(!intent.getParcelableExtra(wifi.EXTRA_NEW_STATE).toString().equals(SupplicantState.SCANNING)) wifi.disconnect();
}
}