Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Nougat PhoneStateListener is not triggered

In Android (target 25) I have a background service and in onCreate function I have initialized a phone state listener. It works fine on Android versions that are before Nougat but in Nougat it doesn't work, even though the permissions are granted.

public class Service extends IntentService
{
    class PhoneListener extends PhoneStateListener
    {
       String TAG = getClass().getName();
       @Override
       public void onCallStateChanged(int state, String incomingNumber) 
       {
           super.onCallStateChanged(state, incomingNumber);
           switch (state)
           {
               case TelephonyManager.CALL_STATE_IDLE:
                Log.d(TAG,"IDLE" );
               break;
               case TelephonyManager.CALL_STATE_OFFHOOK:
                Log.d(TAG,"OFFHOOK");
               break;
               case TelephonyManager.CALL_STATE_RINGING:
                Log.d(TAG,"RINGING");
               break;
           }
       }
   }

   public Service ()
   {
       super("ChatService");
   }
   public Service(String name)
   {
       super(name);
   }

   @Override
   public void onCreate()
   {
       super.onCreate();
       TelephonyManager tm = (TelephonyManager)getApplicationContext().getSystemService(TELEPHONY_SERVICE);
       PhoneListener listener = new PhoneListener();
       tm.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
   }
}

I don't know what is the problem, it looks like the telephony manager is not registered and therefore the onCallStateChanged is not triggered. One of my guesses is the Doze feature that was introduced on Android M, but still.. this code works fine on Android 6 even when the phone is not found "in work"

like image 711
Elior Avatar asked Feb 13 '17 20:02

Elior


2 Answers

This was due to a change in PhoneStateListener introduced by https://github.com/aosp-mirror/platform_frameworks_base/commit/f5d7c587e86c64e657a15a12ad70e75d47c48d99#diff-5af2ac899de823cf60597e554bf67fe0.

Local reference to PhoneStateListener is kept track internally only by a weak reference. This makes it eligible for garbage collection upon function exit and once the listener is finalized, apps will not receive any further updates. Solution is to keep a reference to PhoneStateListener via class member variable.

like image 180
Vairavan Avatar answered Sep 27 '22 18:09

Vairavan


So for those who encountered the same problem I found a solution. You don't need to register a BroadcastReceiver for PhoneState.

So instead of registere the telephony manager to listen inside the onCreate method (of the service), I set it in onStartCommand and it started to work.

but notice that in any case that onStartCommand will be triggered it will register the telephony manager, so be sure to register it only once.

In my case, since inside the service class I have the Inner class PhoneListener I created a class member and initialized it to null, and In the onStartCommand I have checked if it's null and then created and registered the telephony manager, but you can use the singelton way.

So this is my code that worked also in Android Nougat:

public class Service extends IntentService
{
    class PhoneListener extends PhoneStateListener
    {
       String TAG = getClass().getName();
       @Override
       public void onCallStateChanged(int state, String incomingNumber) 
       {
           super.onCallStateChanged(state, incomingNumber);
           switch (state)
           {
               case TelephonyManager.CALL_STATE_IDLE:
                  Log.d(TAG,"IDLE" );
               break;
               case TelephonyManager.CALL_STATE_OFFHOOK:
                   Log.d(TAG,"OFFHOOK");
               break;
               case TelephonyManager.CALL_STATE_RINGING:
                   Log.d(TAG,"RINGING");
               break;
           }
     }
     PhoneListener phoneListener = null;

     public Service ()
     {
       super("ChatService");
     }

     @Override
     public void onCreate()
     {
        super.onCreate();
        // do what you need here
     }

     @Override
     public int onStartCommand (Intent intent, int flags, int startId)
     {
        if (phoneListener == null)
        {
          TelephonyManager tm = (TelephonyManager)getApplicationContext().getSystemService(TELEPHONY_SERVICE);
          phoneListener = new PhoneListener();
          tm.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
        }
        // do what you need to do here

        return START_STICKY; // you can set it as you want
     } 
 }
like image 37
Elior Avatar answered Sep 27 '22 19:09

Elior