mirror of
https://gitlab.com/xynngh/YetAnotherCallBlocker.git
synced 2025-02-26 16:47:45 +01:00
Add experimental support for blocking hidden numbers
This commit is contained in:
parent
c1b7c4e9cd
commit
6909c344b5
@ -153,7 +153,9 @@ public class CallLogItemRecyclerViewAdapter
|
||||
}
|
||||
|
||||
label.setText(ellipsize(
|
||||
item.numberInfo.name != null ? item.numberInfo.name : item.number, 15));
|
||||
item.numberInfo.noNumber ? label.getContext().getString(R.string.no_number) :
|
||||
item.numberInfo.name != null ? item.numberInfo.name : item.number,
|
||||
15));
|
||||
|
||||
IconAndColor iconAndColor = IconAndColor.forNumberRating(
|
||||
item.numberInfo.rating, item.numberInfo.contactItem != null);
|
||||
|
@ -5,6 +5,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
@ -21,7 +22,6 @@ import dummydomain.yetanothercallblocker.data.DatabaseSingleton;
|
||||
import dummydomain.yetanothercallblocker.data.NumberInfo;
|
||||
import dummydomain.yetanothercallblocker.event.CallEndedEvent;
|
||||
import dummydomain.yetanothercallblocker.event.CallOngoingEvent;
|
||||
import dummydomain.yetanothercallblocker.event.CallStartedEvent;
|
||||
|
||||
import static dummydomain.yetanothercallblocker.EventUtils.postEvent;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
@ -38,28 +38,38 @@ public class CallReceiver extends BroadcastReceiver {
|
||||
|
||||
String telephonyExtraState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
||||
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
|
||||
LOG.info("Received intent: action={}, extraState={}, incomingNumber={}",
|
||||
intent.getAction(), telephonyExtraState, incomingNumber);
|
||||
boolean hasNumberExtra = intent.hasExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
|
||||
LOG.info("Received intent: extraState={}, incomingNumber={}, hasNumberExtra={}",
|
||||
telephonyExtraState, incomingNumber, hasNumberExtra);
|
||||
|
||||
extraLogging(intent); // TODO: make optional or remove
|
||||
|
||||
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(telephonyExtraState)) {
|
||||
isOnCall = true;
|
||||
postEvent(new CallOngoingEvent());
|
||||
} else if (TelephonyManager.EXTRA_STATE_RINGING.equals(telephonyExtraState)) {
|
||||
if (incomingNumber == null) return;
|
||||
|
||||
postEvent(new CallStartedEvent());
|
||||
if (incomingNumber == null) {
|
||||
if (hasNumberExtra) {
|
||||
incomingNumber = "";
|
||||
} else {
|
||||
if (!PermissionHelper.hasNumberInfoPermissions(context)) {
|
||||
LOG.warn("No info permissions");
|
||||
return;
|
||||
}
|
||||
return; // TODO: check
|
||||
}
|
||||
}
|
||||
|
||||
Settings settings = App.getSettings();
|
||||
|
||||
boolean blockCalls = settings.getBlockCalls();
|
||||
boolean blockingEnabled = settings.getCallBlockingEnabled();
|
||||
boolean showNotifications = settings.getIncomingCallNotifications();
|
||||
|
||||
if (blockCalls || showNotifications) {
|
||||
if (blockingEnabled || showNotifications) {
|
||||
NumberInfo numberInfo = DatabaseSingleton.getNumberInfo(incomingNumber);
|
||||
|
||||
boolean blocked = false;
|
||||
if (blockCalls && !isOnCall && numberInfo.rating == NumberInfo.Rating.NEGATIVE
|
||||
&& numberInfo.contactItem == null) {
|
||||
if (blockingEnabled && !isOnCall && DatabaseSingleton.shouldBlock(numberInfo)) {
|
||||
blocked = rejectCall(context);
|
||||
|
||||
if (blocked) {
|
||||
@ -79,6 +89,26 @@ public class CallReceiver extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
private void extraLogging(Intent intent) {
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
LOG.trace("extraLogging() extras:");
|
||||
for (String k : extras.keySet()) {
|
||||
LOG.trace("extraLogging() key={}, value={}", k, extras.get(k));
|
||||
}
|
||||
|
||||
Object subscription = extras.get("subscription"); // PhoneConstants.SUBSCRIPTION_KEY
|
||||
if (subscription != null) {
|
||||
LOG.trace("extraLogging() subscription.class={}", subscription.getClass());
|
||||
if (subscription instanceof Number) {
|
||||
long subId = ((Number) subscription).longValue();
|
||||
LOG.trace("extraLogging() subId={}, check={}",
|
||||
subId, subId < Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private boolean rejectCall(@NonNull Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
|
@ -2,9 +2,14 @@ package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.telecom.Call;
|
||||
import android.telecom.CallScreeningService;
|
||||
import android.telecom.Connection;
|
||||
import android.telecom.GatewayInfo;
|
||||
import android.telecom.PhoneAccount;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
@ -38,23 +43,61 @@ public class CallScreeningServiceImpl extends CallScreeningService {
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore && !App.getSettings().getBlockCalls()) {
|
||||
if (!ignore && !App.getSettings().getCallBlockingEnabled()) {
|
||||
ignore = true;
|
||||
}
|
||||
|
||||
extraLogging(callDetails); // TODO: make optional or remove
|
||||
|
||||
String number = null;
|
||||
|
||||
if (!ignore) {
|
||||
Uri handle = callDetails.getHandle();
|
||||
if (PhoneAccount.SCHEME_TEL.equals(handle.getScheme())) {
|
||||
String number = handle.getSchemeSpecificPart();
|
||||
LOG.debug("onScreenCall() number={}", number);
|
||||
LOG.trace("onScreenCall() handle: {}", handle);
|
||||
|
||||
numberInfo = DatabaseSingleton.getNumberInfo(number);
|
||||
if (handle != null && PhoneAccount.SCHEME_TEL.equals(handle.getScheme())) {
|
||||
number = handle.getSchemeSpecificPart();
|
||||
LOG.debug("onScreenCall() number from handle: {}", number);
|
||||
}
|
||||
|
||||
if (numberInfo.rating == NumberInfo.Rating.NEGATIVE
|
||||
&& numberInfo.contactItem == null) {
|
||||
shouldBlock = true;
|
||||
if (number == null) {
|
||||
Bundle intentExtras = callDetails.getIntentExtras();
|
||||
if (intentExtras != null) {
|
||||
Object o = intentExtras.get(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
|
||||
LOG.trace("onScreenCall() EXTRA_INCOMING_CALL_ADDRESS={}", o);
|
||||
|
||||
if (o instanceof Uri) {
|
||||
Uri uri = (Uri) o;
|
||||
if (PhoneAccount.SCHEME_TEL.equals(uri.getScheme())) {
|
||||
number = uri.getSchemeSpecificPart();
|
||||
}
|
||||
}
|
||||
|
||||
if (number == null && intentExtras.containsKey(
|
||||
"com.google.android.apps.hangouts.telephony.hangout_info_bundle")) {
|
||||
// NB: SIA doesn't block (based on number) hangouts if there's no number in intentExtras
|
||||
number = "YACB_hangouts_stub";
|
||||
}
|
||||
}
|
||||
|
||||
if (number == null && callDetails.getExtras() != null) {
|
||||
// NB: this part is broken in SIA
|
||||
number = callDetails.getExtras().getString(Connection.EXTRA_CHILD_ADDRESS);
|
||||
LOG.trace("onScreenCall() EXTRA_CHILD_ADDRESS={}", number);
|
||||
}
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(number)
|
||||
&& !PermissionHelper.hasNumberInfoPermissions(this)) {
|
||||
ignore = true;
|
||||
LOG.warn("onScreenCall() no info permissions");
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore) {
|
||||
numberInfo = DatabaseSingleton.getNumberInfo(number);
|
||||
|
||||
shouldBlock = DatabaseSingleton.shouldBlock(numberInfo);
|
||||
}
|
||||
} finally {
|
||||
LOG.debug("onScreenCall() blocking call: {}", shouldBlock);
|
||||
@ -86,4 +129,38 @@ public class CallScreeningServiceImpl extends CallScreeningService {
|
||||
}
|
||||
}
|
||||
|
||||
private void extraLogging(Call.Details callDetails) {
|
||||
LOG.trace("extraLogging() handle={}", callDetails.getHandle());
|
||||
|
||||
if (callDetails.getStatusHints() != null) {
|
||||
LOG.trace("extraLogging() statusHints.label={}",
|
||||
callDetails.getStatusHints().getLabel());
|
||||
}
|
||||
|
||||
GatewayInfo gatewayInfo = callDetails.getGatewayInfo();
|
||||
if (gatewayInfo != null) {
|
||||
LOG.trace("extraLogging() gatewayInfo provider={}," +
|
||||
"gatewayAddress={}, originalAddress={}",
|
||||
gatewayInfo.getGatewayProviderPackageName(),
|
||||
gatewayInfo.getGatewayAddress(),
|
||||
gatewayInfo.getOriginalAddress());
|
||||
}
|
||||
|
||||
Bundle intentExtras = callDetails.getIntentExtras();
|
||||
if (intentExtras != null) {
|
||||
LOG.trace("extraLogging() intentExtras:");
|
||||
for (String k : intentExtras.keySet()) {
|
||||
LOG.trace("extraLogging() key={}, value={}", k, intentExtras.get(k));
|
||||
}
|
||||
}
|
||||
|
||||
Bundle extras = callDetails.getExtras();
|
||||
if (intentExtras != null) {
|
||||
LOG.trace("extraLogging() intentExtras:");
|
||||
for (String k : extras.keySet()) {
|
||||
LOG.trace("extraLogging() key={}, value={}", k, extras.get(k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -61,4 +61,8 @@ public class GenericSettings {
|
||||
return pref.contains(key);
|
||||
}
|
||||
|
||||
public void unset(String key) {
|
||||
pref.edit().remove(key).apply();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,10 +24,12 @@ public class InfoDialogHelper {
|
||||
public static void showDialog(Context context, NumberInfo numberInfo,
|
||||
DialogInterface.OnDismissListener onDismissListener) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
.setTitle(numberInfo.number);
|
||||
.setTitle(!numberInfo.noNumber
|
||||
? numberInfo.number : context.getString(R.string.no_number));
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.info_dialog, null);
|
||||
builder.setView(view);
|
||||
|
||||
TextView categoryView = view.findViewById(R.id.category);
|
||||
|
||||
@ -66,6 +68,13 @@ public class InfoDialogHelper {
|
||||
ReviewsSummaryHelper.populateSummary(view.findViewById(R.id.reviews_summary),
|
||||
numberInfo.communityDatabaseItem);
|
||||
|
||||
if (onDismissListener != null) builder.setOnDismissListener(onDismissListener);
|
||||
|
||||
if (numberInfo.noNumber) {
|
||||
builder.show();
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable reviewsAction = () -> {
|
||||
context.startActivity(clearTop(
|
||||
ReviewsActivity.getNumberIntent(context, numberInfo.number)));
|
||||
@ -77,12 +86,9 @@ public class InfoDialogHelper {
|
||||
IntentHelper.startActivity(context, new Intent(Intent.ACTION_VIEW, uri));
|
||||
};
|
||||
|
||||
builder.setView(view)
|
||||
.setPositiveButton(R.string.add_web_review, null)
|
||||
builder.setPositiveButton(R.string.add_web_review, null)
|
||||
.setNeutralButton(R.string.online_reviews, null);
|
||||
|
||||
if (onDismissListener != null) builder.setOnDismissListener(onDismissListener);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
// avoid dismissing the original dialog on button press
|
||||
|
@ -65,7 +65,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
settings.getIncomingCallNotifications());
|
||||
|
||||
menu.findItem(R.id.menu_block_calls).setChecked(
|
||||
settings.getBlockCalls());
|
||||
settings.getBlockNegativeSiaNumbers());
|
||||
|
||||
menu.findItem(R.id.menu_auto_updates).setChecked(
|
||||
updateScheduler.isAutoUpdateScheduled());
|
||||
@ -82,7 +82,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
PermissionHelper.handlePermissionsResult(this, requestCode, permissions, grantResults,
|
||||
settings.getIncomingCallNotifications(), settings.getBlockCalls(),
|
||||
settings.getIncomingCallNotifications(), settings.getCallBlockingEnabled(),
|
||||
settings.getUseContacts());
|
||||
|
||||
loadCallLog();
|
||||
@ -134,7 +134,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private void checkPermissions() {
|
||||
PermissionHelper.checkPermissions(this,
|
||||
settings.getIncomingCallNotifications(), settings.getBlockCalls(),
|
||||
settings.getIncomingCallNotifications(), settings.getCallBlockingEnabled(),
|
||||
settings.getUseContacts());
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void onBlockCallsChanged(MenuItem item) {
|
||||
settings.setBlockCalls(!item.isChecked());
|
||||
settings.setBlockNegativeSiaNumbers(!item.isChecked());
|
||||
checkPermissions();
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,8 @@ public class NotificationHelper {
|
||||
public static void showBlockedCallNotification(Context context, NumberInfo numberInfo) {
|
||||
Notification notification = createBlockedCallNotification(context, numberInfo);
|
||||
|
||||
String tag = numberInfo.number != null ? NOTIFICATION_TAG_BLOCKED_CALL + numberInfo.number : null; // TODO: handle repeating
|
||||
String tag = NOTIFICATION_TAG_BLOCKED_CALL
|
||||
+ (!numberInfo.noNumber ? numberInfo.number : System.nanoTime()); // TODO: handle repeating
|
||||
notify(context, tag, NOTIFICATION_ID_BLOCKED_CALL, notification);
|
||||
}
|
||||
|
||||
@ -210,7 +211,7 @@ public class NotificationHelper {
|
||||
NumberInfo numberInfo) {
|
||||
builder.setContentIntent(createInfoIntent(context, numberInfo));
|
||||
|
||||
if (numberInfo.contactItem == null) {
|
||||
if (!numberInfo.noNumber && numberInfo.contactItem == null) {
|
||||
builder.addAction(0, context.getString(R.string.online_reviews),
|
||||
createReviewsIntent(context, numberInfo));
|
||||
}
|
||||
|
@ -128,6 +128,13 @@ public class PermissionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasNumberInfoPermissions(Context context) {
|
||||
for (String permission : INFO_PERMISSIONS) {
|
||||
if (!hasPermission(context, permission)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean hasCallLogPermission(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
return hasPermission(context, Manifest.permission.READ_CALL_LOG);
|
||||
|
@ -6,12 +6,16 @@ import android.text.TextUtils;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dummydomain.yetanothercallblocker.data.CountryHelper;
|
||||
|
||||
public class Settings extends GenericSettings {
|
||||
|
||||
public static final String PREF_INCOMING_CALL_NOTIFICATIONS = "incomingCallNotifications";
|
||||
public static final String PREF_BLOCK_CALLS = "blockCalls";
|
||||
public static final String PREF_BLOCK_NEGATIVE_SIA_NUMBERS = "blockNegativeSiaNumbers";
|
||||
public static final String PREF_BLOCK_HIDDEN_NUMBERS = "blockHiddenNumbers";
|
||||
public static final String PREF_USE_CONTACTS = "useContacts";
|
||||
public static final String PREF_UI_MODE = "uiMode";
|
||||
public static final String PREF_NUMBER_OF_RECENT_CALLS = "numberOfRecentCalls";
|
||||
@ -26,7 +30,9 @@ public class Settings extends GenericSettings {
|
||||
|
||||
static final String SYS_PREFERENCES_VERSION = "__preferencesVersion";
|
||||
|
||||
private static final int PREFERENCES_VERSION = 1;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Settings.class);
|
||||
|
||||
private static final int PREFERENCES_VERSION = 2;
|
||||
|
||||
private volatile String cachedAutoDetectedCountryCode;
|
||||
|
||||
@ -43,7 +49,13 @@ public class Settings extends GenericSettings {
|
||||
|
||||
if (preferencesVersion == PREFERENCES_VERSION) return;
|
||||
|
||||
LOG.info("init() preferencesVersion={}", preferencesVersion);
|
||||
|
||||
String prefBlockCalls = "blockCalls";
|
||||
|
||||
if (preferencesVersion < 1) {
|
||||
LOG.debug("init() upgrading to 1");
|
||||
|
||||
PreferenceManager.setDefaultValues(context, R.xml.root_preferences, false);
|
||||
|
||||
Settings oldSettings = new Settings(context, "yacb_preferences");
|
||||
@ -51,8 +63,8 @@ public class Settings extends GenericSettings {
|
||||
if (oldSettings.isSet(PREF_INCOMING_CALL_NOTIFICATIONS)) {
|
||||
setIncomingCallNotifications(oldSettings.getIncomingCallNotifications());
|
||||
}
|
||||
if (oldSettings.isSet(PREF_BLOCK_CALLS)) {
|
||||
setBlockCalls(oldSettings.getBlockCalls());
|
||||
if (oldSettings.isSet(prefBlockCalls)) {
|
||||
setBoolean(prefBlockCalls, oldSettings.getBoolean(prefBlockCalls));
|
||||
}
|
||||
if (oldSettings.isSet(PREF_USE_CONTACTS)) {
|
||||
setUseContacts(oldSettings.getUseContacts());
|
||||
@ -60,8 +72,17 @@ public class Settings extends GenericSettings {
|
||||
setLastUpdateTime(oldSettings.getLastUpdateTime());
|
||||
setLastUpdateCheckTime(oldSettings.getLastUpdateCheckTime());
|
||||
}
|
||||
if (preferencesVersion < 2) {
|
||||
LOG.debug("init() upgrading to 2");
|
||||
|
||||
if (isSet(prefBlockCalls)) {
|
||||
setBlockNegativeSiaNumbers(getBoolean(prefBlockCalls));
|
||||
unset(prefBlockCalls);
|
||||
}
|
||||
}
|
||||
|
||||
setInt(SYS_PREFERENCES_VERSION, PREFERENCES_VERSION);
|
||||
LOG.debug("init() finished upgrade");
|
||||
}
|
||||
|
||||
public boolean getIncomingCallNotifications() {
|
||||
@ -72,12 +93,24 @@ public class Settings extends GenericSettings {
|
||||
setBoolean(PREF_INCOMING_CALL_NOTIFICATIONS, show);
|
||||
}
|
||||
|
||||
public boolean getBlockCalls() {
|
||||
return getBoolean(PREF_BLOCK_CALLS);
|
||||
public boolean getCallBlockingEnabled() {
|
||||
return getBlockNegativeSiaNumbers() || getBlockHiddenNumbers();
|
||||
}
|
||||
|
||||
public void setBlockCalls(boolean block) {
|
||||
setBoolean(PREF_BLOCK_CALLS, block);
|
||||
public boolean getBlockNegativeSiaNumbers() {
|
||||
return getBoolean(PREF_BLOCK_NEGATIVE_SIA_NUMBERS);
|
||||
}
|
||||
|
||||
public void setBlockNegativeSiaNumbers(boolean block) {
|
||||
setBoolean(PREF_BLOCK_NEGATIVE_SIA_NUMBERS, block);
|
||||
}
|
||||
|
||||
public boolean getBlockHiddenNumbers() {
|
||||
return getBoolean(PREF_BLOCK_HIDDEN_NUMBERS);
|
||||
}
|
||||
|
||||
public void setBlockHiddenNumbers(boolean block) {
|
||||
setBoolean(PREF_BLOCK_HIDDEN_NUMBERS, block);
|
||||
}
|
||||
|
||||
public boolean getUseContacts() {
|
||||
|
@ -76,7 +76,7 @@ public class SettingsActivity extends AppCompatActivity
|
||||
Settings settings = App.getSettings();
|
||||
|
||||
PermissionHelper.handlePermissionsResult(this, requestCode, permissions, grantResults,
|
||||
settings.getIncomingCallNotifications(), settings.getBlockCalls(),
|
||||
settings.getIncomingCallNotifications(), settings.getCallBlockingEnabled(),
|
||||
settings.getUseContacts());
|
||||
}
|
||||
|
||||
@ -143,14 +143,16 @@ public class SettingsActivity extends AppCompatActivity
|
||||
return true;
|
||||
});
|
||||
|
||||
SwitchPreferenceCompat blockCallsPref =
|
||||
requireNonNull(findPreference(Settings.PREF_BLOCK_CALLS));
|
||||
blockCallsPref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Preference.OnPreferenceChangeListener callBlockingListener = (preference, newValue) -> {
|
||||
if (Boolean.TRUE.equals(newValue)) {
|
||||
PermissionHelper.checkPermissions((AppCompatActivity) getActivity(), false, true, false);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
requireNonNull((SwitchPreferenceCompat) findPreference(Settings.PREF_BLOCK_NEGATIVE_SIA_NUMBERS))
|
||||
.setOnPreferenceChangeListener(callBlockingListener);
|
||||
requireNonNull((SwitchPreferenceCompat) findPreference(Settings.PREF_BLOCK_HIDDEN_NUMBERS))
|
||||
.setOnPreferenceChangeListener(callBlockingListener);
|
||||
|
||||
SwitchPreferenceCompat callScreeningPref =
|
||||
requireNonNull(findPreference(PREF_USE_CALL_SCREENING_SERVICE));
|
||||
|
@ -0,0 +1,29 @@
|
||||
package dummydomain.yetanothercallblocker.data;
|
||||
|
||||
import dummydomain.yetanothercallblocker.Settings;
|
||||
|
||||
public class BlockingDecisionMaker implements DatabaseSingleton.BlockingDecisionMaker {
|
||||
|
||||
private final Settings settings;
|
||||
|
||||
public BlockingDecisionMaker(Settings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBlock(NumberInfo numberInfo) {
|
||||
if (numberInfo.contactItem != null) return false;
|
||||
|
||||
if (numberInfo.isHiddenNumber && settings.getBlockHiddenNumbers()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (numberInfo.rating == NumberInfo.Rating.NEGATIVE
|
||||
&& settings.getBlockNegativeSiaNumbers()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -104,6 +104,8 @@ public class Config {
|
||||
DatabaseSingleton.setDbManager(new DbManager(storage, SIA_PATH_PREFIX,
|
||||
new DbDownloader(okHttpClientFactory)));
|
||||
|
||||
DatabaseSingleton.setHiddenNumberDetector(NumberUtils::isHiddenNumber);
|
||||
|
||||
CommunityDatabase communityDatabase = new CommunityDatabase(
|
||||
storage, AbstractDatabase.Source.ANY, SIA_PATH_PREFIX,
|
||||
SIA_SECONDARY_PATH_PREFIX, siaSettings, webService);
|
||||
@ -129,6 +131,8 @@ public class Config {
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
DatabaseSingleton.setBlockingDecisionMaker(new BlockingDecisionMaker(settings));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ public class DatabaseSingleton {
|
||||
|
||||
private static SiaMetadata siaMetadata;
|
||||
|
||||
private static HiddenNumberDetector hiddenNumberDetector;
|
||||
|
||||
private static CommunityDatabase communityDatabase;
|
||||
|
||||
private static FeaturedDatabase featuredDatabase;
|
||||
@ -32,6 +34,8 @@ public class DatabaseSingleton {
|
||||
|
||||
private static ContactsProvider contactsProvider;
|
||||
|
||||
private static BlockingDecisionMaker blockingDecisionMaker;
|
||||
|
||||
static void setWebService(WebService webService) {
|
||||
DatabaseSingleton.webService = webService;
|
||||
}
|
||||
@ -44,6 +48,10 @@ public class DatabaseSingleton {
|
||||
DatabaseSingleton.siaMetadata = siaMetadata;
|
||||
}
|
||||
|
||||
static void setHiddenNumberDetector(HiddenNumberDetector hiddenNumberDetector) {
|
||||
DatabaseSingleton.hiddenNumberDetector = hiddenNumberDetector;
|
||||
}
|
||||
|
||||
static void setCommunityDatabase(CommunityDatabase communityDatabase) {
|
||||
DatabaseSingleton.communityDatabase = communityDatabase;
|
||||
}
|
||||
@ -60,6 +68,10 @@ public class DatabaseSingleton {
|
||||
DatabaseSingleton.contactsProvider = contactsProvider;
|
||||
}
|
||||
|
||||
static void setBlockingDecisionMaker(BlockingDecisionMaker blockingDecisionMaker) {
|
||||
DatabaseSingleton.blockingDecisionMaker = blockingDecisionMaker;
|
||||
}
|
||||
|
||||
public static WebService getWebService() {
|
||||
return webService;
|
||||
}
|
||||
@ -88,24 +100,37 @@ public class DatabaseSingleton {
|
||||
LOG.debug("getNumberInfo({}) started", number);
|
||||
// TODO: check number format
|
||||
|
||||
CommunityDatabaseItem communityItem = DatabaseSingleton.getCommunityDatabase()
|
||||
.getDbItemByNumber(number);
|
||||
LOG.trace("getNumberInfo() communityItem={}", communityItem);
|
||||
|
||||
FeaturedDatabaseItem featuredItem = DatabaseSingleton.getFeaturedDatabase()
|
||||
.getDbItemByNumber(number);
|
||||
LOG.trace("getNumberInfo() featuredItem={}", featuredItem);
|
||||
|
||||
ContactItem contactItem = DatabaseSingleton.contactsProvider.get(number);
|
||||
LOG.trace("getNumberInfo() contactItem={}", contactItem);
|
||||
|
||||
NumberInfo numberInfo = new NumberInfo();
|
||||
numberInfo.number = number;
|
||||
|
||||
numberInfo.communityDatabaseItem = communityItem;
|
||||
numberInfo.featuredDatabaseItem = featuredItem;
|
||||
numberInfo.contactItem = contactItem;
|
||||
if (hiddenNumberDetector != null) {
|
||||
numberInfo.isHiddenNumber = hiddenNumberDetector.isHiddenNumber(number);
|
||||
}
|
||||
LOG.trace("getNumberInfo() isHiddenNumber={}", numberInfo.isHiddenNumber);
|
||||
|
||||
if (numberInfo.isHiddenNumber || TextUtils.isEmpty(numberInfo.number)) {
|
||||
numberInfo.noNumber = true;
|
||||
}
|
||||
LOG.trace("getNumberInfo() noNumber={}", numberInfo.noNumber);
|
||||
|
||||
if (numberInfo.noNumber) {
|
||||
LOG.debug("getNumberInfo() finished");
|
||||
return numberInfo;
|
||||
}
|
||||
|
||||
numberInfo.communityDatabaseItem = DatabaseSingleton.getCommunityDatabase()
|
||||
.getDbItemByNumber(number);
|
||||
LOG.trace("getNumberInfo() communityItem={}", numberInfo.communityDatabaseItem);
|
||||
|
||||
numberInfo.featuredDatabaseItem = DatabaseSingleton.getFeaturedDatabase()
|
||||
.getDbItemByNumber(number);
|
||||
LOG.trace("getNumberInfo() featuredItem={}", numberInfo.featuredDatabaseItem);
|
||||
|
||||
numberInfo.contactItem = DatabaseSingleton.contactsProvider.get(number);
|
||||
LOG.trace("getNumberInfo() contactItem={}", numberInfo.contactItem);
|
||||
|
||||
ContactItem contactItem = numberInfo.contactItem;
|
||||
FeaturedDatabaseItem featuredItem = numberInfo.featuredDatabaseItem;
|
||||
if (contactItem != null && !TextUtils.isEmpty(contactItem.displayName)) {
|
||||
numberInfo.name = contactItem.displayName;
|
||||
} else if (featuredItem != null && !TextUtils.isEmpty(featuredItem.getName())) {
|
||||
@ -113,6 +138,7 @@ public class DatabaseSingleton {
|
||||
}
|
||||
LOG.trace("getNumberInfo() name={}", numberInfo.name);
|
||||
|
||||
CommunityDatabaseItem communityItem = numberInfo.communityDatabaseItem;
|
||||
if (communityItem != null && communityItem.hasRatings()) {
|
||||
if (communityItem.getNegativeRatingsCount() > communityItem.getPositiveRatingsCount()
|
||||
+ communityItem.getNeutralRatingsCount()) {
|
||||
@ -127,7 +153,23 @@ public class DatabaseSingleton {
|
||||
}
|
||||
LOG.trace("getNumberInfo() rating={}", numberInfo.rating);
|
||||
|
||||
LOG.debug("getNumberInfo() finished");
|
||||
return numberInfo;
|
||||
}
|
||||
|
||||
public static boolean shouldBlock(NumberInfo numberInfo) {
|
||||
if (blockingDecisionMaker != null) {
|
||||
return blockingDecisionMaker.shouldBlock(numberInfo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface HiddenNumberDetector {
|
||||
boolean isHiddenNumber(String number);
|
||||
}
|
||||
|
||||
public interface BlockingDecisionMaker {
|
||||
boolean shouldBlock(NumberInfo numberInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ public class NumberInfo {
|
||||
public String number;
|
||||
|
||||
// info from various sources
|
||||
public boolean isHiddenNumber;
|
||||
public CommunityDatabaseItem communityDatabaseItem;
|
||||
public FeaturedDatabaseItem featuredDatabaseItem;
|
||||
public ContactItem contactItem;
|
||||
@ -20,7 +21,8 @@ public class NumberInfo {
|
||||
// computed rating
|
||||
public Rating rating = Rating.UNKNOWN;
|
||||
|
||||
// name (for convenience)
|
||||
// precomputed for convenience
|
||||
public boolean noNumber;
|
||||
public String name;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package dummydomain.yetanothercallblocker.data;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public class NumberUtils {
|
||||
|
||||
private static final Set<String> HIDDEN_NUMBERS = new HashSet<>(Arrays.asList(
|
||||
"-1", "-2", "UNAVAILABLE", "ABSENT NUMBER", "NNN", "PRIVATE NUMBER"
|
||||
));
|
||||
|
||||
public static boolean isHiddenNumber(String number) {
|
||||
if (TextUtils.isEmpty(number) || TextUtils.getTrimmedLength(number) == 0) return true;
|
||||
return HIDDEN_NUMBERS.contains(number.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package dummydomain.yetanothercallblocker.event;
|
||||
|
||||
public class CallStartedEvent extends CallEvent {}
|
@ -11,7 +11,7 @@
|
||||
android:id="@+id/menu_block_calls"
|
||||
android:checkable="true"
|
||||
android:onClick="onBlockCallsChanged"
|
||||
android:title="@string/block_calls" />
|
||||
android:title="@string/block_negative_sia_short" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_auto_updates"
|
||||
|
@ -84,8 +84,6 @@
|
||||
|
||||
<string name="incoming_call_notifications">Notificaciones de llamadas entrantes</string>
|
||||
<string name="incoming_call_notifications_summary">Muestra una notificación con el resumen del número de teléfono (clasificación, recuento de revisiones, categoría) durante las llamadas entrantes</string>
|
||||
<string name="block_calls">Bloqueo de llamadas no deseadas</string>
|
||||
<string name="block_calls_summary">Automáticamente bloquea las llamadas con calificación negativa</string>
|
||||
<string name="auto_updates">Base de datos de actualización automática</string>
|
||||
<string name="auto_updates_summary">Automáticamente recibe actualizaciones diarias de la BD (estas son actualizaciones incrementales/delta, por lo que consumen muy poco tráfico)</string>
|
||||
<string name="use_contacts">Usar contactos</string>
|
||||
|
@ -74,7 +74,6 @@
|
||||
<string name="load_reviews_confirmation_message">Door online-recensies te laden, lekt het nummer uit naar een externe dienst. Weet je zeker dat je dit wilt doen met een nummer uit je contactpersonenlijst?</string>
|
||||
|
||||
<string name="incoming_call_notifications">Inkomende oproep-meldingen</string>
|
||||
<string name="block_calls">Ongewenste oproepen blokkeren</string>
|
||||
<string name="auto_updates">Databank automatisch bijwerken</string>
|
||||
<string name="use_contacts">Contactpersonen uitlezen</string>
|
||||
|
||||
|
@ -20,8 +20,11 @@
|
||||
<string name="sia_category_service">Сервис/услуги</string>
|
||||
<string name="sia_category_robocall">Робот/автомат</string>
|
||||
<string name="sia_category_nonprofit">Некоммерческая орг-я</string>
|
||||
<string name="block_calls">Блокир-ть нежелат. вызовы</string>
|
||||
<string name="block_calls_summary">Автоматически сбрасывать звонки c номеров с отрицательным рейтингом</string>
|
||||
<string name="block_negative_sia_short">Блокир. по отзывам</string>
|
||||
<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="use_call_screening_service">Продвинутый режим блокирования вызовов</string>
|
||||
<string name="use_call_screening_service_summary">Позволяет блокировать вызовы до того, как телефон зазвонит. Это требует назначить приложение \"приложением для звонков\" (на Android 7–9) или \"приложением для АОН и защиты от спама\" (на Android 10+)</string>
|
||||
<string name="use_call_screening_service_disable_message">Выберите другое приложение для звонков или защиты от спама в меню Настройки - Приложения - Приложения по умолчанию</string>
|
||||
@ -112,4 +115,5 @@
|
||||
<string name="save_logcat_to_file_summary">Сохранить содержимое logcat в файл в общем хранилище (/sdcard/Android/data/dummydomain.yetanothercallblocker/files/). Отчёты могут содержать конфиденциальные данные (номера телефонов, имена контактов). Другие приложения с разрешением на доступ к хранилищу могут иметь доступ к этим данным в общем хранилище</string>
|
||||
<string name="save_logcat_to_file_done">Выполнено</string>
|
||||
<string name="save_logcat_to_file_error">Ошибка</string>
|
||||
<string name="no_number"><![CDATA[<нет номера>]]></string>
|
||||
</resources>
|
@ -89,8 +89,11 @@
|
||||
|
||||
<string name="incoming_call_notifications">Incoming call notifications</string>
|
||||
<string name="incoming_call_notifications_summary">Displays a notification with phone number summary (rating, reviews count, category) during incoming calls</string>
|
||||
<string name="block_calls">Block unwanted calls</string>
|
||||
<string name="block_calls_summary">Automatically blocks calls with negative rating</string>
|
||||
<string name="block_negative_sia_short">Block by rating</string>
|
||||
<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">Block calls from hidden numbers. Experimental. Probably works better in \"advanced call blocking mode\". Please report your experience in the repo issues on gitlab</string>
|
||||
<string name="use_call_screening_service">Advanced call blocking mode</string>
|
||||
<string name="use_call_screening_service_summary">Allows to block calls before the phone starts to ring. Requires the app to be set as the \"Phone app\" (Android 7–9) or as the \"Caller ID app\" (Android 10+)</string>
|
||||
<string name="use_call_screening_service_disable_message">Select different \"Phone app\" or \"Caller ID app\" in Settings - Apps - Default apps</string>
|
||||
@ -124,6 +127,7 @@
|
||||
<string name="save_logcat_to_file_summary">Save logcat output to a file in public storage (/sdcard/Android/data/dummydomain.yetanothercallblocker/files/). The reports may contain sensitive data (phone numbers, contact names). Other apps with storage permission may have access to this data in public storage</string>
|
||||
<string name="save_logcat_to_file_done">Done</string>
|
||||
<string name="save_logcat_to_file_error">Error</string>
|
||||
<string name="no_number"><![CDATA[<no number>]]></string>
|
||||
|
||||
<string name="open_debug_activity">Open debug screen</string>
|
||||
<string name="debug_activity_label">Debug</string>
|
||||
|
@ -31,9 +31,13 @@
|
||||
|
||||
<PreferenceCategory app:title="@string/settings_category_call_blocking">
|
||||
<SwitchPreferenceCompat
|
||||
app:key="blockCalls"
|
||||
app:summary="@string/block_calls_summary"
|
||||
app:title="@string/block_calls" />
|
||||
app:key="blockNegativeSiaNumbers"
|
||||
app:summary="@string/block_negative_sia_numbers_summary"
|
||||
app:title="@string/block_negative_sia" />
|
||||
<SwitchPreferenceCompat
|
||||
app:key="blockHiddenNumbers"
|
||||
app:summary="@string/block_hidden_number_summary"
|
||||
app:title="@string/block_hidden_number" />
|
||||
<SwitchPreferenceCompat
|
||||
app:key="useCallScreeningService"
|
||||
app:persistent="false"
|
||||
|
Loading…
x
Reference in New Issue
Block a user