【问题标题】:Android - How to create a PhoneStateListenerAndroid - 如何创建 PhoneStateListener
【发布时间】:2020-07-26 22:49:40
【问题描述】:

我有一个功能可以发起外拨电话。我需要设置监听器以了解通话状态(响铃、挂断等)。我无法弄清楚如何做到这一点,并且没有找到说明如何做到这一点的教程。这是拨打电话的设置:

PhoneCall.kt

class PhoneCall : AppCompatActivity() {
    private fun placeCall() {
        if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permision.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
            val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            telephonyManager.listen(CallListener, PhoneStateListener.LISTEN_CALL_STATE) //Not sure how to set up CallListener here?
            val callIntent = Intent(Intent.ACTION_CALL, Uri.parse(phoneNumber))
            startActivity(callIntent)
        }
    }
}

我相信从CallListener 我可以创建一个when() 来查找当前状态。但是我不确定如何创建 CallListener 并且这似乎不是一个真正的听众? CallListener 是否需要是一个新的类、对象或其他东西?我想我可能需要一个广播接收器?我不知道正确的处理方法。

【问题讨论】:

    标签: android kotlin telephonymanager android-audiomanager


    【解决方案1】:

    我有一个项目,我做了类似的事情,我创建了两个类,一个是 PhoneCallListener 和 PhoneCallReceiver。我已经删除了一些用于我需要的代码,但是如果你实现了这两个类,你应该没问题。我不是专家,但希望对您有所帮助。

    jsonObject 只是作为一个例子来展示“做某事”。我还应该提一下,我不了解 Kotlin,但有人告诉我 Android Studio 可以将 Java 转换为 Kotlin,所以它可能会有所帮助,希望有经验的人知道 Kotlin 的使用方法。

    PhoneCallListener.java

        public class PhoneCallListener extends PhoneCallReceiver {
    
        @Override
        protected void onIncomingCallStarted(Context c, String number, Date start) {
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("Timestamp", App.getUTCTimestamp());
                    jsonObject.put("Direction", "incoming");
                    jsonObject.put("Number", number);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
        }
    
        @Override
        protected void onOutgoingCallStarted(Context c, String number, Date start) {
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("Timestamp", App.getUTCTimestamp());
                    jsonObject.put("Direction", "outgoing");
                    jsonObject.put("Number", number);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
        }
    
        @Override
        protected void onIncomingCallEnded(Context c, String number, Date start, Date end) 
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("Timestamp", App.getUTCTimestamp());
                    jsonObject.put("Direction", "incoming call ended");
                    jsonObject.put("Number", number);
                } catch (JSONException e) {
                    e.printStackTrace();
                });
        }
    
        @Override
        protected void onOutgoingCallEnded(Context c, String number, Date start, Date end) {
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("Timestamp", App.getUTCTimestamp());
                    jsonObject.put("Direction", "outgoing call ended");
                    jsonObject.put("Number", number);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
        }
    
        @Override
        protected void onMissedCall(Context c, String number, Date start) {
    
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("Timestamp", App.getUTCTimestamp());
                    jsonObject.put("Direction", "missed");
                    jsonObject.put("Number", number);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
        }
    }
    

    PhoneCallReceiver.java

    abstract class PhoneCallReceiver extends BroadcastReceiver {
    
        //The receiver will be recreated whenever android feels like it.  We need a static variable to remember data between instantiations
    
        private static int lastState = TelephonyManager.CALL_STATE_IDLE;
        private static Date callStartTime;
        private static boolean isIncoming;
        private static String savedNumber;  //because the passed incoming is only valid in ringing
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            //We listen to two intents.  The new outgoing call only tells us of an outgoing call.  We use it to get the number.
            try {
                if (Objects.equals(intent.getAction(), "android.intent.action.NEW_OUTGOING_CALL")) {
                    savedNumber = Objects.requireNonNull(intent.getExtras()).getString("android.intent.extra.PHONE_NUMBER");
                } else {
                    String stateStr = Objects.requireNonNull(intent.getExtras()).getString(TelephonyManager.EXTRA_STATE);
                    String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
                    if (number == null) {
                        number = "00000000000"; // Caller Withheld.
                    }
    
                    int state = 0;
                    assert stateStr != null;
                    if (!stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                        if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                            state = TelephonyManager.CALL_STATE_OFFHOOK;
                        } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                            state = TelephonyManager.CALL_STATE_RINGING;
                        }
                    }
                    onCallStateChanged(context, state, number);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //Derived classes should override these to respond to specific events of interest
        protected void onIncomingCallStarted(Context ctx, String number, Date start) {
        }
    
        protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
        }
    
        protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) {
        }
    
        protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
        }
    
        protected void onMissedCall(Context ctx, String number, Date start) {
        }
    
        //Deals with actual events
    
        //Incoming call-  goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
        //Outgoing call-  goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
        public void onCallStateChanged(Context context, int state, String number) {
            if (lastState == state) {
                //No change, debounce extras
                return;
            }
            switch (state) {
                case TelephonyManager.CALL_STATE_RINGING:
                    isIncoming = true;
                    callStartTime = new Date();
                    savedNumber = number;
                    onIncomingCallStarted(context, number, callStartTime);
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    //Transition of ringing->offhook are pickups of incoming calls.  Nothing done on them
                    if (lastState != TelephonyManager.CALL_STATE_RINGING) {
                        isIncoming = false;
                        callStartTime = new Date();
                        onOutgoingCallStarted(context, savedNumber, callStartTime);
                    }
                    break;
                case TelephonyManager.CALL_STATE_IDLE:
                    //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                    if (lastState == TelephonyManager.CALL_STATE_RINGING) {
                        //Ring but no pickup-  a miss
                        onMissedCall(context, savedNumber, callStartTime);
                    } else if (isIncoming) {
                        onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
                    } else {
                        onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
                    }
                    break;
            }
            lastState = state;
        }
    }
    

    【讨论】:

    • 感谢代码示例。那么,您是从哪里发起新的呼出电话的呢?看来这只是在监听呼入电话。
    • onOutgoingCallStarted()
    猜你喜欢
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多