Refactoring
Use foreground IntentService for DB loading and update. Add EventBus. Some other changes.
This commit is contained in:
parent
3f6778cbc7
commit
cf32cf41cb
|
@ -8,6 +8,12 @@ android {
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 3040
|
versionCode 3040
|
||||||
versionName "0.3.4"
|
versionName "0.3.4"
|
||||||
|
|
||||||
|
javaCompileOptions {
|
||||||
|
annotationProcessorOptions {
|
||||||
|
arguments = [eventBusIndex: 'dummydomain.yetanothercallblocker.EventBusIndex']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
@ -25,6 +31,8 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
def eventbus_version = '3.2.0'
|
||||||
|
|
||||||
implementation 'org.slf4j:slf4j-api:1.7.30'
|
implementation 'org.slf4j:slf4j-api:1.7.30'
|
||||||
implementation 'com.github.tony19:logback-android:2.0.0'
|
implementation 'com.github.tony19:logback-android:2.0.0'
|
||||||
//noinspection GradleDependency: 3.12.* is the latest version compatible with Android <5
|
//noinspection GradleDependency: 3.12.* is the latest version compatible with Android <5
|
||||||
|
@ -35,4 +43,6 @@ dependencies {
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
implementation 'com.google.android.material:material:1.1.0'
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
implementation 'androidx.work:work-runtime:2.3.4'
|
implementation 'androidx.work:work-runtime:2.3.4'
|
||||||
|
implementation "org.greenrobot:eventbus:$eventbus_version"
|
||||||
|
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,3 +19,14 @@
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-keepattributes *Annotation*
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||||
|
}
|
||||||
|
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
||||||
|
|
||||||
|
# And if you use AsyncExecutor:
|
||||||
|
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
|
||||||
|
<init>(java.lang.Throwable);
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
<action android:name="android.intent.action.PHONE_STATE" />
|
<action android:name="android.intent.action.PHONE_STATE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<service android:name=".work.TaskService" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -2,6 +2,8 @@ package dummydomain.yetanothercallblocker;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
|
|
||||||
private static App instance;
|
private static App instance;
|
||||||
|
@ -12,6 +14,14 @@ public class App extends Application {
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
|
EventBus.builder()
|
||||||
|
.throwSubscriberException(BuildConfig.DEBUG)
|
||||||
|
.sendNoSubscriberEvent(false)
|
||||||
|
.addIndex(new EventBusIndex())
|
||||||
|
.installDefaultEventBus();
|
||||||
|
|
||||||
|
EventHandler.create(this);
|
||||||
|
|
||||||
NotificationHelper.createNotificationChannels(this);
|
NotificationHelper.createNotificationChannels(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,16 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
|
|
||||||
|
import dummydomain.yetanothercallblocker.event.SecondaryDbUpdateFinished;
|
||||||
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
||||||
import dummydomain.yetanothercallblocker.sia.model.NumberCategory;
|
import dummydomain.yetanothercallblocker.sia.model.NumberCategory;
|
||||||
import dummydomain.yetanothercallblocker.sia.model.database.CommunityDatabaseItem;
|
import dummydomain.yetanothercallblocker.sia.model.database.CommunityDatabaseItem;
|
||||||
import dummydomain.yetanothercallblocker.sia.model.database.FeaturedDatabaseItem;
|
import dummydomain.yetanothercallblocker.sia.model.database.FeaturedDatabaseItem;
|
||||||
|
import dummydomain.yetanothercallblocker.work.TaskService;
|
||||||
|
|
||||||
public class DebugActivity extends AppCompatActivity {
|
public class DebugActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@ -22,6 +28,26 @@ public class DebugActivity extends AppCompatActivity {
|
||||||
hideSummary();
|
hideSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
|
||||||
|
EventBus.getDefault().register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
EventBus.getDefault().unregister(this);
|
||||||
|
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
|
||||||
|
public void onSecondaryDbUpdateFinished(SecondaryDbUpdateFinished event) {
|
||||||
|
setResult(getString(R.string.debug_update_result,
|
||||||
|
DatabaseSingleton.getCommunityDatabase().getEffectiveDbVersion()));
|
||||||
|
}
|
||||||
|
|
||||||
public void onQueryDbButtonClick(View view) {
|
public void onQueryDbButtonClick(View view) {
|
||||||
setResult("");
|
setResult("");
|
||||||
hideSummary();
|
hideSummary();
|
||||||
|
@ -90,20 +116,7 @@ public class DebugActivity extends AppCompatActivity {
|
||||||
setResult("");
|
setResult("");
|
||||||
hideSummary();
|
hideSummary();
|
||||||
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
TaskService.start(this, TaskService.TASK_UPDATE_SECONDARY_DB);
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
DatabaseSingleton.getCommunityDatabase().updateSecondaryDb();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void aVoid) {
|
|
||||||
setResult(DebugActivity.this.getString(R.string.debug_update_result,
|
|
||||||
DatabaseSingleton.getCommunityDatabase().getEffectiveDbVersion()));
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getNumber() {
|
private String getNumber() {
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package dummydomain.yetanothercallblocker;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
import org.greenrobot.eventbus.SubscriberExceptionEvent;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class EventHandler {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(EventHandler.class);
|
||||||
|
|
||||||
|
private static EventHandler instance;
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
public static EventHandler create(Context context) {
|
||||||
|
EventHandler instance = new EventHandler(context);
|
||||||
|
|
||||||
|
EventBus.getDefault().register(instance);
|
||||||
|
|
||||||
|
return EventHandler.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventHandler(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onSubscriberExceptionEvent(SubscriberExceptionEvent event) {
|
||||||
|
LOG.warn("onSubscriberExceptionEvent()", event.throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,18 +16,27 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import dummydomain.yetanothercallblocker.event.MainDbDownloadFinishedEvent;
|
||||||
|
import dummydomain.yetanothercallblocker.event.MainDbDownloadingEvent;
|
||||||
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
||||||
import dummydomain.yetanothercallblocker.sia.model.NumberInfo;
|
import dummydomain.yetanothercallblocker.sia.model.NumberInfo;
|
||||||
import dummydomain.yetanothercallblocker.sia.model.database.DbManager;
|
import dummydomain.yetanothercallblocker.work.TaskService;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private CallLogItemRecyclerViewAdapter callLogAdapter;
|
private CallLogItemRecyclerViewAdapter callLogAdapter;
|
||||||
private List<CallLogItem> callLogItems = new ArrayList<>();
|
private List<CallLogItem> callLogItems = new ArrayList<>();
|
||||||
|
|
||||||
|
private AsyncTask<Void, Void, Boolean> checkMainDbTask;
|
||||||
|
private AsyncTask<Void, Void, List<CallLogItem>> loadCallLogTask;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -53,22 +62,6 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (isChecked) Updater.scheduleAutoUpdateWorker();
|
if (isChecked) Updater.scheduleAutoUpdateWorker();
|
||||||
else Updater.cancelAutoUpdateWorker();
|
else Updater.cancelAutoUpdateWorker();
|
||||||
});
|
});
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
AsyncTask<Void, Void, Boolean> noDbTask = new AsyncTask<Void, Void, Boolean>() {
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... voids) {
|
|
||||||
return DatabaseSingleton.getCommunityDatabase().isOperational();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean result) {
|
|
||||||
updateNoDbUi(result ? UpdateUiState.HIDDEN : UpdateUiState.NO_DB);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
noDbTask.execute();
|
|
||||||
|
|
||||||
PermissionHelper.checkPermissions(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -91,29 +84,74 @@ public class MainActivity extends AppCompatActivity {
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
|
EventBus.getDefault().register(this);
|
||||||
|
|
||||||
|
startCheckMainDbTask();
|
||||||
|
|
||||||
|
PermissionHelper.checkPermissions(this);
|
||||||
|
|
||||||
loadCallLog();
|
loadCallLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDownloadDbClick(View view) {
|
@Override
|
||||||
// TODO: use service
|
protected void onStop() {
|
||||||
|
EventBus.getDefault().unregister(this);
|
||||||
|
|
||||||
updateNoDbUi(UpdateUiState.DOWNLOADING_DB);
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
cancelCheckMainDbTask();
|
||||||
|
cancelLoadingCallLogTask();
|
||||||
|
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
|
||||||
|
public void onMainDbDownloadFinished(MainDbDownloadFinishedEvent event) {
|
||||||
|
loadCallLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCheckMainDbTask() {
|
||||||
|
cancelCheckMainDbTask();
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
AsyncTask<Void, Void, Boolean> dlTask = new AsyncTask<Void, Void, Boolean>() {
|
AsyncTask<Void, Void, Boolean> checkMainDbTask = this.checkMainDbTask
|
||||||
|
= new AsyncTask<Void, Void, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... voids) {
|
protected Boolean doInBackground(Void... voids) {
|
||||||
return DbManager.downloadMainDb()
|
return DatabaseSingleton.getCommunityDatabase().isOperational();
|
||||||
&& DatabaseSingleton.getCommunityDatabase().reload()
|
|
||||||
&& DatabaseSingleton.getFeaturedDatabase().reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean result) {
|
protected void onPostExecute(Boolean result) {
|
||||||
updateNoDbUi(result ? UpdateUiState.HIDDEN : UpdateUiState.ERROR);
|
if (!result && EventBus.getDefault().getStickyEvent(MainDbDownloadingEvent.class) == null) {
|
||||||
|
showNoMainDbDialog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dlTask.execute();
|
checkMainDbTask.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelCheckMainDbTask() {
|
||||||
|
if (checkMainDbTask != null) {
|
||||||
|
checkMainDbTask.cancel(true);
|
||||||
|
checkMainDbTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showNoMainDbDialog() {
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.no_main_db_title)
|
||||||
|
.setMessage(R.string.no_main_db_text)
|
||||||
|
.setPositiveButton(R.string.download_main_db,
|
||||||
|
(d, w) -> downloadMainDb())
|
||||||
|
.setNegativeButton(R.string.no, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void downloadMainDb() {
|
||||||
|
TaskService.start(this, TaskService.TASK_DOWNLOAD_MAIN_DB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onOpenDebugActivity(MenuItem item) {
|
public void onOpenDebugActivity(MenuItem item) {
|
||||||
|
@ -147,24 +185,16 @@ public class MainActivity extends AppCompatActivity {
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UpdateUiState {HIDDEN, NO_DB, DOWNLOADING_DB, ERROR}
|
|
||||||
|
|
||||||
private void updateNoDbUi(UpdateUiState state) {
|
|
||||||
findViewById(R.id.noDbText).setVisibility(state == UpdateUiState.NO_DB ? View.VISIBLE : View.GONE);
|
|
||||||
findViewById(R.id.downloadDbButton).setVisibility(state == UpdateUiState.NO_DB ? View.VISIBLE : View.GONE);
|
|
||||||
|
|
||||||
findViewById(R.id.downloadingDbText).setVisibility(state == UpdateUiState.DOWNLOADING_DB ? View.VISIBLE : View.GONE);
|
|
||||||
|
|
||||||
findViewById(R.id.dbCouldNotBeDownloaded).setVisibility(state == UpdateUiState.ERROR ? View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadCallLog() {
|
private void loadCallLog() {
|
||||||
if (!PermissionHelper.havePermission(this, Manifest.permission.READ_CALL_LOG)) {
|
if (!PermissionHelper.havePermission(this, Manifest.permission.READ_CALL_LOG)) {
|
||||||
setCallLogVisibility(false);
|
setCallLogVisibility(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new AsyncTask<Void, Void, List<CallLogItem>>() {
|
cancelLoadingCallLogTask();
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
AsyncTask<Void, Void, List<CallLogItem>> loadCallLogTask = this.loadCallLogTask
|
||||||
|
= new AsyncTask<Void, Void, List<CallLogItem>>() {
|
||||||
@Override
|
@Override
|
||||||
protected List<CallLogItem> doInBackground(Void... voids) {
|
protected List<CallLogItem> doInBackground(Void... voids) {
|
||||||
List<CallLogItem> items = CallLogHelper.getRecentCalls(MainActivity.this, 10);
|
List<CallLogItem> items = CallLogHelper.getRecentCalls(MainActivity.this, 10);
|
||||||
|
@ -186,7 +216,15 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
setCallLogVisibility(true);
|
setCallLogVisibility(true);
|
||||||
}
|
}
|
||||||
}.execute();
|
};
|
||||||
|
loadCallLogTask.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelLoadingCallLogTask() {
|
||||||
|
if (loadCallLogTask != null) {
|
||||||
|
loadCallLogTask.cancel(true);
|
||||||
|
loadCallLogTask = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCallLogVisibility(boolean visible) {
|
private void setCallLogVisibility(boolean visible) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
import androidx.annotation.ColorInt;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
@ -26,15 +27,19 @@ public class NotificationHelper {
|
||||||
private static final String NOTIFICATION_TAG_BLOCKED_CALL = "blockedCallNotification";
|
private static final String NOTIFICATION_TAG_BLOCKED_CALL = "blockedCallNotification";
|
||||||
private static final int NOTIFICATION_ID_INCOMING_CALL = 1;
|
private static final int NOTIFICATION_ID_INCOMING_CALL = 1;
|
||||||
private static final int NOTIFICATION_ID_BLOCKED_CALL = 2;
|
private static final int NOTIFICATION_ID_BLOCKED_CALL = 2;
|
||||||
|
public static final int NOTIFICATION_ID_TASKS = 3;
|
||||||
|
|
||||||
private static final String CHANNEL_GROUP_ID_INCOMING_CALLS = "incoming_calls";
|
private static final String CHANNEL_GROUP_ID_INCOMING_CALLS = "incoming_calls";
|
||||||
private static final String CHANNEL_GROUP_ID_BLOCKED_CALLS = "blocked_calls";
|
private static final String CHANNEL_GROUP_ID_BLOCKED_CALLS = "blocked_calls";
|
||||||
|
private static final String CHANNEL_GROUP_ID_TASKS = "tasks";
|
||||||
|
|
||||||
private static final String CHANNEL_ID_POSITIVE_KNOWN = "positive_known_calls";
|
private static final String CHANNEL_ID_POSITIVE_KNOWN = "positive_known_calls";
|
||||||
private static final String CHANNEL_ID_POSITIVE = "positive_calls";
|
private static final String CHANNEL_ID_POSITIVE = "positive_calls";
|
||||||
private static final String CHANNEL_ID_NEUTRAL = "neutral_calls";
|
private static final String CHANNEL_ID_NEUTRAL = "neutral_calls";
|
||||||
private static final String CHANNEL_ID_UNKNOWN = "unknown_calls";
|
private static final String CHANNEL_ID_UNKNOWN = "unknown_calls";
|
||||||
private static final String CHANNEL_ID_NEGATIVE = "negative_calls";
|
private static final String CHANNEL_ID_NEGATIVE = "negative_calls";
|
||||||
private static final String CHANNEL_ID_BLOCKED_INFO = "blocked_info";
|
private static final String CHANNEL_ID_BLOCKED_INFO = "blocked_info";
|
||||||
|
public static final String CHANNEL_ID_TASKS = "tasks";
|
||||||
|
|
||||||
public static void showIncomingCallNotification(Context context, NumberInfo numberInfo) {
|
public static void showIncomingCallNotification(Context context, NumberInfo numberInfo) {
|
||||||
Notification notification = createIncomingCallNotification(context, numberInfo);
|
Notification notification = createIncomingCallNotification(context, numberInfo);
|
||||||
|
@ -171,6 +176,11 @@ public class NotificationHelper {
|
||||||
context.getString(R.string.notification_channel_group_name_blocked_calls));
|
context.getString(R.string.notification_channel_group_name_blocked_calls));
|
||||||
notificationManager.createNotificationChannelGroup(channelGroupBlocked);
|
notificationManager.createNotificationChannelGroup(channelGroupBlocked);
|
||||||
|
|
||||||
|
NotificationChannelGroup channelGroupTasks = new NotificationChannelGroup(
|
||||||
|
CHANNEL_GROUP_ID_TASKS,
|
||||||
|
context.getString(R.string.notification_channel_group_name_tasks));
|
||||||
|
notificationManager.createNotificationChannelGroup(channelGroupTasks);
|
||||||
|
|
||||||
List<NotificationChannel> channels = new ArrayList<>();
|
List<NotificationChannel> channels = new ArrayList<>();
|
||||||
|
|
||||||
NotificationChannel channel;
|
NotificationChannel channel;
|
||||||
|
@ -217,6 +227,13 @@ public class NotificationHelper {
|
||||||
channel.setGroup(channelGroupBlocked.getId());
|
channel.setGroup(channelGroupBlocked.getId());
|
||||||
channels.add(channel);
|
channels.add(channel);
|
||||||
|
|
||||||
|
channel = new NotificationChannel(
|
||||||
|
CHANNEL_ID_TASKS, context.getString(R.string.notification_channel_name_tasks),
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
);
|
||||||
|
channel.setGroup(channelGroupTasks.getId());
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
notificationManager.createNotificationChannels(channels);
|
notificationManager.createNotificationChannels(channels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
package dummydomain.yetanothercallblocker;
|
package dummydomain.yetanothercallblocker;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -22,7 +24,8 @@ public class ReviewsActivity extends AppCompatActivity {
|
||||||
private static final String PARAM_NUMBER = "param_number";
|
private static final String PARAM_NUMBER = "param_number";
|
||||||
|
|
||||||
private CustomListViewAdapter listViewAdapter;
|
private CustomListViewAdapter listViewAdapter;
|
||||||
private RecyclerView reviewsList;
|
|
||||||
|
private AsyncTask<Void, Void, List<CommunityReview>> loadReviewsTask;
|
||||||
|
|
||||||
public static Intent getNumberIntent(Context context, String number) {
|
public static Intent getNumberIntent(Context context, String number) {
|
||||||
Intent intent = new Intent(context, ReviewsActivity.class);
|
Intent intent = new Intent(context, ReviewsActivity.class);
|
||||||
|
@ -47,12 +50,14 @@ public class ReviewsActivity extends AppCompatActivity {
|
||||||
setText(getString(R.string.reviews_loading));
|
setText(getString(R.string.reviews_loading));
|
||||||
|
|
||||||
listViewAdapter = new CustomListViewAdapter();
|
listViewAdapter = new CustomListViewAdapter();
|
||||||
reviewsList = findViewById(R.id.reviews_list);
|
RecyclerView reviewsList = findViewById(R.id.reviews_list);
|
||||||
reviewsList.setLayoutManager(new LinearLayoutManager(this));
|
reviewsList.setLayoutManager(new LinearLayoutManager(this));
|
||||||
reviewsList.setAdapter(listViewAdapter);
|
reviewsList.setAdapter(listViewAdapter);
|
||||||
reviewsList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
|
reviewsList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
|
||||||
|
|
||||||
new AsyncTask<Void, Void, List<CommunityReview>>() {
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
AsyncTask<Void, Void, List<CommunityReview>> asyncTask = loadReviewsTask
|
||||||
|
= new AsyncTask<Void, Void, List<CommunityReview>>() {
|
||||||
@Override
|
@Override
|
||||||
protected List<CommunityReview> doInBackground(Void... voids) {
|
protected List<CommunityReview> doInBackground(Void... voids) {
|
||||||
return CommunityReviewsLoader.loadReviews(paramNumber);
|
return CommunityReviewsLoader.loadReviews(paramNumber);
|
||||||
|
@ -63,7 +68,22 @@ public class ReviewsActivity extends AppCompatActivity {
|
||||||
setText("");
|
setText("");
|
||||||
handleReviews(reviews);
|
handleReviews(reviews);
|
||||||
}
|
}
|
||||||
}.execute();
|
};
|
||||||
|
asyncTask.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
cancelReviewsLoadingTask();
|
||||||
|
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelReviewsLoadingTask() {
|
||||||
|
if (loadReviewsTask != null) {
|
||||||
|
loadReviewsTask.cancel(true);
|
||||||
|
loadReviewsTask = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setText(String text) {
|
private void setText(String text) {
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
package dummydomain.yetanothercallblocker;
|
package dummydomain.yetanothercallblocker;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.work.Worker;
|
||||||
|
import androidx.work.WorkerParameters;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import androidx.work.Worker;
|
import dummydomain.yetanothercallblocker.event.SecondaryDbUpdateFinished;
|
||||||
import androidx.work.WorkerParameters;
|
import dummydomain.yetanothercallblocker.event.SecondaryDbUpdatingEvent;
|
||||||
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
||||||
|
|
||||||
public class UpdateWorker extends Worker {
|
public class UpdateWorker extends Worker {
|
||||||
|
@ -23,7 +27,18 @@ public class UpdateWorker extends Worker {
|
||||||
public Result doWork() {
|
public Result doWork() {
|
||||||
LOG.info("doWork() started");
|
LOG.info("doWork() started");
|
||||||
|
|
||||||
DatabaseSingleton.getCommunityDatabase().updateSecondaryDb();
|
EventBus bus = EventBus.getDefault();
|
||||||
|
|
||||||
|
SecondaryDbUpdatingEvent sticky = new SecondaryDbUpdatingEvent();
|
||||||
|
|
||||||
|
bus.postSticky(sticky);
|
||||||
|
try {
|
||||||
|
DatabaseSingleton.getCommunityDatabase().updateSecondaryDb();
|
||||||
|
} finally {
|
||||||
|
bus.removeStickyEvent(sticky);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.post(new SecondaryDbUpdateFinished());
|
||||||
|
|
||||||
LOG.info("doWork() finished");
|
LOG.info("doWork() finished");
|
||||||
return Result.success();
|
return Result.success();
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package dummydomain.yetanothercallblocker.event;
|
||||||
|
|
||||||
|
public class MainDbDownloadFinishedEvent {}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package dummydomain.yetanothercallblocker.event;
|
||||||
|
|
||||||
|
public class MainDbDownloadingEvent {}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package dummydomain.yetanothercallblocker.event;
|
||||||
|
|
||||||
|
public class SecondaryDbUpdateFinished {}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package dummydomain.yetanothercallblocker.event;
|
||||||
|
|
||||||
|
public class SecondaryDbUpdatingEvent {}
|
|
@ -33,9 +33,20 @@ public class DbManager {
|
||||||
|
|
||||||
if (DbDownloader.download(url, FileUtils.getDataDirPath() + tmpUpdateDir)) {
|
if (DbDownloader.download(url, FileUtils.getDataDirPath() + tmpUpdateDir)) {
|
||||||
LOG.debug("downloadMainDb() downloaded and unpacked");
|
LOG.debug("downloadMainDb() downloaded and unpacked");
|
||||||
new File(dataDir, siaDir).renameTo(new File(dataDir, oldDir));
|
|
||||||
new File(dataDir, tmpUpdateDir).renameTo(new File(dataDir, siaDir));
|
File old = new File(dataDir, siaDir);
|
||||||
|
if (old.exists() && !old.renameTo(new File(dataDir, oldDir))) {
|
||||||
|
LOG.warn("downloadMainDb() couldn't rename sia to old");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new File(dataDir, tmpUpdateDir).renameTo(new File(dataDir, siaDir))) {
|
||||||
|
LOG.warn("downloadMainDb() couldn't rename tmp to sia");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
FileUtils.delete(dataDir, oldDir);
|
FileUtils.delete(dataDir, oldDir);
|
||||||
|
|
||||||
LOG.debug("downloadMainDb() folders moved");
|
LOG.debug("downloadMainDb() folders moved");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
package dummydomain.yetanothercallblocker.work;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Process;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import dummydomain.yetanothercallblocker.NotificationHelper;
|
||||||
|
import dummydomain.yetanothercallblocker.R;
|
||||||
|
import dummydomain.yetanothercallblocker.event.MainDbDownloadFinishedEvent;
|
||||||
|
import dummydomain.yetanothercallblocker.event.MainDbDownloadingEvent;
|
||||||
|
import dummydomain.yetanothercallblocker.event.SecondaryDbUpdateFinished;
|
||||||
|
import dummydomain.yetanothercallblocker.event.SecondaryDbUpdatingEvent;
|
||||||
|
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
||||||
|
import dummydomain.yetanothercallblocker.sia.model.database.DbManager;
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TaskService.class);
|
||||||
|
|
||||||
|
public static void start(Context context, String task) {
|
||||||
|
Intent intent = new Intent(context, TaskService.class);
|
||||||
|
intent.setAction(task);
|
||||||
|
ContextCompat.startForegroundService(context, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskService() {
|
||||||
|
super(TaskService.class.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(@Nullable Intent intent) {
|
||||||
|
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
|
||||||
|
String action = intent != null ? intent.getAction() : null;
|
||||||
|
|
||||||
|
startForeground(NotificationHelper.NOTIFICATION_ID_TASKS, createNotification(null));
|
||||||
|
try {
|
||||||
|
if (!TextUtils.isEmpty(action)) {
|
||||||
|
switch (action) {
|
||||||
|
case TASK_DOWNLOAD_MAIN_DB:
|
||||||
|
updateNotification(getString(R.string.main_db_downloading));
|
||||||
|
downloadMainDb();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TASK_UPDATE_SECONDARY_DB:
|
||||||
|
updateNotification(getString(R.string.secondary_db_updating));
|
||||||
|
updateSecondaryDb();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG.warn("Unknown action: " + action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
stopForeground(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Notification createNotification(String title) {
|
||||||
|
if (title == null) title = getString(R.string.notification_background_operation);
|
||||||
|
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(
|
||||||
|
getApplicationContext(), NotificationHelper.CHANNEL_ID_TASKS)
|
||||||
|
.setSmallIcon(R.drawable.ic_file_download_black_24dp);
|
||||||
|
|
||||||
|
builder.setContentTitle(title);
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateNotification(String title) {
|
||||||
|
NotificationManagerCompat notificationManager = NotificationManagerCompat
|
||||||
|
.from(getApplicationContext());
|
||||||
|
|
||||||
|
notificationManager.notify(NotificationHelper.NOTIFICATION_ID_TASKS,
|
||||||
|
createNotification(title));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadMainDb() {
|
||||||
|
MainDbDownloadingEvent sticky = new MainDbDownloadingEvent();
|
||||||
|
|
||||||
|
postSticky(sticky);
|
||||||
|
try {
|
||||||
|
DbManager.downloadMainDb();
|
||||||
|
DatabaseSingleton.getCommunityDatabase().reload();
|
||||||
|
DatabaseSingleton.getFeaturedDatabase().reload();
|
||||||
|
} finally {
|
||||||
|
removeSticky(sticky);
|
||||||
|
}
|
||||||
|
|
||||||
|
post(new MainDbDownloadFinishedEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSecondaryDb() {
|
||||||
|
SecondaryDbUpdatingEvent sticky = new SecondaryDbUpdatingEvent();
|
||||||
|
|
||||||
|
postSticky(sticky);
|
||||||
|
try {
|
||||||
|
DatabaseSingleton.getCommunityDatabase().updateSecondaryDb();
|
||||||
|
} finally {
|
||||||
|
removeSticky(sticky);
|
||||||
|
}
|
||||||
|
|
||||||
|
post(new SecondaryDbUpdateFinished());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void post(Object event) {
|
||||||
|
bus().post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postSticky(Object event) {
|
||||||
|
bus().postSticky(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeSticky(Object event) {
|
||||||
|
bus().removeStickyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventBus bus() {
|
||||||
|
return EventBus.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z" />
|
||||||
|
</vector>
|
|
@ -26,54 +26,6 @@
|
||||||
android:paddingRight="@dimen/item_padding"
|
android:paddingRight="@dimen/item_padding"
|
||||||
android:showDividers="middle">
|
android:showDividers="middle">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/noDbText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginStart="@dimen/text_margin"
|
|
||||||
android:layout_marginLeft="@dimen/text_margin"
|
|
||||||
android:paddingTop="@dimen/item_padding"
|
|
||||||
android:text="@string/no_main_db"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
android:textColor="@color/rateNegative"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatButton
|
|
||||||
android:id="@+id/downloadDbButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/text_margin"
|
|
||||||
android:layout_marginBottom="@dimen/text_margin"
|
|
||||||
android:onClick="onDownloadDbClick"
|
|
||||||
android:text="@string/download_main_db"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/downloadingDbText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginStart="@dimen/text_margin"
|
|
||||||
android:layout_marginLeft="@dimen/text_margin"
|
|
||||||
android:paddingTop="@dimen/item_padding"
|
|
||||||
android:text="@string/downloading_db"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/dbCouldNotBeDownloaded"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:layout_marginStart="@dimen/text_margin"
|
|
||||||
android:layout_marginLeft="@dimen/text_margin"
|
|
||||||
android:paddingTop="@dimen/item_padding"
|
|
||||||
android:text="@string/db_could_not_be_downloaded"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
android:textColor="@color/rateNegative"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.SwitchCompat
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
android:id="@+id/notificationsEnabledSwitch"
|
android:id="@+id/notificationsEnabledSwitch"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
<string name="notification_channel_group_name_incoming_calls">Incoming calls</string>
|
<string name="notification_channel_group_name_incoming_calls">Incoming calls</string>
|
||||||
<string name="notification_channel_group_name_blocked_calls">Blocked calls</string>
|
<string name="notification_channel_group_name_blocked_calls">Blocked calls</string>
|
||||||
|
<string name="notification_channel_group_name_tasks">Tasks</string>
|
||||||
|
|
||||||
<string name="notification_channel_name_positive_known">Known positive calls</string>
|
<string name="notification_channel_name_positive_known">Known positive calls</string>
|
||||||
<string name="notification_channel_name_positive">Positive calls</string>
|
<string name="notification_channel_name_positive">Positive calls</string>
|
||||||
|
@ -10,6 +11,7 @@
|
||||||
<string name="notification_channel_name_unknown">Unknown calls</string>
|
<string name="notification_channel_name_unknown">Unknown calls</string>
|
||||||
<string name="notification_channel_name_negative">Negative calls</string>
|
<string name="notification_channel_name_negative">Negative calls</string>
|
||||||
<string name="notification_channel_name_blocked_info">Blocked info</string>
|
<string name="notification_channel_name_blocked_info">Blocked info</string>
|
||||||
|
<string name="notification_channel_name_tasks">Tasks</string>
|
||||||
|
|
||||||
<string name="notification_incoming_call_positive">Positive call</string>
|
<string name="notification_incoming_call_positive">Positive call</string>
|
||||||
<string name="notification_incoming_call_neutral">Neutral call</string>
|
<string name="notification_incoming_call_neutral">Neutral call</string>
|
||||||
|
@ -20,6 +22,8 @@
|
||||||
|
|
||||||
<string name="notification_incoming_call_text_description">Negative: %d, positive: %d, neutral: %d</string>
|
<string name="notification_incoming_call_text_description">Negative: %d, positive: %d, neutral: %d</string>
|
||||||
|
|
||||||
|
<string name="notification_background_operation">Performing background operation…</string>
|
||||||
|
|
||||||
<string name="sia_category_none">None</string>
|
<string name="sia_category_none">None</string>
|
||||||
<string name="sia_category_telemarketer">Telemarketer</string>
|
<string name="sia_category_telemarketer">Telemarketer</string>
|
||||||
<string name="sia_category_dept_collector">Debt collector</string>
|
<string name="sia_category_dept_collector">Debt collector</string>
|
||||||
|
@ -47,18 +51,22 @@
|
||||||
<string name="reviews_loading">Loading reviews…</string>
|
<string name="reviews_loading">Loading reviews…</string>
|
||||||
|
|
||||||
<string name="general_settings">General settings</string>
|
<string name="general_settings">General settings</string>
|
||||||
<string name="no_main_db">Database is not present! For the app to function offline you need to download DB. Press the button below to do it.</string>
|
|
||||||
<string name="downloading_db">Downloading DB…</string>
|
<string name="no_main_db_title">Download main database</string>
|
||||||
<string name="db_could_not_be_downloaded">Database couldn\'t be downloaded</string>
|
<string name="no_main_db_text">Database is not present! For the app to perform most of its functions you need to download DB. It will take around 25 MB of traffic.</string>
|
||||||
|
<string name="download_main_db">Download database</string>
|
||||||
|
<string name="main_db_downloading">Downloading DB…</string>
|
||||||
|
|
||||||
|
<string name="secondary_db_updating">Updating DB…</string>
|
||||||
|
|
||||||
<string name="recent_calls">Recent calls</string>
|
<string name="recent_calls">Recent calls</string>
|
||||||
<string name="online_reviews">Online reviews</string>
|
<string name="online_reviews">Online reviews</string>
|
||||||
<string name="back">Back</string>
|
<string name="back">Back</string>
|
||||||
|
<string name="no">No</string>
|
||||||
|
|
||||||
<string name="incoming_call_notifications_enabled">Incoming call notifications enabled</string>
|
<string name="incoming_call_notifications_enabled">Incoming call notifications enabled</string>
|
||||||
<string name="block_calls">Block unwanted calls</string>
|
<string name="block_calls">Block unwanted calls</string>
|
||||||
<string name="auto_update_enabled">Auto-update enabled</string>
|
<string name="auto_update_enabled">Auto-update enabled</string>
|
||||||
<string name="download_main_db">Download database</string>
|
|
||||||
|
|
||||||
<string name="open_debug_activity">Open debug screen</string>
|
<string name="open_debug_activity">Open debug screen</string>
|
||||||
<string name="debug_activity_label">Debug</string>
|
<string name="debug_activity_label">Debug</string>
|
||||||
|
|
Loading…
Reference in New Issue