Home‎ > ‎RF Signal Tracker‎ > ‎

    How To: Capture Phone Parameters (a very basic tutorial)

    I get questions about the RF Signal Tracker app every now and then, so to answer some of these I've decided to create this page showing some basic points on how to build a phone state listener and other little odds and ends I've discovered. This will grow as I get more organized. ~ Ken

    MY FIRST ASSUMPTION ABOUT YOU: You know the basics of Android App development. The cool thing about Android is that it has grown up on the web, so there are tutorials and example code everywhere (honestly, about 60-70% of RF Signal Tracker was lifted from examples found all over the web). The problem with that, though, is if you know nothing about Android you may get confused on the basics. It's like knowing nothing about cars and deciding you want to build one from scratch. You find car parts (with detailed explanations of the part) laying all over the place, but you have no idea how they go together.

    Well, for the basics I would suggest Professional Android 2 Application Development (Wrox Programmer to Programmer), by Reto Meier. This will give you a good foundation on Android -- remember, the platform you are building on is a telephone...its primary job is to make and receive calls, so the philosophy is a little different. Read that and learn about Intents and Activities and Broadcast Alerts and such.

    The Basic Steps to Read Your Phone:

    1. Set the permissions in the Manifest.

      In your manifest you are going to need this line or nothing will work.

      <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

      On installation this will cause the app to ask the user for permission to:

      READ PHONE STATE AND IDENTITY
      Allows the application to access the phone features of the device. An application with this permission can determine the phone number and serial number of this phone, whether a call is active, the number that call is connected to and the like.


    2. Create your objects.

      You are going to need a PhoneStateListener and a TelephoneManager object. As the name implies, the PhoneStateListener will "listen" for changes in the current cell, data activity, data connection state, signal strength, call state, and a few more things. The TelephonyManager actually gets the current cell, data activity, connection state, etc. I make these objects global because I call them all over the activity:

      PhoneStateListener myPhoneStateListener;
      TelephonyManager tm;


    3. Initialize your objects.

      I put the following code in the onCreate:

      tm  = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

      The TelephonyManager object has a crap load of useful things like data activity, data state, network operator, phone type, Sim serial
      number, device ID, subscriber ID, network type, and much more. Play around with these. For example, to figure out and display the network technology
      do this:

      String NetTypeStr;
      switch(tm.getNetworkType()){
      case 0: NetTypeStr = getString(R.string.unknown); break;
      case 1: NetTypeStr = "GPRS"; break;
      case 2: NetTypeStr = "EDGE"; break;
        case 3: NetTypeStr = "UMTS"; break;
        case 4: NetTypeStr = "CDMA"; break;
        case 5: NetTypeStr = "EVDO_0"; break;
        case 6: NetTypeStr = "EVDO_A"; break;
        case 7: NetTypeStr = "1xRTT"; break;
        case 8: NetTypeStr = "HSDPA"; break;
        case 9: NetTypeStr = "HSUPA"; break;
        case 10: NetTypeStr = "HSPA"; break;
        case 11: NetTypeStr = "iDen"; break;
        case 12: NetTypeStr = "EVDO_B"; break;
        case 13: NetTypeStr = "LTE"; break;
        case 14: NetTypeStr = "eHRPD"; break;
      case 15: NetTypeStr = "HSPA+"; break;
      }


      And your technology type is in the string variable NetTypeStr.

      I like to initialize the phone listener in a separate method that I call in my onCreate when the app starts. The basic method looks something like this:

      private void phoneStateSetup(){
      myPhoneStateListener = new PhoneStateListener() {
      public void onCallForwardingIndicatorChanged(boolean cfi){}
      public void onCallStateChanged(int state, String incomingNumber){}
      public void onCellLocationChanged(CellLocation location){}
      public void onDataActivity(int direction){}
      public void onDataConnectionStateChanged(int state){}
      public void onMessageWaitIndicatorChanged(boolean mwi){}
      public void onServiceStateChanged(ServiceState serviceState){}
      public void onSignalStrengthsChanged(SignalStrength signalStrength){}
      };

      try{
         tm.listen(myPhoneStateListener, PhoneStateListener.LISTEN_CELL_LOCATION
              | PhoneStateListener.LISTEN_DATA_ACTIVITY
              | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
              | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
              | PhoneStateListener.LISTEN_CALL_STATE);
      }catch(Exception e){

      }
      }


      If you just add the line,

      phoneStateListener();

      In your onCreate the listener will start running and any changes in the activities you are listening for will fire the corresponding callback. In the example above, a handoff to a new cell would fire the onCellLocationChanged() sub-method. If you want to do something when that happens, you would place your code in that sub-method.

      Also, make sure you add the proper listeners in the try/catch. I only added a few in the example above.

    4. Read your data.

      Those methods in PhoneStateListener(){} are where you would put your code.

      The "listen" thing on the try/catch at the end turns on the various listeners you actually want to check. In this example I wanted to listen for changes in the serving cell, data activity, data connection, signal strength, and call state. In the app, I call the method that updates the screen in those  PhoneStateListener  methods.

      For example,  when the phone hands off to a new cell, the onCellLocationChanged(CellLocation location){} method gets called. You would call the methods in your TelephonyManager object here to get a new LAC/CellID (GSM), or SystemID/NetworkID (CDMA).  In the  onCellLocationChanged() method, I do something like this:

      GsmCellLocation cl = (GsmCellLocation) tm.getCellLocation();
      String temp = tm.getNetworkOperator();
      int MCC = Integer.parseInt(ut.Left(temp,3));
      int MNC = Integer.parseInt(temp.substring(3,temp.length()));
      int LAC = cl.getLac(); 
      int ci = cl.getCid();


      To get the Cell ID you will need to convert it from hexidecimal:

      int CELLID = ci & 0xffff;

      Oddly, the MCC, MNC, and LAC are all decimals. There are a couple ways of getting the MCC and MNC, this is just what I use.

      The signal strength object returns something called an 
      asu (this is found in the signalStrength variable in the onSignalStrengthsChanged() method). I have no idea what an asu is, but to convert it to dBm apply this formula:

      int rssi = -113 + 2 * signalStrength.getGsmSignalStrength();

      Please note that this is for GSM. To get the value in CDMA just take signalStrength.getCdmaDbm().

      For LTE you are going to want to determine the Network type first. If tm.getNetworkType()=13 then it is LTE. In that case take the toString() of 
      the SignalStrength method. Example:

      String ltestr = signalStrength.toString();
      String[] parts = temp.split(" ");


      The parts[] array will then contain these elements:

      part[0] = "Signalstrength:"  _ignore this, it's just the title_
      parts[1] = GsmSignalStrength
      parts[2] = GsmBitErrorRate
      parts[3] = CdmaDbm
      parts[4] = CdmaEcio
      parts[5] = EvdoDbm
      parts[6] = EvdoEcio
      parts[7] = EvdoSnr
      parts[8] = LteSignalStrength
      parts[9] = LteRsrp
      parts[10] = LteRsrq
      parts[11] = LteRssnr
      parts[12] = LteCqi
      parts[13] = gsm|lte
      parts[14] = _not reall sure what this number is_

      The numbers are mostly integers, but play around with it to see what you get. It's important to note that LTE is sometimes measured in Reference Signal Received Power (RSRP) rather than RSSI. You will have to decide which to use based on your needs.

    5. Turn off your listeners when you are done.

      You are going to want to set up a method that turns off your listeners when you close or pause the activity (it's a good programming practice). To turn off the TelephonyManager you would do something like this:

      try{
      if(myPhoneStateListener != null){tm.listen(myPhoneStateListener, PhoneStateListener.LISTEN_NONE);}
      }catch(Exception e){
      e.printStackTrace();
      }


    6. Remind yourself how cool you are.

      This is important, as the app will not function until you do.

    But that's it.  See the reference page on the TelephonyManager for all the methods you can access.
    Comments