13

I've very newly gotten into Android development, and decided that my first conquest on this fresh field would be to grasp how the phone reacted to incoming calls.

A little googling later led me to http://www.compiletimeerror.com/2013/08/android-call-state-listener-example.html#.Vi3Ren4vfwM (so my code shares a striking resemblance to his/hers).

My main (and only) activity looks like this:

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TelephonyManager TelephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    TelephonyMgr.listen(new TeleListener(),
            PhoneStateListener.LISTEN_CALL_STATE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}
class TeleListener extends PhoneStateListener {
    public void onCallStateChanged(int state, String incomingNumber) {
        super.onCallStateChanged(state, incomingNumber);
        switch (state) {
            case TelephonyManager.CALL_STATE_IDLE:
                // CALL_STATE_IDLE;
                Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
                Toast.makeText(getApplicationContext(), "CALL_STATE_IDLE",
                        Toast.LENGTH_LONG).show();
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                // CALL_STATE_OFFHOOK;
                Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
                Toast.makeText(getApplicationContext(), "CALL_STATE_OFFHOOK",
                        Toast.LENGTH_LONG).show();
                break;
            case TelephonyManager.CALL_STATE_RINGING:
                // CALL_STATE_RINGING
                Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
                Toast.makeText(getApplicationContext(), incomingNumber,
                        Toast.LENGTH_LONG).show();
                Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING",
                        Toast.LENGTH_LONG).show();
                break;
            default:
                break;
        }
    }

}
}

Now, here's where the fun stops. I got the app running on emulator, and used DDMS to spoof a few phone calls to my emulated device to see where the pieces landed.

And surely enough toast popped up and MyLittleDebugger flared up upon state swaps. The listener was working, however no number was ever being shown in my log or my toast.

It was just blank where the number should have been! Not null or anything, no, but blank!

After a little more googling, I realized that my AndroidManifest.xml might be the problem. It is as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.x.xy" >

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

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >
    <activity android:name=".MainActivity" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

Now, here's the question: what am I missing?

Clearly, a little fraction of a something has gone wrong somewhere, because I am able to have my TelephonyMgr object .listen() to call states, but I can't get the number to show.

New information:

I've also tried this on my phone, without emulating to the exact same result.

ViRALiC
  • 1,419
  • 4
  • 18
  • 46
  • I ran your code and it worked for me. # showed up using ddm faked call. – JJF Nov 02 '15 at 13:42
  • Also my app wouldn't even run if I didn't give it READ_PHONE_STATE permission. That sounds different than what you saw. What versions of Android have you tried this on? – JJF Nov 02 '15 at 14:07
  • I am having the exact same problem but the broadcast receiver isn't working for me . – Mainak Jul 04 '16 at 13:33

3 Answers3

4

You probably need to make use of broadcast receiver which may help you what you trying to achieve. create class extending broadcast receiver and in that try to catch the incoming number.

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        TelephonyManager mtelephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        mtelephony.listen(new PhoneStateListener(){
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                super.onCallStateChanged(state, incomingNumber);
               switch (state) {
                 case TelephonyManager.CALL_STATE_RINGING:
                // CALL_STATE_RINGING
                Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
            Toast.makeText(getApplicationContext(), incomingNumber,
                    Toast.LENGTH_LONG).show();
            Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING",
                    Toast.LENGTH_LONG).show();
            break;
        default:
            break;
               }   
            }
        },PhoneStateListener.LISTEN_CALL_STATE);
    }

and in your manifest this line as well.

        <receiver android:name=".MyReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>
dawncode
  • 578
  • 1
  • 8
  • 22
4

I haven't used the listen function of TelephonyManager, but I did successfully use a BroadcastReceiver for getting the phone state changes and the phone number.

Register your receiver in the Activity or in the Manifest (if you want to receive updates when the app is in background):

Activity:

@Override
protected void onResume() {
     super.onResume();
     BroadcastReceiver receiver = new PhoneStateBroadcastReceiver();
     IntentFilter filter= new IntentFilter();
     filter.addAction("android.intent.action.PHONE_STATE");
     filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
     registerReceiver(reciever, filter);
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(reciever);
 }  

Manifest:

<receiver
    android:name=".PhoneStateBroadcastReceiver"
    android:permission="android.permission.READ_PHONE_STATE" >
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>

and a basic receiver:

public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
   private final String TAG = getClass().getName();
   private static String number = null;

   @Override
   public void onReceive(final Context context, final Intent intent) {
      if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
         String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
         Log.d(TAG, intent.getAction() + ", EXTRA_STATE: " + state);
         // on ringing get incoming number
         if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
            number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
            Log.d(TAG, "EXTRA_INCOMING_NUMBER: " + number);

         }
      }

      if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
         number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
         Log.d(TAG, intent.getAction() + ", EXTRA_PHONE_NUMBER: " + number);
      }

   }

}

and in this SO answer you can find a nice implementation that also handles multiple calls: https://stackoverflow.com/a/15564021/348378

Community
  • 1
  • 1
Raanan
  • 4,777
  • 27
  • 47
  • 1
    Thank you, this was a good explanation, but I got it working with danwcode's answer. +1! – ViRALiC Nov 04 '15 at 06:34
  • 1
    You're welcome, he did answer before me but I felt a bit more is needed. You should notice that PHONE_STATE alone doesn't give you the number on out going calls, for that you need to register the NEW_OUTGOING_CALL as well. Additionally the manifest solution will make your application receive event also when your app isn't in foreground. – Raanan Nov 04 '15 at 13:27
3

I would advise you to run your app on a real working phone!

There are multiple reasons why a phone number is not available on all notifications, but you stand a much better chance of there being one if the call is from a real phone network that can provide the number.

zmarties
  • 4,809
  • 22
  • 39
  • I did try that, after originally posting the question. It is not the error. I'll give you a +1 for the good suggestion, and it could have been the error, but it was not in this case. – ViRALiC Oct 29 '15 at 10:37