The way I am gathering cell signal info is as follows: I use TelephonyManager and a PhoneStateListener (with an overridden onSignalStrengthsChanged function) to listen for updates in the cell signal RSSI. The onSignalStrengthsChanged function gives you a SignalStrength object.
Here is where it gets messy. The SignalStrength object contains many functions to find properties of the signal specific to a particular cell technology (CDMA/EDVO/GSM). You have to use TelephonyManager.getNetworkType to figure out which of these functions to use. getNetworkType returns a code corresponding to one of the enumerated network types in TelephonyManager. My app uses API level 9 since we want it to be compatible with a wide range of phones. Unfortunately, this API version came out before LTE was used in Android phones, so they were not included in the network type enumerations. In fact, LTE was not added as a network type until API level 11 (Android 3.0). In API 11, LTE is defined as 13 and eHRPD (a technology used for handoffs from EVDO to LTE) is defined as 14.
My first instinct was that we needed to have two versions of the app; one for phones with LTE and one for phones without LTE. However, when I did some more looking at the Android API, I found that even though the LTE network type was defined in API 11, there were still no signal strength methods. Nothing even reminescent of an LTE signal strength method was added until API 17, which is currently the latest API. This was obviously unacceptable, as very few phones currently use this version of Android. There had to be another way.
More snooping around on the internet told me that phone manufacturers actually added their own methods to the SignalStrength object in order to retrieve LTE RSSI data. This left me with the question of how to call a method that's not in the official Android API. The answer to this is the programming technique of reflection. Java allows us the ability to examine a class dynamically at run time. We can ask if a certain method exists, and if it does we can call it.
The problem of knowing which methods to call is a little harder. Tom at sevenplusandroid.org wrote a blog on this very topic that I found incredibly useful. He wrote an app that examined the methods available on the SignalStrength object using reflection. Then, his app was run on many devices. Sorting through his results, I noted that the three main LTE signal strength methods were called getLteRssi, getLteSignalStrength, and getLteRsrp. RSRP is different than RSSI, and you should keep that in mind when working with the data returned from that function.
Here is a snippet of how I used reflection to call these methods (you should probably handle those exceptions..).
//13 = NETWORK_TYPE_LTE case 13: //the android API doesn't support LTE signal strength until 4.2... so we must use reflection to find these methods try { Method[] methods = android.telephony.SignalStrength.class.getMethods(); for(Method mthd:methods){ if(mthd.getName().equals("getLteRssi") || mthd.getName().equals("getLteSignalStrength") || mthd.getName().equals("getLteRsrp")){ signalStrength = (Integer) mthd.invoke(signal, new Object[]{}); break; } } } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } break;
Hope this helps someone! Reflection was completely new to me, so it wasn't an intuitive solution to this problem. I have used this to successfully get LTE RSSI readings using an app compiled with Android API 9 (2.3).
I have samsung galaxy s3 I9300 phone, OS version 4.1.2. Using your source codes I tried to use reflection to get the method getLteRsrp() or getLteRsrq() from SignalStrength class. However when I get all the methods like this: Method[] m = android.telephony.SignalStrength.class.getMethods();
ReplyDeletein the list of methods I don’t see getLteRsrp() or getLteRsrq(). Does this mean that the SDK of my android phone doesn't have those functions and I have not way to use them?
Hi lu,
DeleteI got the names of my functions from the results posted here:
http://sevenplusandroid.org/blog/2011/12/signal-strength-detector-the-results/
This blog was posted before the S3 was released so I'm not sure which one should be used by it. What methods do you see in the getMethods()? You can also use the APK posted in that blog to find out which methods you have.
You do not need Rsrp or Rsrq. Actually, these aren't the same as RSSI. Do you have getLteRssi or getLteSignalStrength?
Adam
Just wanted to say thanks, I had been trying to figure out why I couldn't just use these functions from the get-go and didn't take the time to see how SevenPlusAndroid had done it.
ReplyDeleteKeep it up!
Hi, I copy the result of your method an get me this:
ReplyDeletepublic int android.telephony.SignalStrength.describeContents(),
public boolean android.telephony.SignalStrength.equals(java.lang.Object),
public void android.telephony.SignalStrength.fillInNotifierBundle(android.os.Bundle),
public int android.telephony.SignalStrength.getCdmaDbm(),
public int android.telephony.SignalStrength.getCdmaEcio(),
public int android.telephony.SignalStrength.getEvdoDbm(),
public int android.telephony.SignalStrength.getEvdoEcio(),
public int android.telephony.SignalStrength.getEvdoSnr(),
public int android.telephony.SignalStrength.getGsmBitErrorRate(),
public int android.telephony.SignalStrength.getGsmSignalStrength(),
public int android.telephony.SignalStrength.hashCode(),
public boolean android.telephony.SignalStrength.isGsm(),
public java.lang.String android.telephony.SignalStrength.toString(),
public void android.telephony.SignalStrength.writeToParcel(android.os.Parcel,int),
public static android.telephony.SignalStrength android.telephony.SignalStrength.newFromBundle(android.os.Bundle),
public final native java.lang.Class java.lang.Object.getClass(),
public final native void java.lang.Object.notify(),
public final native void java.lang.Object.notifyAll(),
public final void java.lang.Object.wait() throws java.lang.InterruptedException,
public final void java.lang.Object.wait(long) throws java.lang.InterruptedException,
public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
how is the LTE Signal?
I can't tell much from that exception. What device are you running this on?
DeleteI put a new question Adam.
DeleteThankz!
I run this on the emulator, it doesn't throws any exception, only get the result of the method you post, because don't insert in this instruction:
ReplyDeleteif(mthd.getName().equals("getLteRssi") || mthd.getName().equals("getLteSignalStrength") || mthd.getName().equals("getLteRsrp")){
signalStrength = (Integer) mthd.invoke(signal, new Object[]{});
break;
}
Thankz again and sorry...for my bad inglish!
I don't understand the problem you are facing. If you are using the emulator, then you will not see any of these proprietary extensions to the Android API. These are only present in some devices because the phone manufacturers need them and have created them. The emulator will use vanilla Android, so it won't have any LTE functions.
DeleteSorry if I do not understand your situation!
new one...and last...
ReplyDeletethis is rigth: mthd.invoke(signal, new Object[]{});
because throws me varius exceptions, never resolve for good.
I try pass signal like SignalStrength, int and string.
Thanks again master!
Hi Adam,
ReplyDeleteI used an alternative method. I use the SignalStrength.toString() method. Then I split it.The last value are for example for the LTE.
My question would be about the value getLteRssi or getLteSignalStrength you (we) are looking for. When it's not 99 we get something between 0 and (looks like) 31. It appears to be an ASU value like in GSM or CDMA. But how can we convert it into a dbm Rssi value ?
I am pretty sure that there is no good answer for that. This depends on the device/radio itself. It is even called "Arbitrary Strength Unit"...
DeleteBut Wikipedia says that you should be able to subtract 140 from that number to get the dBm, but I would take that with a grain of salt.
http://en.wikipedia.org/wiki/Mobile_phone_signal#ASU
Hi Adam,
DeleteI'm still on it. The ASU from the getLteSignalStrength or getLteRssi is in a 0.31 -99 range. it doesnt work with the asu-140. I made a lot of tests but I still not find anything that work.
For information, the signal bars on LTE use the RSCP (getLteRsrp) and should be the best value.
Thanks for your reply.
where can we get the LTE programming SDK?
ReplyDeleteThis comment has been removed by the author.
ReplyDeletewhat we pass in place of "signal" .............. please suggest...
ReplyDeleteSorry I did not make that clear. You need an instance of this object: http://developer.android.com/reference/android/telephony/SignalStrength.html
Delete