Search code examples
androidphone-call

Android: Incoming call listener without permission


I know that we can listen phone state by broadcast receiver with filter

action android:name="android.intent.action.PHONE_STATE"

but this way requires permission

uses-permission android:name="android.permission.READ_PHONE_STATE"

How to determine the incoming GSM call whithout this permission?

P.S.

I'm sure that this is possibly because Whatsapp doing it.
When I'm talking on the Whatsapp audio calls and then got incoming gsm call - whatsapp checking it and set self call to pause. How do they understand that need set pause?

Whatsapp has READ_PHONE_STATE permission in Manifest file, but I check calls on Android 6 and not granted this permission. This permission was disabled.

When this permission is disabled my Receiver doesn't receive action android.intent.action.PHONE_STATE and PhoneStateListener is not working.


Solution

  • I found solution without this permission.

    First of all (when our sip call start) we need request audio focus with lisener

     mAudioManager.requestAudioFocus(afChangeListener, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN);
    

    The afChangeListener can tell us then someboby changed audio focus and then we can check current audio channel. If current mode is AudioManager.MODE_IN_CALL or AudioManager.MODE_RINGTONE then we know that gsm call started.

    AudioManager.OnAudioFocusChangeListener afChangeListener =
            new AudioManager.OnAudioFocusChangeListener() {
                public void onAudioFocusChange(int focusChange) {
    
                    if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                        // Permanent loss of audio focus
                        // Pause playback immediately
                    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                        ScheduledExecutorService scheduler = App.getInstance().obtainScheduler();
                        scheduler.schedule(() -> {
                             Logging.i(TAG, "onAudioFocusChange defer mode = " + mAudioManager.getMode());
                             switch (mAudioManager.getMode()) {
                                 case AudioManager.MODE_RINGTONE:
                                 case AudioManager.MODE_IN_CALL:
                                     //**there we can start standby mode**
                                     break;
                             }
                        }, 100, TimeUnit.MILLISECONDS);
    
                    } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
                        Logging.i(TAG, "onAudioFocusChange AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
                        // Lower the volume, keep playing
                    } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                        // Your app has been granted audio focus again
                        //**there we can stop standby mode**
                    }
    
                }
            };