Add DB filtering

This commit is contained in:
xynngh 2021-06-03 23:24:52 +04:00
parent 1f3b621450
commit 91ddb35296
12 changed files with 385 additions and 8 deletions

View File

@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- \[Advanced\] Options for database filtering to save storage space.
- Vietnamese translation thanks to bruh ([@quangtrung02hn16](https://hosted.weblate.org/user/quangtrung02hn16/)).
- Esperanto translation of the app description thanks to phlostically ([@phlostically](https://hosted.weblate.org/user/phlostically/)).

View File

@ -0,0 +1,81 @@
package dummydomain.yetanothercallblocker;
import android.text.TextUtils;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.EditTextPreference;
import java.util.ArrayList;
import java.util.List;
import dummydomain.yetanothercallblocker.data.YacbHolder;
import dummydomain.yetanothercallblocker.utils.DbFilteringUtils;
import dummydomain.yetanothercallblocker.work.TaskService;
import static dummydomain.yetanothercallblocker.Settings.PREF_DB_FILTERING_PREFIXES_TO_KEEP;
public class DbFilteringSettingsFragment extends BaseSettingsFragment {
private static final String PREF_SCREEN_DB_FILTERING = "dbFiltering";
private static final String PREF_INFO = "dbFilteringInfo";
private static final String PREF_FILTER_DB = "dbFilteringFilterDb";
private final Settings settings = App.getSettings();
@Override
protected String getScreenKey() {
return PREF_SCREEN_DB_FILTERING;
}
@Override
protected int getPreferencesResId() {
return R.xml.db_filtering_preferences;
}
@Override
protected void initScreen() {
requirePreference(PREF_INFO).setOnPreferenceClickListener(pref -> {
new AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_screen_db_filtering)
.setMessage(pref.getSummary())
.setNegativeButton(R.string.back, null)
.show();
return true;
});
setPrefChangeListener(PREF_DB_FILTERING_PREFIXES_TO_KEEP, (pref, newValue) -> {
String value = (String) newValue;
List<String> prefixes = new ArrayList<>();
for (String prefix : DbFilteringUtils.parsePrefixes(value)) {
prefixes.add("+" + prefix);
}
String formattedPrefixes = TextUtils.join(",", prefixes);
if (!TextUtils.equals(formattedPrefixes, value)) {
((EditTextPreference) pref).setText(formattedPrefixes);
return false;
}
return true;
});
requirePreference(PREF_FILTER_DB).setOnPreferenceClickListener(preference -> {
updateFilter();
TaskService.start(requireContext(), TaskService.TASK_FILTER_DB);
return true;
});
}
@Override
public void onStop() {
super.onStop();
updateFilter();
}
private void updateFilter() {
YacbHolder.getDbManager().setNumberFilter(DbFilteringUtils.getNumberFilter(settings));
}
}

View File

@ -34,6 +34,11 @@ public class Settings extends GenericSettings {
public static final String PREF_BLOCK_IN_LIMITED_MODE = "blockInLimitedMode";
public static final String PREF_LAST_UPDATE_TIME = "lastUpdateTime";
public static final String PREF_LAST_UPDATE_CHECK_TIME = "lastUpdateCheckTime";
public static final String PREF_DB_FILTERING_ENABLED = "dbFilteringEnabled";
public static final String PREF_DB_FILTERING_PREFIXES_TO_KEEP = "dbFilteringPrefixesToKeep";
public static final String PREF_DB_FILTERING_THOROUGH = "dbFilteringThorough";
public static final String PREF_DB_FILTERING_KEEP_SHORT_NUMBERS = "dbFilteringKeepShortNumbers";
public static final String PREF_DB_FILTERING_KEEP_SHORT_NUMBERS_MAX_LENGTH = "dbFilteringKeepShortNumbersMaxLength";
public static final String PREF_COUNTRY_CODE_OVERRIDE = "countryCodeOverride";
public static final String PREF_COUNTRY_CODE_FOR_REVIEWS_OVERRIDE = "countryCodeForReviewsOverride";
public static final String PREF_DATABASE_DOWNLOAD_URL = "databaseDownloadUrl";
@ -242,6 +247,46 @@ public class Settings extends GenericSettings {
setLong(PREF_LAST_UPDATE_CHECK_TIME, timestamp);
}
public boolean isDbFilteringEnabled() {
return getBoolean(PREF_DB_FILTERING_ENABLED);
}
public void setDbFilteringEnabled(boolean enabled) {
setBoolean(PREF_DB_FILTERING_ENABLED, enabled);
}
public String getDbFilteringPrefixesToKeep() {
return getString(PREF_DB_FILTERING_PREFIXES_TO_KEEP);
}
public void setDbFilteringPrefixesToKeep(String prefixes) {
setString(PREF_DB_FILTERING_PREFIXES_TO_KEEP, prefixes);
}
public boolean isDbFilteringThorough() {
return getBoolean(PREF_DB_FILTERING_THOROUGH, true);
}
public void setDbFilteringThorough(boolean thorough) {
setBoolean(PREF_DB_FILTERING_THOROUGH, thorough);
}
public boolean getDbFilteringKeepShortNumbers() {
return getBoolean(PREF_DB_FILTERING_KEEP_SHORT_NUMBERS, true);
}
public void setDbFilteringKeepShortNumbers(boolean keep) {
setBoolean(PREF_DB_FILTERING_KEEP_SHORT_NUMBERS, keep);
}
public int getDbFilteringKeepShortNumbersMaxLength() {
return getInt(PREF_DB_FILTERING_KEEP_SHORT_NUMBERS_MAX_LENGTH, 5);
}
public void setDbFilteringKeepShortNumbersMaxLength(int length) {
setInt(PREF_DB_FILTERING_KEEP_SHORT_NUMBERS_MAX_LENGTH, length);
}
public String getCountryCodeOverride() {
return getString(PREF_COUNTRY_CODE_OVERRIDE);
}

View File

@ -22,6 +22,7 @@ import dummydomain.yetanothercallblocker.sia.network.DbUpdateRequester;
import dummydomain.yetanothercallblocker.sia.network.OkHttpClientFactory;
import dummydomain.yetanothercallblocker.sia.network.WebService;
import dummydomain.yetanothercallblocker.sia.utils.Utils;
import dummydomain.yetanothercallblocker.utils.DbFilteringUtils;
import dummydomain.yetanothercallblocker.utils.DeferredInit;
import dummydomain.yetanothercallblocker.utils.SystemUtils;
import okhttp3.OkHttpClient;
@ -117,6 +118,8 @@ public class Config {
new DbDownloader(okHttpClientFactory), new DbUpdateRequester(webService),
communityDatabase));
YacbHolder.getDbManager().setNumberFilter(DbFilteringUtils.getNumberFilter(settings));
YacbHolder.setCommunityReviewsLoader(new CommunityReviewsLoader(webService));
YacbDaoSessionFactory daoSessionFactory = new YacbDaoSessionFactory(context, "YACB");

View File

@ -0,0 +1,50 @@
package dummydomain.yetanothercallblocker.data;
import java.util.List;
public class NumberFilter
implements dummydomain.yetanothercallblocker.sia.model.database.NumberFilter {
private final String[] prefixesToKeep;
private final int keepLength;
private final boolean detailed;
public NumberFilter(List<String> prefixesToKeep, boolean detailed, int keepLength) {
this.prefixesToKeep = prefixesToKeep.toArray(new String[0]);
this.detailed = detailed;
this.keepLength = keepLength;
}
@Override
public boolean keepPrefix(String prefix) {
for (String prefixToKeep : prefixesToKeep) {
if (prefixMatch(prefix, prefixToKeep)) return true;
}
return false;
}
@Override
public boolean keepNumber(String number) {
if (detailed && keepLength > 0 && number.length() <= keepLength) return true;
for (String prefixToKeep : prefixesToKeep) {
if (number.startsWith(prefixToKeep)) return true;
}
return false;
}
@Override
public boolean isDetailed() {
return detailed;
}
private boolean prefixMatch(String prefix, String keepPrefix) {
if (prefix.length() < keepPrefix.length()) {
return keepPrefix.startsWith(prefix);
} else {
return prefix.startsWith(keepPrefix);
}
}
}

View File

@ -0,0 +1,54 @@
package dummydomain.yetanothercallblocker.preference;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.preference.EditTextPreference;
public class IntEditTextPreference extends EditTextPreference {
public IntEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setListener();
}
public IntEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setListener();
}
public IntEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setListener();
}
public IntEditTextPreference(Context context) {
super(context);
setListener();
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInt(index, 0);
}
@Override
protected void onSetInitialValue(Object defaultValue) {
int defaultInt = defaultValue != null ? (int) defaultValue : 0;
setText(String.valueOf(getPersistedInt(defaultInt)));
}
@Override
protected boolean persistString(String value) {
return persistInt(!TextUtils.isEmpty(value) ? Integer.parseInt(value) : 0);
}
private void setListener() {
setOnBindEditTextListener(editText -> editText.setInputType(InputType.TYPE_CLASS_NUMBER));
}
}

