如何在Android设备中检测来电?

162

我想制作一个应用程序,当手机接到电话时,我想检测号码。下面是我尝试过的,但它无法检测到来电。

我想让我的MainActivity在后台运行,我该怎么做?

我已在manifest文件中授予权限。

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

在清单中还需要提供其他信息吗?

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_layout);
   }

   public class myPhoneStateChangeListener extends PhoneStateListener {
       @Override
       public void onCallStateChanged(int state, String incomingNumber) {
           super.onCallStateChanged(state, incomingNumber);
           if (state == TelephonyManager.CALL_STATE_RINGING) {
               String phoneNumber =   incomingNumber;
           }
       }
   }
}

我们应该为Android P做什么? - Ahmad Arslan
13个回答

1
你需要一个BroadcastReceiver来监听 ACTION_PHONE_STATE_CHANGED。这会在电话状态从空闲、响铃、接听等发生变化时调用你的接收器,因此你可以通过前一个值和新值检测是否是呼入/呼出电话。
所需权限为:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

但是如果你想在广播中接收EXTRA_INCOMING_NUMBER,你需要另一个权限:"android.permission.READ_CALL_LOG"

代码大致如下:

val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "onReceive")
    }
}

override fun onResume() {
    val filter = IntentFilter()
    filter.addAction("android.intent.action.PHONE_STATE")
    registerReceiver(receiver, filter)
    super.onResume()
}

override fun onPause() {
    unregisterReceiver(receiver)
    super.onPause()
}

在接收器类中,我们可以通过读取意图来获取当前状态,如下所示:

intent.extras["state"]

extras的结果可能是:

RINGING -> 如果您的手机正在响铃

OFFHOOK -> 如果您正在与某人通话(呼入或呼出电话)

IDLE -> 如果通话结束(呼入或呼出电话)

使用PHONE_STATE广播,我们不需要使用PROCESS_OUTGOING_CALLS权限或已弃用的NEW_OUTGOING_CALL操作。


0

黑客警报 :)

如果您只对来电事件感兴趣,请考虑使用AudioManager并监听焦点更改。 优点-不需要权限。 缺点-在静音模式下无法工作...在这种情况下,我们将增加来电的音量到最低限度,以仍然获得音频焦点事件。

 /**
 * Register a callback to [AudioManager] to identify an incoming call.
 */
private fun registerAudioFocusChangeListener(){
   val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    val incomingCallVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING)
    if(incomingCallVolume == 0) {
        // Hack Alert :)
        // The user has muted the phone calls, if we still want to intercept the event,
        // we set the volume of the incoming call to Minumum otherwise we will not get
        // Audio focus event...
        try {
            audioManager.adjustVolume(
                AudioManager.ADJUST_UNMUTE,
                AudioManager.FLAG_ALLOW_RINGER_MODES
            )
            audioManager.setStreamVolume(
                AudioManager.STREAM_RING,
                audioManager.getStreamMinVolume(AudioManager.STREAM_RING),
                0
            );
        } catch (e : SecurityException){
            // DND (Don't Disturb Mode) is probably ON, we are not allowed to set the volume
            //  in this scenario, But in this case no incoming call is possible anyway.
        }
    }
    val requestBuilder = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
    requestBuilder.setOnAudioFocusChangeListener { _ ->

        Handler(Looper.getMainLooper()).postDelayed({
            val mode = audioManager.mode
            if(mode == AudioManager.MODE_RINGTONE || mode == AudioManager.MODE_IN_CALL){
                //Ring Ring, do your thing
            }
        }, 100)
    }
    audioManager.requestAudioFocus(requestBuilder.build())
}

0

请参考Gabe Sechan的答案。如上所述,在呼出电话的情况下,我们有以下状态变化:IDLE -> OFFHOOK -> IDLE。在Gabe的原始答案中,只有当电话状态变为RINGING时才设置savedNumber,这对于呼出电话来说是不正确的。修复方法是在电话状态变为OFFHOOK时也设置savedNumber

case TelephonyManager.CALL_STATE_OFFHOOK:
    if(lastState != TelephonyManager.CALL_STATE_RINGING){
        //IDLE to OFFHOOK for example.
        isIncoming = false;
        callStartTime = new Date();
        savedNumber = number;
        onOutgoingCallStarted(context, savedNumber, callStartTime);
    }
...

此修复允许拨打的号码以与传入号码相同的方式传递到呼出通话方法中,就像传入号码传递到来电或未接来电方法中一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接