Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why onCallStateChanged() on Android is invoked more than one time in a single call?

Tags:

android

I wanted to implement an app that prevents calls like a firewall. When I debug my app, I found that when there is a call in, the onCallStateChanged() function in interface PhoneStateListener is invoked three times. As a result, preventing one call can result in three logs. I'm so confused!!

my code:

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        try {
            if (state == TelephonyManager.CALL_STATE_RINGING && 
                PhoneUtil.getITelephony(tpm).isRinging()) {
                String flag = isBlockCall(myContext, myHelper, myTypes, incomingNumber);
                if (flag.length() > 0) {
                    blockCall();
                    myHelper.insertLog(new String[] { flag, incomingNumber, String.valueOf(System.currentTimeMillis()), null });
                    showNotification(myContext, incomingNumber, System.currentTimeMillis());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        super.onCallStateChanged(state, incomingNumber);
    }
}, PhoneStateListener.LISTEN_CALL_STATE);
like image 922
PinkyJie Avatar asked Apr 05 '11 09:04

PinkyJie


3 Answers

Answer lies in your code where you are creating a TelephonyManager and then Registering a listener with it. It would be getting registered for a listener every time you start a new call and therefore multiple listeners attached to same telephony Manager resulting in a onCallStateChanged() for every Listener.
try creating new Telephony Manager and registering it where it executes only for once.(Constructor).

TelephonyManager tmanager=(TelephonyManager)this.getSystemService(TELEPHONY_SERVICE);

tmanager.listen(new CallListener(),PhoneStateListener.LISTEN_CALL_STATE);

like image 157
Aakash Avatar answered Oct 15 '22 18:10

Aakash


Just to better phrase Aakash's answer, onCallStateChanged() gets called multiple times because TelephonyManager.listen() is inside onReceive(). That way, a new PhoneStateListener is instantiated and registered to the TelephonyManager whenever an event is broadcast, so there's many of them.

I personally did something like this in my code:

if (noCallListenerYet) { // noCallListenerYet is static boolean
    TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    tm.listen(new OutgoingCallListener(), PhoneStateListener.LISTEN_CALL_STATE);
    noCallListenerYet = false;
}
like image 22
MLQ Avatar answered Oct 15 '22 16:10

MLQ


Okay now, I had been suffering from the same thing, but somehow I've found a way to do it.

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;

public class CallActionsReceiver extends BroadcastReceiver {
    static ThePhoneStateListener phoneStateListener;

    @Override
    public void onReceive(Context arg0, Intent arg1) {
        TelephonyManager manager = (TelephonyManager) arg0
                .getSystemService(arg0.TELEPHONY_SERVICE);
        if (phoneStateListener == null) {
            phoneStateListener = new ThePhoneStateListener(arg0);
            manager.listen(phoneStateListener,
                    android.telephony.PhoneStateListener.LISTEN_CALL_STATE);
        }

    }

}

In this way the TelephonyManager will listen just once. Cheers . . .

like image 28
Usman Riaz Avatar answered Oct 15 '22 16:10

Usman Riaz