Application never receives RSSI_CHANGED_ACTION - android

I am new to Android programming and am trying to understand the concept of BroadcastReceivers. In order to help myself, I am just trying to write a small application that monitors Wifi signal strength.
Now, from my understanding I can simply wait to receive the RSSI_CHANGED_ACTION broadcasted by the system. The RSSI should change frequently which means I should be receiving this notification frequently...however, never do I receive it once. I have watered my code down to the bare minimum so it just logs a message when the notification is received.
public class RssiActivity extends Activity {
public BroadcastReceiver rssiReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d("Rssi", "RSSI changed");
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public void onResume() {
super.onResume();
registerReceiver(rssiReceiver, new IntentFilter(WifiManager.RSSI_CHANGED_ACTION));
Log.d("Rssi", "Registered");
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(rssiReceiver);
Log.d("Rssi", "Unregistered");
}
}
I have already seen this post Android: How to monitor WiFi signal strength and it doesn't seem to help me. I have also tried the code sample here http://android-er.blogspot.com/2011/01/check-rssi-by-monitoring-of.html and it never updated the RSSI value either. I'm quite confused as to why this is. Any help you can give me would be greatly appreciated. Thanks!

So, I had the same problem that you did, wanting to an updated RSSI value as the user walked around, etc, and I could not solve it using RSSI_CHANGED_ACTION.
Like the issue you're having, my callback would not be called correctly. Strangely, it was only called once, when the activity was created, and then never again.
My Workaround
In your onCreate(), register a callback for SCAN_RESULTS_AVAILABLE_ACTION. Then call WifiManager.startScan().
Now, in your callback, do:
WifiManager wifiMan=(WifiManager)getActivity().getSystemService(Context.WIFI_SERVICE);
int newRssi = wifiMan.getConnectionInfo().getRssi();
wifiMan.startScan();
Now you have a loop, where the callback initiates a scan, receives the results, and initiates another scan.
It's gross and will suck a lot of power, however, you can watch the RSSI values change as you walk around.
Full Code
(note that I use onResume and onPause to register and unregister, so it will only scan repeatedly, e.g. waste battery, when the activity is onscreen)
#Override
public void onResume() {
super.onResume();
//Note: Not using RSSI_CHANGED_ACTION because it never calls me back.
IntentFilter rssiFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
this.registerReceiver(myRssiChangeReceiver, rssiFilter);
WifiManager wifiMan=(WifiManager)getActivity().getSystemService(Context.WIFI_SERVICE);
wifiMan.startScan();
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(myRssiChangeReceiver);
}
/**
* Broadcast receiver to update
*/
private BroadcastReceiver myRssiChangeReceiver
= new BroadcastReceiver(){
#Override
public void onReceive(Context arg0, Intent arg1) {
WifiManager wifiMan=(WifiManager)getActivity().getSystemService(Context.WIFI_SERVICE);
wifiMan.startScan();
int newRssi = wifiMan.getConnectionInfo().getRssi();
Toast.makeText(getActivity(), ""+newRssi, Toast.LENGTH_SHORT).show();
}};
Sorry I'm so late, I just had to find out I had to solve your problem :P

WifiManager.RSSI_CHANGED_ACTION is triggered when the RSSI levels change. I.E. you lose or win a wifi bar. It does not happen that often.
My guess is it's sticky so it triggers when registered.
As said, the best way I found to solve the problem is through WifiManager.SCAN_RESULTS_AVAILABLE_ACTION .

are you shure that it has to trigger (meaning are you shure the signal strength is changing)? have you read the BroadcastReciever Dokumentation?
Note: If registering a receiver in your Activity.onResume() implementation, you should unregister it in Activity.onPause(). (You won't receive intents when paused, and this will cut down on unnecessary system overhead). Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack.
Try to register your reciever inside of your AndroidManifest.

Related

Fragment's BroadcastReceiver onCreate method does not get called

I have a simple Fragment within my Activity in which I enable and disable Bluetooth adapter and I want to listen to Bluetooth Adapter state changes with a BroadcastReceiver from within the Fragment. The reason is that I want to directly change the Fragment's UI elements upon Bluetooth state change. This is my code:
public class FragmentBT extends Fragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
IntentFilter iFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(BtStateChangedReceiver, iFilter);
}
#Override
public void onDestroy()
{
super.onDestroy();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(BtStateChangedReceiver);
}
public BroadcastReceiver BtStateChangedReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
... change UI based on the extra data from intent ...
}
}
}
When I enable or disable BT in my device using Action Buttons in my Fragment's ActionBar, the BT goes on and off, but my receiver never gets called. I never get into the receiver's onReceive method. I realize this is a pretty common question here, but I tried the sollutions from several but neither worked (and all are incorporated into my current code).
Thank you for any advice!
Try this:
getActivity().registerReceiver(BtStateChangedReceiver, iFilter);
getActivity().unregisterReceiver(BtStateChangedReceiver);
The docs say that 'LocalBroadcastManager' is used to 'register for and send broadcasts of Intents to local objects within your process'.

