TelephonyManagerの通話状態は、通話が終了した後もCALL_STATE_RINGINGに設定されています

Aug 23 2020

私は現在、Android開発を改善するための楽しいプロジェクトとしてスパム通話ブロックアプリを構築しており、この奇妙なバグに直面しています。

通話状態の変化をリッスンするブロードキャストレシーバーのセットアップと、通話が着信しているかどうかを確認するロジックがあり、基本的に、番号がユーザーの連絡先リストまたは承認された番号の「ホワイトリスト」にない場合は通話を終了しますデータベースに保持されます。ただし、通話が終了した後も、受信者は複数回(場合によっては8回以上)呼び出され続け、多くの場合、通話状態が呼び出し音として設定された状態で呼び出されます(通話が終了したにもかかわらず)。

基本的に、私は未知の番号が電話をかけた回数を追跡しようとしていますが、1回の呼び出しごとに、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);
}

着信番号が連絡先/ホワイトリストに登録されているかどうかを確認し、通話を終了するカスタム関数は次のとおりです。

@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レシーバーが2回以上呼び出される理由(着信時に1回、電話を切るために1回)、およびその後に呼び出されたときに電話が鳴っていると見なされる理由はありますか?

事前に助けに感謝します。

回答

1 marmor Aug 24 2020 at 15:16

電話の状態が変化したときにコールバックを取得するには、2つの方法があります。PhoneStateListenerBroadcastReceiverをリッスンしandroid.intent.action.PHONE_STATEます。

2つのメソッドを組み合わせているように見えます。つまり、BroadcastReceiverが呼び出されるたびに、別の新しいを登録しPhoneStateListenerているため、同じことを行うリスナーをどんどん追加していきます。

私は使っていないお勧めしますPhoneStateListenerすべてでは、と一緒に行くBroadcastReceiverを経由して設定することができる唯一の方法、AndroidManifestアプリが眠っている場合でも呼び出すことができるようになります。

このチュートリアルを参照してください: https://medium.com/@saishaddai/how-to-know-when-a-device-is-ringing-in-android-57e516d0ab42