Improve hidden number detection
This commit is contained in:
parent
24f4dd5881
commit
fa5b616573
|
@ -27,7 +27,8 @@ public class CallMonitoringService extends Service {
|
|||
private static final Logger LOG = LoggerFactory.getLogger(CallMonitoringService.class);
|
||||
|
||||
private final MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();
|
||||
private final CallReceiver callReceiver = new CallReceiver(true);
|
||||
private final CallReceiver callReceiver = new CallReceiver(
|
||||
PhoneStateHandler.Source.PHONE_STATE_BROADCAST_RECEIVER_MONITORING);
|
||||
|
||||
private boolean monitoringStarted;
|
||||
|
||||
|
@ -135,15 +136,17 @@ public class CallMonitoringService extends Service {
|
|||
}
|
||||
|
||||
PhoneStateHandler phoneStateHandler = YacbHolder.getPhoneStateHandler();
|
||||
PhoneStateHandler.Source source = PhoneStateHandler.Source.PHONE_STATE_LISTENER;
|
||||
|
||||
switch (state) {
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
phoneStateHandler.onIdle(phoneNumber);
|
||||
phoneStateHandler.onIdle(source, phoneNumber);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
phoneStateHandler.onRinging(phoneNumber);
|
||||
phoneStateHandler.onRinging(source, phoneNumber);
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
phoneStateHandler.onOffHook(phoneNumber);
|
||||
phoneStateHandler.onOffHook(source, phoneNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,20 +15,20 @@ public class CallReceiver extends BroadcastReceiver {
|
|||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CallReceiver.class);
|
||||
|
||||
private final boolean monitoringService;
|
||||
private final PhoneStateHandler.Source source;
|
||||
|
||||
@SuppressWarnings({"unused", "RedundantSuppression"}) // required for BroadcastReceivers
|
||||
public CallReceiver() {
|
||||
this(false);
|
||||
this(PhoneStateHandler.Source.PHONE_STATE_BROADCAST_RECEIVER);
|
||||
}
|
||||
|
||||
public CallReceiver(boolean monitoringService) {
|
||||
this.monitoringService = monitoringService;
|
||||
public CallReceiver(PhoneStateHandler.Source source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
LOG.debug("onReceive() invoked, monitoringService={}", monitoringService);
|
||||
LOG.debug("onReceive() invoked, source={}", source);
|
||||
|
||||
if (!TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(intent.getAction())
|
||||
&& !TelephonyManager.EXTRA_STATE_RINGING.equals(intent.getAction())) { // TODO: check
|
||||
|
@ -58,11 +58,11 @@ public class CallReceiver extends BroadcastReceiver {
|
|||
|
||||
PhoneStateHandler phoneStateHandler = YacbHolder.getPhoneStateHandler();
|
||||
if (TelephonyManager.EXTRA_STATE_RINGING.equals(telephonyExtraState)) {
|
||||
phoneStateHandler.onRinging(incomingNumber);
|
||||
phoneStateHandler.onRinging(source, incomingNumber);
|
||||
} else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(telephonyExtraState)) {
|
||||
phoneStateHandler.onOffHook(incomingNumber);
|
||||
phoneStateHandler.onOffHook(source, incomingNumber);
|
||||
} else if (TelephonyManager.EXTRA_STATE_IDLE.equals(telephonyExtraState)) {
|
||||
phoneStateHandler.onIdle(incomingNumber);
|
||||
phoneStateHandler.onIdle(source, incomingNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package dummydomain.yetanothercallblocker;
|
|||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.core.util.Predicate;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -21,6 +23,12 @@ import static dummydomain.yetanothercallblocker.EventUtils.postEvent;
|
|||
|
||||
public class PhoneStateHandler {
|
||||
|
||||
public enum Source {
|
||||
PHONE_STATE_LISTENER,
|
||||
PHONE_STATE_BROADCAST_RECEIVER_MONITORING,
|
||||
PHONE_STATE_BROADCAST_RECEIVER
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PhoneStateHandler.class);
|
||||
|
||||
private final Context context;
|
||||
|
@ -42,8 +50,8 @@ public class PhoneStateHandler {
|
|||
this.notificationService = notificationService;
|
||||
}
|
||||
|
||||
public void onRinging(String phoneNumber) {
|
||||
LOG.debug("onRinging({})", phoneNumber);
|
||||
public void onRinging(Source source, String phoneNumber) {
|
||||
LOG.debug("onRinging({}, \"{}\")", source, phoneNumber);
|
||||
|
||||
boolean ignore = false;
|
||||
|
||||
|
@ -53,17 +61,30 @@ public class PhoneStateHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: check
|
||||
LOG.debug("onRinging() ignoring null");
|
||||
ignore = true;
|
||||
if (source == Source.PHONE_STATE_LISTENER) {
|
||||
LOG.info("onRinging() treating null from PhoneStateListener as a hidden number");
|
||||
phoneNumber = "";
|
||||
} else if ((source == Source.PHONE_STATE_BROADCAST_RECEIVER_MONITORING
|
||||
|| source == Source.PHONE_STATE_BROADCAST_RECEIVER)
|
||||
&& isEventPresent(sameSourceAndNumber(source, null))
|
||||
&& !isEventPresent(nonEmptyNumber())) {
|
||||
LOG.info("onRinging() treating repeated null from PhoneStateBroadcastReceiver" +
|
||||
" as a hidden number");
|
||||
phoneNumber = "";
|
||||
}
|
||||
|
||||
if (phoneNumber == null) {
|
||||
LOG.debug("onRinging() ignoring null");
|
||||
ignore = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore && !shouldProcess(phoneNumber)) {
|
||||
if (!ignore && isEventPresent(sameNumber(phoneNumber))) {
|
||||
LOG.debug("onRinging() ignoring repeated event");
|
||||
ignore = true;
|
||||
}
|
||||
|
||||
recordEvent(phoneNumber);
|
||||
recordEvent(source, phoneNumber);
|
||||
|
||||
if (ignore) return;
|
||||
|
||||
|
@ -95,16 +116,16 @@ public class PhoneStateHandler {
|
|||
}
|
||||
}
|
||||
|
||||
public void onOffHook(String phoneNumber) {
|
||||
LOG.debug("onOffHook({})", phoneNumber);
|
||||
public void onOffHook(Source source, String phoneNumber) {
|
||||
LOG.debug("onOffHook({}, \"{}\")", source, phoneNumber);
|
||||
|
||||
isOffHook = true;
|
||||
|
||||
postEvent(new CallOngoingEvent());
|
||||
}
|
||||
|
||||
public void onIdle(String phoneNumber) {
|
||||
LOG.debug("onIdle({})", phoneNumber);
|
||||
public void onIdle(Source source, String phoneNumber) {
|
||||
LOG.debug("onIdle({}, \"{}\")", source, phoneNumber);
|
||||
|
||||
isOffHook = false;
|
||||
|
||||
|
@ -113,38 +134,56 @@ public class PhoneStateHandler {
|
|||
postEvent(new CallEndedEvent());
|
||||
}
|
||||
|
||||
private boolean shouldProcess(String phoneNumber) {
|
||||
private static Predicate<CallEvent> sameNumber(String number) {
|
||||
return event -> TextUtils.equals(event.number, number);
|
||||
}
|
||||
|
||||
private static Predicate<CallEvent> sameSourceAndNumber(Source source, String number) {
|
||||
return event -> event.source == source && TextUtils.equals(event.number, number);
|
||||
}
|
||||
|
||||
private static Predicate<CallEvent> nonEmptyNumber() {
|
||||
return event -> !TextUtils.isEmpty(event.number);
|
||||
}
|
||||
|
||||
private boolean isEventPresent(Predicate<CallEvent> predicate) {
|
||||
return findEvent(predicate) != null;
|
||||
}
|
||||
|
||||
private CallEvent findEvent(Predicate<CallEvent> predicate) {
|
||||
// using 1 second ago as the cutoff point - consider everything older as unrelated events
|
||||
long cutoff = System.nanoTime() - TimeUnit.SECONDS.toNanos(1);
|
||||
|
||||
if (lastEventTimestamp - cutoff < 0) { // no events in the last second
|
||||
lastEvents.clear();
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ListIterator<CallEvent> it = lastEvents.listIterator(); it.hasNext(); ) {
|
||||
CallEvent event = it.next();
|
||||
if (event.timestamp - cutoff < 0) { // event is older than the cutoff point
|
||||
it.remove();
|
||||
} else if (TextUtils.equals(event.number, phoneNumber)) {
|
||||
return false; // don't process same event
|
||||
} else if (predicate.test(event)) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void recordEvent(String phoneNumber) {
|
||||
private void recordEvent(Source source, String phoneNumber) {
|
||||
long currentTimestamp = System.nanoTime();
|
||||
lastEvents.add(new CallEvent(phoneNumber, currentTimestamp));
|
||||
lastEvents.add(new CallEvent(source, phoneNumber, currentTimestamp));
|
||||
lastEventTimestamp = currentTimestamp;
|
||||
}
|
||||
|
||||
private static class CallEvent {
|
||||
final Source source;
|
||||
final String number;
|
||||
final long timestamp;
|
||||
|
||||
public CallEvent(String number, long timestamp) {
|
||||
public CallEvent(Source source, String number, long timestamp) {
|
||||
this.source = source;
|
||||
this.number = number;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<string name="block_negative_sia">Блокировать по отзывам</string>
|
||||
<string name="block_negative_sia_numbers_summary">Блокировать звонки c номеров с отрицательным рейтингом</string>
|
||||
<string name="block_hidden_number">Блокировать скрытые номера</string>
|
||||
<string name="block_hidden_number_summary">(Экспериментальная функция.) Блокировать звонки со скрытых номеров. Вероятно, работает лучше в \"Продвинутом режиме блокирования вызовов\". Пожалуйста, сообщите о своём опыте использования в репозитории на GitLab</string>
|
||||
<string name="block_hidden_number_summary">Блокировать звонки со скрытых номеров. Может работать по-другому (лучше или хуже) в \"Продвинутом режиме блокирования вызовов\"</string>
|
||||
<string name="block_blacklisted_short">Блокировать из ЧС</string>
|
||||
<string name="block_blacklisted">Блокировать из чёрного списка</string>
|
||||
<string name="block_blacklisted_summary">Блокировать звонки с номеров добавленных в чёрный список</string>
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
<string name="block_negative_sia">Block based on rating</string>
|
||||
<string name="block_negative_sia_numbers_summary">Block calls from numbers with negative rating (based on a community database)</string>
|
||||
<string name="block_hidden_number">Block hidden numbers</string>
|
||||
<string name="block_hidden_number_summary">(Experimental.) Block calls from hidden numbers. Probably works better in \"Advanced call blocking mode\". Please report your experience on GitLab</string>
|
||||
<string name="block_hidden_number_summary">Block calls from hidden numbers. May work differently (better or worse) in \"Advanced call blocking mode\"</string>
|
||||
<string name="block_blacklisted_short">Block blacklisted</string>
|
||||
<string name="block_blacklisted">Block blacklisted numbers</string>
|
||||
<string name="block_blacklisted_summary">Block calls from numbers added to the blacklist</string>
|
||||
|
|
Loading…
Reference in New Issue