Can LocalBroadcastManager detect WifiManager.NETWORK_STATE_CHANGED_ACTION changes?

I'd like to notify my Activity of any Wifi connection changes using the BroadcastReceiver. Since this broadcast is within the application I'm trying to use the more efficient LocalBroadcastManager object.
However no matter what I do, the BroadcastReceiver.onReceive() method will not fire. I may have wired it up incorrectly, or perhaps the WifiManager.NETWORK_STATE_CHANGED_ACTION action I'm listening for cannot be registered against a LocalBroadcastManager? Any help or clarification would be appreciated.
Here's a sample of my Activity class which contains all the logic.
public class MyActivity extends ActionBarActivity {
private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
{
// Do something
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
IntentFilter wifiStatusIntentFilter = new IntentFilter();
wifiStatusIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
wifiStatusIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(wifiReceiver, wifiStatusIntentFilter);
}
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(wifiReceiver);
}
protected void onResume() {
super.onResume();
IntentFilter wifiStatusIntentFilter = new IntentFilter();
wifiStatusIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(wifiReceiver, wifiStatusIntentFilter);
}
}
When I switch the wifi on my mobile on and off, or enter and leave the wifi range, the onReceive() method is never fired.
You can't receive WifiManager.NETWORK_STATE_CHANGED_ACTION with LocalBroadcastManager. LocalBroadcastManager works only within your process.
Helper to register for and send broadcasts of Intents to local objects
within your process. This is has a number of advantages over sending
global broadcasts with sendBroadcast(Intent):
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes
they can exploit.
It is more efficient than sending a global broadcast through the system.
You should use registerReceiver of Context
Since this broadcast is within the application I'm trying to use the more efficient LocalBroadcastManager object.
That only works for broadcasts that you send via LocalBroadcastManager. It does not work for system broadcasts, particularly those sent by other processes.
perhaps the WifiManager.NETWORK_STATE_CHANGED_ACTION action I'm listening for cannot be registered against a LocalBroadcastManager?
Correct.

Google Glass How to know if the glass is worn

I know this problem is really vague but i am really looking for a informative answer of how to do it.. or stuff like that..
A question on Stackoverflow already..
There are two ways to do it. One is the on Head wake and the other is notification glance. Can these be accessed for glassware apps. Can we basically control the glass rear view camera when inside an app and verify whether a user has actually worn it rather than just having a vague access with head wake or notificaiton glance.
You can listen to the ACTION_ON_HEAD_STATE_CHANGED broadcast Intent to know if the user is wearing Glass or not: this requires that the user has turned this feature on.
To do so, create a BroadcastReceiver to handle the Intent and register it within your Activity:
BroadcastReceiver mOnHeadStateChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean isOnHead = intent.getBooleanExtra(Intents.EXTRA_IS_ON_HEAD, false);
// Process the intent.
}
};
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(Intents.ACTION_ON_HEAD_STATE_CHANGED);
registerReceiver(mOnHeadStateChangedReceiver, filter);
}
#Override
protected void onPause() {
unregisterReceiver(mOnHeadStateChangedReceiver);
super.onPause();
}
This example is using an Activity but this can be done in a Service or anywhere you have access to a valid Context.

call broadcast receiver random times when wi-fi state change in android 4.2.2

