I want to know the signal strength of my current cell tower on Android. After some research I found, that I should use a PhoneStateListener which listen for an update to get the value (strange way to do that IMHO).
So I want to get the signal as soon as I get it and stop the listener after. This is the code I use :
// object containing the information about the cell
MyGSMCell myGSMCell = new MyGSMCell(cid,lac);
// object listening for the signal strength
new GetGsmSignalStrength(myGSMCell, context);
...
public class GetGsmSignalStrength {
private MyGSMCell callback;
private TelephonyManager telMan;
private MyPhoneStateListener myListener;
public GetGsmSignalStrength(MyGSMCell callback, Context context) {
this.callback = callback;
this.myListener = new MyPhoneStateListener();
this.telMan = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
this.telMan.listen(this.myListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
private class MyPhoneStateListener extends PhoneStateListener
{
public void onSignalStrengthsChanged(SignalStrength signalStrength)
{
// get the strength
super.onSignalStrengthsChanged(signalStrength);
// return it to the MyGSMCell object to set the value
callback.setStrength(signalStrength.getGsmSignalStrength());
}
}
}
I would like to stop the listener as soon as I send a setStrength(value)
Any idea ?
Thank you
From the docs:
To unregister a listener, pass the listener object and set the events
argument to LISTEN_NONE (0).
So, add this to your listener:
telMan.listen(myListener, PhoneStateListener.LISTEN_NONE);
Related
My problem is, that in onCreate() method of my MainActivity I am creating new Thread object to which I want to pass reference to this activity, and than in that thread use it to call getSystemService(). But in the end, when I start the app it crashes and I get NullPointerException.
I have already found that problem could be that I am passing reference to activity befor super.onCreate(), but in my code super.onCreate() is performed before passing the reference.
This is my MainActivity's onCreate() method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Instance which contains thread for obtaining wifi info
final WifiInfoThread wifi_info = new WifiInfoThread(this);
....
}
And this is Thread class in which I am trying to get reference to system service
public class WifiInfoThread extends Thread {
// Constructor for passing context to this class to be able to access xml resources
Activity activity;
WifiInfoThread(Activity current) {
activity = current;
}
// Flag for stopping thread
boolean flag = false;
// Obtain service and WifiManager object
WifiManager current_wifi = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
// Runnable object passed to UIThread
Runnable uirunnable = new Runnable() {
#Override
public void run() {
// Get current wifi status
WifiInfo wifi_info = current_wifi.getConnectionInfo();
// Things with showing it on screen
TextView tv_output = (TextView) activity.findViewById(R.id.tv_output);
String info = "SSID: " + wifi_info.getSSID();
info += "\nSpeed: " + wifi_info.getLinkSpeed() + " Mbps";
tv_output.setText(info);
}
};
public void run() {
flag = true;
for(; flag; ) {
activity.runOnUiThread(uirunnable);
try {
this.sleep(500);
}
catch(InterruptedException e) {}
}
}
}
You are using activity.getSystemService before initializing activity. To get ride of this, move below line into Constructor
// Obtain service and WifiManager object
WifiManager current_wifi = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
Like
WifiManager current_wifi;
WifiInfoThread(Activity current) {
activity = current;
current_wifi = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
}
move the initialitation current_wifi in the Constructor of your Thread.
// Obtain service and WifiManager object
WifiManager current_wifi = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
in your case, activity is still a null reference. It gets a valid one after you assign it in the constructor
The other answers show you how to fix this. You should also know what is the reason for the NullPointerException: In java your code does not get executed in the order you write it. Every thing written outside of member functions (methods) gets executed first (sort of). Then the constructor is called. Hence you are calling Conetxt.getSystemService() on activity, which is null.
Also for background work, android has AsyncTask and IntentService. Look them up.
I got this error in my logcat
TelephonyManager : Hidden constructor called more than once per process!
And my PhoneListener is not working
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.e("state", "idle");
break;
case TelephonyManager.DATA_CONNECTED:
Log.e("state", "connected");
break;
}
};
};
telManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
It won't print out my log.
From the source code i got this:
/** Provides access to information about the telephony services on the device. Applications can use the methods in this class to determine telephony services and states, as well as to access some types of subscriber information. Applications can also register a listener to receive notification of telephony state changes.
You do not instantiate this class directly; instead, you retrieve a reference to an instance through {#link android.content.Context#getSystemService Context.getSystemService(Context.TELEPHONY_SERVICE)}. *
Note that access to some telephony information is permission-protected. Your application cannot access the protected * information unless it has the appropriate permissions declared in its manifest file. Where permissions apply, they are noted in the the methods through which you access the protected information. **/
public class TelephonyManager {
private static final String TAG = "TelephonyManager";
private static Context sContext;
private static ITelephonyRegistry sRegistry;
/** #hide */
public TelephonyManager(Context context) {
context = context.getApplicationContext();
if (sContext == null) {
sContext = context;
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
} else if (sContext != context) {
Log.e(TAG, "Hidden constructor called more than once per process!");
Log.e(TAG, "Original: " + sContext.getPackageName() + ", new: " +
context.getPackageName());
}
}
Are you creating multiple instance of TelephonyManger from different context? If so then the Error Log will show as the context is static.
I am currently writing an application for a client who wants to gather data regarding the signal strength at set intervals.
Currently I am using this code:
private static class MyPhoneStateListener extends PhoneStateListener
{
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength)
{
super.onSignalStrengthsChanged(signalStrength);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
InfoStore.setSignal(String.valueOf(signalStrength.getGsmSignalStrength()));
}
};
This works fine, however the client wants the signal strength in both level (I guess how many bars?), DBM, and ASU.
Anyone have any clue how to read the signal strengths using those different forms?
As mentioned by Charles Ma and Kevin Krumwiede the relevant Android methods are hidden (probably for good reason), however it is still possible to get the values by reflection. Thus one solution to original question:
private class MyPhoneStateListener extends PhoneStateListener
{
public static final int INVALID = Integer.MAX_VALUE;
public int signalStrengthDbm = INVALID;
public int signalStrengthAsuLevel = INVALID;
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength)
{
signalStrengthDbm = getSignalStrengthByName(signalStrength, "getDbm");
signalStrengthAsuLevel = getSignalStrengthByName(signalStrength, "getAsuLevel");
}
private int getSignalStrengthByName(SignalStrength signalStrength, String methodName)
{
try
{
Class classFromName = Class.forName(SignalStrength.class.getName());
java.lang.reflect.Method method = classFromName.getDeclaredMethod(methodName);
Object object = method.invoke(signalStrength);
return (int)object;
}
catch (Exception ex)
{
return INVALID;
}
}
}
In android 4.x the SignalStrength class has getAsuLevel, getDbm, as well as getLevel (bars) methods.
If you need this to work for older android versions, have a look at the source code and you can copy the implementations of those methods over.
http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.1.2_r1/android/telephony/SignalStrength.java/
The only thing that you can't get is the Lte measurements in older android versions, but you can probably use java reflection to see if the getLte* methods exist and call it.
Calculate dBm by
int SignalStrength_ASU = signalStrength.getGsmSignalStrength();
int SignalStrength_dBm = (2 * SignalStrength_ASU) - 113; // -> dBm
In some cases I don't want listen to state of my phone.
How to destroy object of PhoneStateListener class?
I create object this way
try {
phoneCallListener = new WnetPlayerPhoneCallListener();
TelephonyManager mTM = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(phoneCallListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch(Exception e) {
Log.e("PhoneCallListener", "Exception: "+e.toString());
}
In the documentation it states to pass the listener object and flag LISTEN_NONE to unregister a listener.
Per this answer, you should keep a reference to TelephonyManager and WnetPlayerPhoneCallListener, and set it to disabled, like so:
mTm.listen(phoneCallListener, PhoneStateListener.LISTEN_NONE);
Why they don't just have standard addListener() and removeListener() methods, I don't know, but this seems to be the accepted method for solving your problem.
I'm trying to creat an app that would save the current signal strength. So far I've seen many examples that are all extending PhoneStateListener, but all of them use a Toast to display this information, like in this example:
http://www.firstdroid.com/2010/05/12/get-provider-gsm-signal-strength/
I was wondering a couple of things:
a) Do I always have to use the PhoneStateListener AND override the onSignalStrengthsChanged(SignalStrength signalStrength) ?
b) How can I access the value signalStrength.getGsmSignalStrength() from outside the PhoneStateListener class?
Thanks in advance
U can try with it. I cant say its the final solution.If u want to access certain data from other activity, then try it with shared preference.Shared preference value is visible from other activities
I might be late to answer your question, but if you are still looking for the answer, here it is:
a) yes you have to use the PhoneStateListener and override the onSignalStrengthsChanged as, in my knowledge that is the only way to get current cells' signal strength for GSM. The listener is only called in big signal strength changes, so you yourself cannot control the listener. the listener will automatically update or make a toast when it is called. So, it is better to declare the listener and ask it to listen at onCreate().
b) For accessing the the RSSI value from outside the Listener is not really difficult, just store the value in a variable and make a method like getRSSI(), which will return you the value when its called. The example is given below:
public class GsmRSSI extends Activity{
MyPhoneStateListener MyListener;
TelephonyManager Tel;
ArrayList<String> signalStrength = new ArrayList<String>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyListener = new MyPhoneStateListener();
Tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Tel.listen(MyListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
timer.schedule(new TimerTask() {
public void run() {
String rssi = MyListener.getStrength();
if(!rssi.equals(""))
signalStrength.add(rssi);
}
}, 0, 5000);//it will add the rssi value after every 5000ms
}
private class MyPhoneStateListener extends PhoneStateListener {
String gsmStrength = "";
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
super.onSignalStrengthsChanged(signalStrength);
gsmStrength = String.valueOf(signalStrength.getGsmSignalStrength()* 2 - 113);
}
public String getStrength() {
return gsmStrength;
}
}
}
This should do the work for you. But at the begining you might not get any rssi value for a little while as the listener is only called when there is a significant change in the rssi.