Search code examples
androidtelephonymanagerandroid-7.0-nougatandroid-7.1-nougatandroid-doze

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"


Solution

  • 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
         } 
     }