通话结束后 TelephonyManager 通话状态仍设置为 CALL_STATE_RINGING

TelephonyManager call state still set at CALL_STATE_RINGING after call has been ended

我目前正在构建一个垃圾邮件拦截应用程序作为一个有趣的项目,以便更好地进行 Android 开发,并且 运行 遇到了这个奇怪的错误。

我有一个广播接收器设置来监听呼叫状态的变化,以及检查呼叫是否传入的逻辑,如果号码不在用户的联系人列表中或者“数据库中保存的已批准号码的白名单”。然而,即使在呼叫结束后,接收者仍会继续被呼叫多次(有时 8 次或更多次)并且通常会在呼叫状态设置为振铃时被呼叫(同样,尽管呼叫已经结束)。

基本上,我试图跟踪每个未知号码呼叫 phone 的次数,但对于每次呼叫,它都会将其记录为 2 - 6 次呼叫。

这是我设置的 onReceive 函数:

public void onReceive(final Context con, Intent intent) {
    System.out.println(intent);

    final TelephonyManager telephony = (TelephonyManager) con.getSystemService(Context.TELEPHONY_SERVICE);
    telephony.listen(new PhoneStateListener() {
        @RequiresApi(api = Build.VERSION_CODES.P)
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            System.out.print(state);
            //Toast.makeText(con, incomingNumber, Toast.LENGTH_LONG).show();
            if (TelephonyManager.CALL_STATE_RINGING == state) {
                checkIfNumberInContacts(con, incomingNumber, telephony, state);
            }
        }
    }, PhoneStateListener.LISTEN_CALL_STATE);
}

这里是检查传入号码是否在 contacts/whitelisted 中并结束呼叫的自定义函数:

@RequiresApi(api = Build.VERSION_CODES.P)
   public void checkIfNumberInContacts(Context con, String incomingNumber, TelephonyManager telephony, 
   int state) {
    db = Room.databaseBuilder(con, SpamBlockerDB.class, 
    "spamblocker.db").createFromAsset("databases/spamblocker.db").allowMainThreadQueries().build();

    FilteredCalls call = new FilteredCalls();
    call.calltime = Calendar.getInstance().getTime().toString();
    call.deleted = 0;
    call.number = incomingNumber;
    call.whitelisted = 0;
    call.callcount = 1;

    List<FilteredCalls> allCalls = db.callsDao().getAll();
    boolean callerExistsInDB = false;
    for (FilteredCalls item : allCalls) {

        if (incomingNumber.equals(item.number)) {
            callerExistsInDB = true;
            String updatedTime = Calendar.getInstance().getTime().toString();
            db.callsDao().updateCallTime(updatedTime, item.recID);
        }
        if (TelephonyManager.CALL_STATE_RINGING == state) {
            int currentCount = db.callsDao().getCallCount(item.recID);
            db.callsDao().updateCallCount(currentCount + 1, item.recID);
        }
    }

    ContentResolver contentResolver = con.getContentResolver();
    Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(incomingNumber));

    String contact = "";

    Cursor c = contentResolver.query(uri, new String[]{ContactsContract.PhoneLookup.HAS_PHONE_NUMBER}, null, null);
    if (c != null) {
        if (c.moveToFirst()) {
            do {
                contact = c.getString(c.getColumnIndex("NUMBER"));
            } while (c.moveToNext());
        }
    }

    if (contact == "" && !checkIfNumberIsWhitelisted(con, incomingNumber)) {
        TelecomManager telecomManager = (TelecomManager) con.getSystemService(Context.TELECOM_SERVICE);
        telecomManager.endCall();

        if (!callerExistsInDB) {
            db.callsDao().insert(call);
        }
    }
}

知道为什么 BroadCast 接收器被调用两次以上(一次用于呼入,一次用于挂断),以及为什么在后续调用时它仍然认为 phone 正在响铃?

提前感谢您的帮助。

当phone状态改变时有两种方法可以得到回调:PhoneStateListener和监听android.intent.action.PHONE_STATE.

BroadcastReceiver

看起来您正在将这两种方法混合在一起,这意味着无论何时调用 BroadcastReceiver,您都在注册 另一个PhoneStateListener,所以您继续添加越来越多的听众做同样的事情。

我建议根本不要使用 PhoneStateListener,而只使用 BroadcastReceiver 方法,可以通过 AndroidManifest 设置它,即使在应用程序时也可以调用它睡着了。

查看本教程:https://medium.com/@saishaddai/how-to-know-when-a-device-is-ringing-in-android-57e516d0ab42