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);
Related
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.
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 the following class for connection listener
public class connectionListener{
public ConnectivityManager conMgr;
public htmlParserListener vystrahyListener;
public htmlParserListener podmienkyListener;
private ConnectivityBroadcastReceiver mReceiver;
public connectionListener(ConnectivityManager conMgr, htmlParserListener vystrahyListener, htmlParserListener podmienkyListener){
this.conMgr = conMgr;
this.vystrahyListener = vystrahyListener;
this.podmienkyListener = podmienkyListener;
}
private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("connected");
}
}
public synchronized void startListening(Context context) {
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mReceiver, filter);
System.out.println("start");
}
}
I instantiate it with this code (from MainActivity):
connectionListener conLst = new connectionListener(conMgr, vystrahyListener, podmienkyListener);
conLst.startListening(this);
However I am getting "start" at output so startListening method works but I dont get "connected" when I disable or enable mobile data. So it looks like my BroadcastReceiver is not working. What am I doing wrong?
Thanks in forward
I dont get "connected" when I disable or enable mobile data.
That is correct. This Broadcast is not triggered when mobile data is enabled or disabled but only when the network connectivity changes.
So it looks like my BroadcastReceiver is not working. What am I doing wrong?
Your BroadcastReceiver is working correctly. However, you expect the CONNECTIVITY_ACTION Broadcast to be triggered at an event where it isn't triggered.
Note: there exists no (other) Broadcast which is sent by the system when the enabled state of mobile data is changed. You also have no option to register a Listener for this change.
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.
I am listening to both connecting and disonnecting the power for my galaxy.
I have creatd 2 BroadCastReceivers, one for connect, and one for disconnect.
When I try to implement, I only get the connected data, even when disconnecting the power cable.
The intent is sent, but looks like it's the wrong one.
Here is the activity code:
// Handle Power On
PowerConnectedBCReceiver myPowerConnectedBCReceiver = new PowerConnectedBCReceiver();
IntentFilter intentPowerOnFilter = new IntentFilter();
intentPowerOnFilter.addAction("android.intent.action.ACTION_POWER_CONNECTED");
registerReceiver(myPowerConnectedBCReceiver, intentPowerOnFilter);
BroadcastReceiver PowerConnectedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
showToast("connected");
}
};
// Handle Power Off
PowerConnectedBCReceiver myPowerDisonnectedBCReceiver = new PowerConnectedBCReceiver();
IntentFilter intentPowerDisconnectedOnFilter = new IntentFilter();
intentPowerDisconnectedOnFilter.addAction("android.intent.action.ACTION_POWER_DISCONNECTED");
registerReceiver(myPowerDisonnectedBCReceiver, intentPowerDisconnectedOnFilter);
BroadcastReceiver PowerDisconnectedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
showToast("disconnected");
}
};
Registering both BC to do the work
registerReceiver(PowerDisconnectedReceiver, new IntentFilter("com.neglected.POWER_DISCONNECTED"));
registerReceiver(PowerConnectedReceiver, new IntentFilter("com.neglected.POWER_CONNECTED"));
BroadCast connected code:
public class PowerConnectedBCReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Phone was connected to power" , Toast.LENGTH_LONG).show();
Intent tIntent = new Intent("com.neglected.POWER_CONNECTED");
context.sendBroadcast(tIntent);
}
}
Broadcast disconnected code:
public class PowerDisconnectedBCReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Phone was disconnected from power" , Toast.LENGTH_LONG).show();
Intent tIntent = new Intent("com.neglected.POWER_DISCONNECTED");
context.sendBroadcast(tIntent);
}
}
IS the code wrong?
Can I listen to both actions? seperately?
I can't see extra been sent with the CONNNECTED Action, is there?
Not sure what your last two classes (*BCReeivers) are supposed to be doing. Your first block of code looks ok. It will be limited to the lifecycle of the enclosing Activity if that matters.
For the Galaxy S, you may not be able to rely on those Intents. In particular, I have found that the Verizon Fascinate (their version of the Galaxy S) to be very buggy. See here: http://devblog.bu.mp/how-to-ddos-yourself
There was an error in my Broadcast instantiation. I mistakenly used the PowerConnectedBCReceiver instead of PowerDisconnectedBCReceiver
problem solved.