My goal is print log when change wi-fi state.
I use below code.
MainActivity.java (Main Activity)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this,WiFiService.class));
}
#Override
protected void onStart()
{
super.onStart();
Log.d("Start Service", "Start Service");;
startService(new Intent(this,WiFiService.class));
}
}
WiFiService.java (Service)
public class WiFiService extends Service
{
WiFiBroadCasetReceiver brod;
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
brod=new WiFiBroadCasetReceiver();
this.registerReceiver(brod, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
WiFiBroadCasetReceiver.java (BroadcastReceiver)
public class WiFiBroadCasetReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context arg0, Intent arg1)
{
Log.d("on receiver", "receiver");
}
}
AndroidManifest.xml
<application>
........
........
<receiver android:name=".WiFiBroadCasetReceiver" >
<intent-filter>
<action android:name="android.net.wifi.supplicant.STATE_CHANGE" />
</intent-filter>
</receiver>
</application>
Problem :
Above code is working fine in android 4.0 and lower versions. When I change state of wi-fi, broadcast receiver is call random times. So, log is print random times. I need only one time. It work fine all android version remains android 4.1.0. or higher version(Jelly Bean). I use android.net.wifi.WIFI_STATE_CHANGED. But still same error occur.
Several points should be addressed in your question.
First, you might be confusing the state of "android.net.wifi.supplicant.STATE_CHANGE" and "android.net.wifi.WIFI_STATE_CHANGED". And I think what you really want is the later one. See the comment from the source code.
/**
* Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
* enabling, disabling, or unknown. One extra provides this state as an int.
* Another extra provides the previous state, if available.
*
* #see #EXTRA_WIFI_STATE
* #see #EXTRA_PREVIOUS_WIFI_STATE
*/
#SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WIFI_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_STATE_CHANGED";
and
/**
* Broadcast intent action indicating that a connection to the supplicant has
* been established (and it is now possible
* to perform Wi-Fi operations) or the connection to the supplicant has been
* lost. One extra provides the connection state as a boolean, where {#code true}
* means CONNECTED.
* #see #EXTRA_SUPPLICANT_CONNECTED
*/
#SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
"android.net.wifi.supplicant.CONNECTION_CHANGE";
Second, why you got multiple broadcast callbacks? And the number of times is random? I think you might need to check your code carefully:
1. You start the service twice, once in Activity.onCreate() and once in Activity.onStart()
2. You register your broadcast receiver twice, once in AndroidManifest.xml and once in Service.onStart()
3. The most important thing is that you will create a new instance of your broadcast receiver instance in your Service.onStart(). That is to say, whenever your service is start, a new receiver will be created and registered. And looking back on 1, you see every time you bring you Activity back will call the service to start again.
So the random times of callback is because your bad code. Please just remove all the broadcast registers, left only the one in the AndroidManifest.xml
Finally, why you cannot make it work on JellyBean later? I think this is because you haven't specified the correct action. Please try "android.net.wifi.WIFI_STATE_CHANGED" instead of "android.net.wifi.supplicant.STATE_CHANGE" and try again.
The broadcast is received whenever the supplicant state of the wifi changes. Since over the course of establishing a connection this will change multiple times, multiple broadcasts are expected. (I remember having seen this on 2.3 devices also but I mostly use the connectivity change broadcast to check connectivity change so I might be incorrect).
The workaround you can do is, in your broadcast receiver check the extras include in the intent which indicates the SupplicantState. If the supplicant state in the extra is equal to SupplicantState.COMPLETED (wifi is connected and authenticated) then only implement your app logic otherwise ignore the broadcast.

Inform Activity from a BroadcastReceiver ONLY if it is in the foreground

Maybe it's easy, but I couldn't really figure this out right so far... I got a BroadcastReceiver waiting to get triggered by the AlarmMangager - this works fine.
Now: because the event, if it occurs, needs to refresh some elements on screen of the main Activity, I would like to send an Intent from that background BroadcastReceiver to my Activity - but only if it is currently in the foreground, aka active.
If it is not running or not visible, I don't care - and the last thing I want to do is start the Activity by my intent! I handle repainting of the views in my onResume() method, so I don't care at all.
Any hints on how to do that?
Thanks!
EDIT: my BroadcastReceiver is waiting for alarms that must be notified to the user. So, it must be there and declared in the manifest. The problem is: it will have to decide whether the mentioned Activity is currently up in front or not.
I believe that you're familiar with AlarmManager now (creating a new Alarm, register a receiver...) so I will not talk about that. Just give you a solution for your question.
Instead of registering a BroadcastReceiver in a class file and in manifest, you only create a new BroadcastReceiver in your activity, and then, register it in onResume method, and unregister it in onPause method, sth like this in your activity:
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do something
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction("your alarm action");
...
}
#Override
protected void onResume() {
registerReceiver(mIntentReceiver, mIntentFilter);
...
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(mIntentReceiver);
...
super.onPause();
}
The receiver will only receive the alarm intent when your activity is in foreground :)
(Sorry if my English is not clear)
So this is almost Bino's answer, but: instead of moving the receiver into the activity, use two receivers, with different Intents. The first one is your original alarm Intent, with a receiver registered in the manifest as you already have, and then that receiver sends a second broadcast intent, which is handled by a receiver registered by the activity as Bino says.
I've done this in my own timer project, on github. Here are the alarm receiver and the requery receiver. Hope that helps.

Categories

Resources