英文:
TelephonyManager call state still set at CALL_STATE_RINGING after call has been ended
问题
我目前正在构建一个垃圾电话拦截应用,作为一个有趣的项目来提升我的Android开发能力,但是遇到了一个奇怪的错误。
我设置了一个广播接收器来监听通话状态的变化,并且有逻辑来检查通话是否是呼入的,如果号码不在用户的联系人列表中或者不在数据库中保存的“白名单”中,就会结束通话。然而,即使通话已经结束,接收器仍然会被多次调用(有时会被调用8次或更多次),并且通常会被设置为响铃状态(尽管通话已经结束)。
基本上,我想要跟踪每个未知号码呼叫手机的次数,但是对于每个单独的通话,它记录为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);
}
}
}
有任何想法为什么广播接收器会被调用超过两次(一次用于呼入,一次用于挂断),并且为什么当它被后续调用时,仍然认为手机在响铃?
提前感谢您的帮助。
英文:
I'm currently building a spam-call blocking app as a fun project to get better with Android development, and am running into this odd bug.
I have a Broadcast Receiver setup to listen for changes in the call state, and logic to check if the call is incoming or not, and basically end the call if the number is not in the user's contact list or a "whitelist" of approved numbers held in a database. However, even after the call has been ended, the receiver continues to be called multiple times (sometimes 8 or more times) and will often be called with Call State set as ringing (again, despite the fact that the call has been ended).
Basically, I'm trying to keep track of how many times each unknown number calls the phone, but for each single call it records it as anywhere from 2 - 6 calls.
Here is the onReceive function I have set up:
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);
}
and here is the custom function that checks if the incoming number is in contacts/whitelisted and ends the call:
@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);
}
}
}
Any ideas why the BroadCast receiver is called more than twice (once for incoming, once for hanging up), and why when it's called the subsequent times it still thinks the phone is ringing?
Appreciate the help in advance.
答案1
得分: 2
有两种方法可以在手机状态改变时获取回调: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
英文:
There are two ways to get callbacks when the phone state changes: PhoneStateListener
and a BroadcastReceiver
that listens to android.intent.action.PHONE_STATE
.
It looks like you're mixing the two methods together, which means that whenever your BroadcastReceiver is called, you're registering another new PhoneStateListener
, so you keep adding more and more listeners that do the same thing.
I would recommend not using PhoneStateListener
at all, and go with the BroadcastReceiver
approach only, which can be setup via AndroidManifest
which allows it to be called even when the app is asleep.
See this tutorial: https://medium.com/@saishaddai/how-to-know-when-a-device-is-ringing-in-android-57e516d0ab42
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论