View File

@ -0,0 +1,40 @@
package dummydomain.yetanothercallblocker.utils;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import dummydomain.yetanothercallblocker.Settings;
import dummydomain.yetanothercallblocker.data.NumberFilter;
public class DbFilteringUtils {
public static NumberFilter getNumberFilter(Settings settings) {
if (!settings.isDbFilteringEnabled()) return null;
return new NumberFilter(getPrefixesToKeep(settings),
settings.isDbFilteringThorough(),
settings.getDbFilteringKeepShortNumbers()
? settings.getDbFilteringKeepShortNumbersMaxLength() : 0);
}
public static List<String> getPrefixesToKeep(Settings settings) {
return parsePrefixes(settings.getDbFilteringPrefixesToKeep());
}
public static List<String> parsePrefixes(String prefixesString) {
if (TextUtils.isEmpty(prefixesString)) return Collections.emptyList();
List<String> prefixList = new ArrayList<>();
for (String prefix : prefixesString.split("[,;]")) {
prefix = prefix.replaceAll("[^0-9]", "");
if (!prefix.isEmpty() && !prefixList.contains(prefix)) prefixList.add(prefix);
}
return prefixList;
}
}

View File

@ -28,6 +28,7 @@ public class TaskService extends IntentService {
public static final String TASK_DOWNLOAD_MAIN_DB = "download_main_db";
public static final String TASK_UPDATE_SECONDARY_DB = "update_secondary_db";
public static final String TASK_FILTER_DB = "filter_db";
private static final Logger LOG = LoggerFactory.getLogger(TaskService.class);
@ -61,6 +62,11 @@ public class TaskService extends IntentService {
updateSecondaryDb();
break;
case TASK_FILTER_DB:
updateNotification(getString(R.string.filtering_db));
filterDb();
break;
default:
LOG.warn("Unknown action: " + action);
break;
@ -102,4 +108,8 @@ public class TaskService extends IntentService {
new DbUpdater().update();
}
private void filterDb() {
YacbHolder.getDbManager().filterDb();
}
}

View File

@ -214,4 +214,21 @@
<string name="translate">Перевести приложение на Weblate</string>
<string name="issues">Получить поддержку / сообщить о проблеме</string>
<string name="license">Это приложение распространяется под лицензией AGPL-3.0-only.</string>
<string name="settings_category_database">База данных</string>
<string name="settings_screen_db_filtering">Фильтрация базы данных</string>
<string name="db_filtering_info">Пояснение</string>
<string name="db_filtering_info_summary">Эта функция позволят сэкономить место в хранилище путём удаления неприменимых к вам данных (таких как номера из других регионов и стран). Она не влияет на общую скорость работы приложения (например, на блокировку вызовов). Фильтрация происходит во время начальной загрузки базы и во время её обновления. Существующие данные (загруженные до включения фильтрации) могут быть отфильтрованы с помощью опции \"Отфильтровать базу\" ниже. Отключение фильтрации или изменение её параметров не восстанавливает удалённые данные - для этого вам потребуется загрузить их заново</string>
<string name="db_filtering_enabled">Фильтрация включена</string>
<string name="db_filtering_enabled_summary">Включает фильтрацию во время загрузки и обновления базы</string>
<string name="db_filtering_prefixes_to_keep">Префиксы для сохранения</string>
<string name="db_filtering_prefixes_to_keep_summary">Список (разделённый запятыми) префиксов номеров, которые нужно сохранить. Префиксы должны быть в международной формате (например, +7999). Например, если вам звонят только номера начинающиеся на +7, введите сюда +7</string>
<string name="db_filtering_thorough">Тщательная фильтрация</string>
<string name="db_filtering_thorough_summary">Если включена, фильтрация проходит по всем блокам данных и удаляет номера, не подходящие по префиксам. В противном случае удаляются только целые блоки (оставляя некоторые лишние номера в сохраняемых блоках). Рекомендуется оставить включённым. Требуется для сохранения коротких номеров</string>
<string name="db_filtering_keep_short_numbers">Сохранять короткие номера</string>
<string name="db_filtering_keep_short_numbers_summary">Сохранять номера, короче указанной длины, вне зависимости от префиксов</string>
<string name="db_filtering_keep_short_numbers_max_length">Длина номеров для сохранения</string>
<string name="db_filtering_keep_short_numbers_max_length_summary">Максимальная длина (включительная) коротких номеров, которые нужно сохранить вне зависимости от префиксов. Например, значение 5 сохранит номера длиной 5 цифр и короче</string>
<string name="db_filtering_filter_db">Отфильтровать базу</string>
<string name="db_filtering_filter_db_summary">Запустить фильтрацию базы сейчас (чтобы отфильтровать существующие данные)</string>
<string name="filtering_db">Фильтрация базы номеров…</string>
</resources>

View File

@ -128,6 +128,7 @@
<string name="call_log_grouping_day">Non-consecutive in a day</string>
<string name="settings_screen_advanced">Advanced settings</string>
<string name="settings_category_database">Database</string>
<string name="block_in_limited_mode">Block in Direct Boot mode</string>
<string name="block_in_limited_mode_summary">Allowed kinds of blocking in Direct Boot mode (Contacts can\'t be reliably used as a whitelist in this mode)</string>
<string name="block_in_limited_mode_rating">By rating</string>
@ -149,6 +150,24 @@
<string name="save_logcat_on_crash_summary">Save logcat output on crash (in addition to a basic stacktrace)</string>
<string name="export_logcat">Export logcat</string>
<string name="export_logcat_summary">Export and share logcat contents with an app of your choosing (for example with an email client). The reports may contain sensitive data (phone numbers, contact names). Only the chosen app will have access to this data</string>
<string name="settings_screen_db_filtering">Database filtering</string>
<string name="db_filtering_info">Explanation</string>
<string name="db_filtering_info_summary">This feature allows to save storage space by removing some data that is not applicable to you (like numbers belonging to different regions or countries). It doesn\'t affect general app performance (like call blocking). Filtering occurs during the initial database download and during database update. Existing data (downloaded prior to enabling the filtering) may be filtered using the \"Filter the database\" option below. Disabling the feature or changing its parameters doesn\'t restore removed data - you need to re-download the database for that</string>
<string name="db_filtering_enabled">Filtering enabled</string>
<string name="db_filtering_enabled_summary">Enables the filtering during the database download and update</string>
<string name="db_filtering_prefixes_to_keep">Prefixes to keep</string>
<string name="db_filtering_prefixes_to_keep_summary">A comma-separated list of prefixes of numbers to keep. The prefixes should be in the international format (like +1234). E.g., if you only receive calls from numbers starting with +1, put +1 here</string>
<string name="db_filtering_thorough">Thorough filtering</string>
<string name="db_filtering_thorough_summary">If enabled, it goes through every block of data and removes numbers not matching the prefixes. Otherwise, it only removes whole unwanted blocks (leaving some unwanted numbers in wanted blocks). It is recommended to leave this on. Required for keeping short numbers</string>
<string name="db_filtering_keep_short_numbers">Keep short numbers</string>
<string name="db_filtering_keep_short_numbers_summary">Keep numbers shorter than the specified length regardless of prefixes</string>
<string name="db_filtering_keep_short_numbers_max_length">Length of numbers to keep</string>
<string name="db_filtering_keep_short_numbers_max_length_summary">The maximum length (inclusive) of short numbers to keep regardless of prefixes. E.g. the value of 5 will keep numbers with length of 5 digits or shorter</string>
<string name="db_filtering_filter_db">Filter the database</string>
<string name="db_filtering_filter_db_summary">Run the database filtering now (to filter the existing data)</string>
<string name="filtering_db">Filtering DB…</string>
<string name="no_number"><![CDATA[<no number>]]></string>
<string name="save">Save</string>
<plurals name="selected_count">

View File

@ -4,6 +4,10 @@
app:key="screenAdvanced"
app:title="@string/settings_screen_advanced">
<PreferenceCategory
app:key="categoryAdvancedDb"
app:title="@string/settings_category_database">
<Preference
app:key="dbManagement"
app:persistent="false"
@ -13,6 +17,13 @@
android:targetPackage="@string/app_id" />
</Preference>
<Preference
app:fragment="dummydomain.yetanothercallblocker.DbFilteringSettingsFragment"
app:key="dbFiltering"
app:title="@string/settings_screen_db_filtering" />
</PreferenceCategory>
<MultiSelectListPreference
android:defaultValue="@array/block_in_limited_mode_default_values"
android:entries="@array/block_in_limited_mode_entries"

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
app:key="dbFiltering"
app:title="@string/settings_screen_db_filtering">
<Preference
app:key="dbFilteringInfo"
app:persistent="false"
app:summary="@string/db_filtering_info_summary"
app:title="@string/db_filtering_info" />
<SwitchPreferenceCompat
app:key="dbFilteringEnabled"
app:summary="@string/db_filtering_enabled_summary"
app:title="@string/db_filtering_enabled" />
<EditTextPreference
app:key="dbFilteringPrefixesToKeep"
app:summary="@string/db_filtering_prefixes_to_keep_summary"
app:title="@string/db_filtering_prefixes_to_keep" />
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="dbFilteringThorough"
app:summary="@string/db_filtering_thorough_summary"
app:title="@string/db_filtering_thorough" />
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="dbFilteringKeepShortNumbers"
app:summary="@string/db_filtering_keep_short_numbers_summary"
app:title="@string/db_filtering_keep_short_numbers" />
<dummydomain.yetanothercallblocker.preference.IntEditTextPreference
app:defaultValue="5"
app:key="dbFilteringKeepShortNumbersMaxLength"
app:summary="@string/db_filtering_keep_short_numbers_max_length_summary"
app:title="@string/db_filtering_keep_short_numbers_max_length" />
<Preference
app:key="dbFilteringFilterDb"
app:persistent="false"
app:summary="@string/db_filtering_filter_db_summary"
app:title="@string/db_filtering_filter_db" />
</PreferenceScreen>