diff --git a/README.md b/README.md index 23cee37..5180ccf 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,11 @@ Overview --- -This is a free application that allows you to configure the blocking of unwanted calls and SMS +This is a fork of free application that allows you to configure the blocking of unwanted calls and SMS in convenient way. It does not contain ads, supports light and dark interface themes and is -supported by devices with Android 2.3 and up. +supported by devices with Android 2.3 and up. As original Blacklist is not maintained anymore, I'll take care of it's fork. +Forked version will introduce online sources syncing, and online repositories for blocking and sharing public blacklists +using CardDAV servers, or even gists. I've also added contacts group support. Features --- @@ -69,8 +71,17 @@ separately. You can adjust the level of visual and audio information about the e You can set the light or dark theme of the application interface. Here, you can also export and import application data, for example, to transfer them from one device to another. -### License: - +### Fork License: + Copyright (C) 2019 Dmitrij Rysanow + Licensed under the Apache License, Version 2.0 (the "License"); you may not + use this file except in compliance with the License. You may obtain a copy of + the License at http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and limitations under + the License. +### Original License: Copyright (C) 2017 Anton Kaliturin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b2b2d8d..5b588d6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,9 @@ android:versionCode="18" android:versionName="1.2.12"> + diff --git a/app/src/main/java/com/kaliturin/blacklist/fragments/AddContactsFragment.java b/app/src/main/java/com/kaliturin/blacklist/fragments/AddContactsFragment.java index da126f2..abdb912 100644 --- a/app/src/main/java/com/kaliturin/blacklist/fragments/AddContactsFragment.java +++ b/app/src/main/java/com/kaliturin/blacklist/fragments/AddContactsFragment.java @@ -31,6 +31,7 @@ import android.support.v4.util.LongSparseArray; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.SearchView; +import android.util.Pair; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -53,6 +54,7 @@ import com.kaliturin.blacklist.utils.ProgressDialogHolder; import com.kaliturin.blacklist.utils.Utils; +import java.util.HashMap; import java.util.List; /** @@ -60,13 +62,20 @@ * which one is adding to the black/white list */ public class AddContactsFragment extends Fragment implements FragmentArguments { + private static final HashMap ACCOUNT_TYPES = new HashMap() {{ + put("com.google", "Google"); + put("at.bitfire.davdroid.address_book", "DAVDroid"); + put("com.deependhulla.opensync.address_book", "Open Sync"); + }}; private ContactsCursorAdapter cursorAdapter = null; private ButtonsBar snackBar = null; private ContactSourceType sourceType = null; private int contactType = 0; private boolean singleNumberMode = false; private LongSparseArray singleContactNumbers = new LongSparseArray<>(); - + private String accountType = null; + private String accountName = null; + private String itemsFilter = null; public AddContactsFragment() { // Required empty public constructor } @@ -157,7 +166,7 @@ public void onClick(View row) { listView.setEmptyView(textEmptyView); // init and run the loader of contacts - getLoaderManager().initLoader(0, null, newLoaderCallbacks(null)); + getLoaderManager().initLoader(0, null, newLoaderCallbacks(null, null, null)); } @Override @@ -173,6 +182,19 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { Utils.setMenuIconTint(getContext(), itemSearch, R.attr.colorAccent); itemSearch.setVisible(true); + MenuItem findByAccount = menu.findItem(R.id.action_filter_group); + Utils.setMenuIconTint(getContext(), findByAccount, R.attr.colorAccent); + findByAccount.setVisible(true); + findByAccount.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + if (menuItem.getTitle() == getResources().getString(R.string.Filter_by_group)) { + showAccountsFilterDialog(); + return true; + } + return false; + } + }); // get the view from search menu item SearchView searchView = (SearchView) MenuItemCompat.getActionView(itemSearch); searchView.setQueryHint(getString(R.string.Search_action)); @@ -185,7 +207,8 @@ public boolean onQueryTextSubmit(String query) { @Override public boolean onQueryTextChange(String newText) { - reloadItems(newText); + itemsFilter = newText; + reloadItems(); return true; } }); @@ -201,7 +224,7 @@ public boolean onMenuItemActionExpand(MenuItem item) { @Override public boolean onMenuItemActionCollapse(MenuItem item) { - reloadItems(null); + reloadItems(); return true; } }); @@ -209,6 +232,38 @@ public boolean onMenuItemActionCollapse(MenuItem item) { super.onCreateOptionsMenu(menu, inflater); } + private void showAccountsFilterDialog() { + ContactsAccessHelper dao = ContactsAccessHelper.getInstance(getContext()); + + final List> accounts = dao.getAccounts(); + + DialogBuilder dialog = new DialogBuilder(getContext()); + dialog.setTitle(R.string.Filter_by_group); + dialog.addItem(R.string.All, new View.OnClickListener() { + @Override + public void onClick(View view) { + applyAccountFilter(null, null); + } + }); + for (final Pair pair: accounts) { + String name = ACCOUNT_TYPES.get(pair.first); + dialog.addItem(name + " " + pair.second, new View.OnClickListener() { + @Override + public void onClick(View view) { + applyAccountFilter(pair.first, pair.second); + } + }); + } + dialog.show(); + } + + private void applyAccountFilter(String accountType, String accountName) { + // assign accountType and accountName + this.accountType = accountType; + this.accountName = accountName; + // refresh the list + reloadItems(); + } //------------------------------------------------------------------- // Opens menu dialog with list of contact's numbers to choose @@ -260,38 +315,42 @@ public boolean dismissSnackBar() { } // Reloads items - private void reloadItems(String itemsFilter) { + private void reloadItems() { singleContactNumbers.clear(); dismissSnackBar(); if (isAdded()) { - getLoaderManager().restartLoader(0, null, newLoaderCallbacks(itemsFilter)); + getLoaderManager().restartLoader(0, null, newLoaderCallbacks(itemsFilter, accountType, accountName)); } } // Creates new contacts loader - private ContactsLoaderCallbacks newLoaderCallbacks(String itemsFilter) { - return new ContactsLoaderCallbacks(getContext(), sourceType, cursorAdapter, itemsFilter); + private ContactsLoaderCallbacks newLoaderCallbacks(String itemsFilter, String accountType, String accountName) { + return new ContactsLoaderCallbacks(getContext(), sourceType, cursorAdapter, itemsFilter, accountType, accountName); } -//------------------------------------------------------------------- // Contact items loader private static class ContactsLoader extends CursorLoader { private ContactSourceType sourceType; private String itemsFilter; - + private String accountType; + private String accountName; ContactsLoader(Context context, ContactSourceType sourceType, - String itemsFilter) { + String itemsFilter, + String accountType, + String accountName) { super(context); this.sourceType = sourceType; this.itemsFilter = itemsFilter; + this.accountType = accountType; + this.accountName = accountName; } @Override public Cursor loadInBackground() { ContactsAccessHelper dao = ContactsAccessHelper.getInstance(getContext()); - return dao.getContacts(getContext(), sourceType, itemsFilter); + return dao.getContacts(getContext(), sourceType, itemsFilter, accountType, accountName); } } @@ -302,21 +361,29 @@ private static class ContactsLoaderCallbacks implements LoaderManager.LoaderCall private ContactSourceType sourceType; private ContactsCursorAdapter cursorAdapter; private String itemsFilter; + private String accountType; + private String accountName; ContactsLoaderCallbacks(Context context, ContactSourceType sourceType, ContactsCursorAdapter cursorAdapter, - String itemsFilter) { + String itemsFilter, + String accountType, + String accountName) { this.context = context; this.sourceType = sourceType; this.cursorAdapter = cursorAdapter; this.itemsFilter = itemsFilter; + this.accountType = accountType; + this.accountName = accountName; } @Override public Loader onCreateLoader(int id, Bundle args) { progress.show(context, 0, R.string.Loading_); - return new ContactsLoader(context, sourceType, itemsFilter); + //TODO: investigate how to assign group to filter + int groupId = 0; + return new ContactsLoader(context, sourceType, itemsFilter, accountType, accountName); } @Override diff --git a/app/src/main/java/com/kaliturin/blacklist/utils/ContactsAccessHelper.java b/app/src/main/java/com/kaliturin/blacklist/utils/ContactsAccessHelper.java index 5f38e58..d20a724 100644 --- a/app/src/main/java/com/kaliturin/blacklist/utils/ContactsAccessHelper.java +++ b/app/src/main/java/com/kaliturin/blacklist/utils/ContactsAccessHelper.java @@ -16,10 +16,14 @@ package com.kaliturin.blacklist.utils; +import android.accounts.Account; +import android.accounts.AccountManager; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.SyncAdapterType; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; import android.database.MatrixCursor; @@ -31,11 +35,15 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import android.util.Pair; import com.kaliturin.blacklist.utils.DatabaseAccessHelper.Contact; import com.kaliturin.blacklist.utils.DatabaseAccessHelper.ContactNumber; import com.kaliturin.blacklist.utils.DatabaseAccessHelper.ContactSource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -48,11 +56,24 @@ */ public class ContactsAccessHelper { private static final String TAG = ContactsAccessHelper.class.getName(); + + private static final String SYNC_AUTHORITY = "com.android.contacts"; + List okSyncs = new ArrayList<>(); + SyncAdapterType[] syncTypes = ContentResolver.getSyncAdapterTypes(); + AccountManager accountManager; + Account[] tempAccounts; + List allAccounts = new ArrayList<>(); private static volatile ContactsAccessHelper sInstance = null; - private ContentResolver contentResolver = null; + private ContentResolver contentResolver; + private Context context; + private List> foundAccounts = new ArrayList<>(); private ContactsAccessHelper(Context context) { contentResolver = context.getApplicationContext().getContentResolver(); + // TODO: try to get accounts here + this.context = context; + this.getAccountsFromSystem(); + } public static ContactsAccessHelper getInstance(Context context) { @@ -66,6 +87,44 @@ public static ContactsAccessHelper getInstance(Context context) { return sInstance; } + private void getAccountsFromSystem() { + if (this.syncTypes.length > 0) { + for (int i = 0; i < syncTypes.length; i++) { + if (this.syncTypes[i].authority.equals(SYNC_AUTHORITY)) { + okSyncs.add(syncTypes[i]); + } + } + } + if (okSyncs.size() > 0) { + accountManager = AccountManager.get(this.context); + for (int i = 0; i < okSyncs.size(); i++) { + tempAccounts = accountManager.getAccountsByType(okSyncs.get(i).accountType); + if (tempAccounts.length > 0) { + for (int j = 0; j < tempAccounts.length; j++) { + allAccounts.add(tempAccounts[j]); + } + } + } + } + if (allAccounts.size() > 0) { + for (int i = 0; i < allAccounts.size(); i++) { + Log.d(TAG, "Adding account " + allAccounts.get(i).name + " of type " + allAccounts.get(i).type); + // I didn't found better way to determine synced accounts without messengers (like Signal or Telegram) + if (allAccounts.get(i).type.equals("com.google")) { + this.foundAccounts.add(new Pair<>(allAccounts.get(i).type, allAccounts.get(i).name)); + } else if (allAccounts.get(i).type.equals("at.bitfire.davdroid.address_book")) { + this.foundAccounts.add(new Pair<>(allAccounts.get(i).type, allAccounts.get(i).name)); + } else if (allAccounts.get(i).type.equals("com.deependhulla.opensync.address_book")) { + this.foundAccounts.add(new Pair<>(allAccounts.get(i).type, allAccounts.get(i).name)); + } + } + } + } + + public List> getAccounts() { + return foundAccounts; + } + private boolean validate(Cursor cursor) { if (cursor == null || cursor.isClosed()) return false; if (cursor.getCount() == 0) { @@ -102,7 +161,7 @@ public static String getPermission(ContactSourceType sourceType) { // Returns contacts from specified source @Nullable - public Cursor getContacts(Context context, ContactSourceType sourceType, @Nullable String filter) { + public Cursor getContacts(Context context, ContactSourceType sourceType, @Nullable String filter, @Nullable String accountType, @Nullable String accountName) { // check permission final String permission = getPermission(sourceType); if (permission == null || !Permissions.isGranted(context, permission)) { @@ -111,7 +170,7 @@ public Cursor getContacts(Context context, ContactSourceType sourceType, @Nullab // return contacts switch (sourceType) { case FROM_CONTACTS: - return getContacts(filter); + return getContacts(filter, accountName, accountType); case FROM_CALLS_LOG: return getContactsFromCallsLog(filter); case FROM_SMS_LIST: @@ -134,10 +193,18 @@ public Cursor getContacts(Context context, ContactSourceType sourceType, @Nullab // Selects contacts from contacts list @Nullable - private ContactCursorWrapper getContacts(@Nullable String filter) { + private ContactCursorWrapper getContacts(@Nullable String filter, @Nullable String accountName, @Nullable String accountType) { filter = (filter == null ? "%%" : "%" + filter + "%"); + final Uri.Builder builder = Contacts.CONTENT_URI.buildUpon(); + if (accountName != null) { + builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName); + } + if (accountType != null) { + builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType); + } + Uri uri = builder.build(); Cursor cursor = contentResolver.query( - Contacts.CONTENT_URI, + uri, new String[]{Contacts._ID, Contacts.DISPLAY_NAME}, Contacts.IN_VISIBLE_GROUP + " != 0 AND " + Contacts.HAS_PHONE_NUMBER + " != 0 AND " + @@ -149,6 +216,7 @@ private ContactCursorWrapper getContacts(@Nullable String filter) { return (validate(cursor) ? new ContactCursorWrapper(cursor) : null); } + // Selects contact from contacts list by id @Nullable private ContactCursorWrapper getContactCursor(long contactId) { diff --git a/app/src/main/res/drawable/ic_group.xml b/app/src/main/res/drawable/ic_group.xml new file mode 100644 index 0000000..38a7e0a --- /dev/null +++ b/app/src/main/res/drawable/ic_group.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml index 01d535d..8a8e858 100644 --- a/app/src/main/res/menu/main.xml +++ b/app/src/main/res/menu/main.xml @@ -1,6 +1,12 @@ + begint met: eindigt op: + Selecteer het adresboek + Filtrer efter gruppe + Alle diff --git a/app/src/main/res/values-nl/strings.xml.rej b/app/src/main/res/values-nl/strings.xml.rej new file mode 100644 index 0000000..b9e0649 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml.rej @@ -0,0 +1,10 @@ +diff a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml (rejected hunks) +@@ -242,8 +242,5 @@ + begint met: + eindigt op: + +- Selecteer het adresboek +- Filtrer efter gruppe +- Alle + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 8925d90..8ffb62a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -249,5 +249,8 @@ начинается на: заканчивается на: + Выберите адресную книгу + Фильтровать по группе + Все diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 4d6eafd..9e42385 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -56,7 +56,7 @@ Från vitlista Manuellt Kontaktlista - Samtalslista/string> + Samtalslista SMS-lista Svartlista Vitlista @@ -245,5 +245,8 @@ börjar med: slutar med: + Välj adressbok + Filtrera per grupp + Allt diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8a73899..b0669af 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,6 +49,7 @@ SMS blocking SMS blocking notification SMS receiving notification + Select address book From the Contact list From the Call log From the SMS list @@ -82,6 +83,8 @@ message is received Private number Search + Filter by group + All Starts with: Ends with: Contains: