diff --git a/app/src/main/java/es/wolfi/app/passman/autofill/CredentialAutofillService.java b/app/src/main/java/es/wolfi/app/passman/autofill/CredentialAutofillService.java index 811046c06..432a608ed 100644 --- a/app/src/main/java/es/wolfi/app/passman/autofill/CredentialAutofillService.java +++ b/app/src/main/java/es/wolfi/app/passman/autofill/CredentialAutofillService.java @@ -40,6 +40,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import es.wolfi.app.ResponseHandlers.AutofillCredentialSaveResponseHandler; import es.wolfi.app.passman.R; @@ -115,7 +116,7 @@ public void onFillRequest(FillRequest request, CancellationSignal cancellationSi CredentialAutofillService.WebDomainResult domain = getLikelyDomain(structures); // Grab Credentials from vault - ArrayList allCred = v.getCredentials(); + CopyOnWriteArrayList allCred = v.getCredentials(); if (allCred.isEmpty()) { Toast.makeText(getApplicationContext(), getString(R.string.autofill_vaultempty), Toast.LENGTH_SHORT).show(); @@ -397,7 +398,7 @@ private String returnBestString(@NonNull String... usernameOptions) { } private List findMatchingCredentials( - @NonNull ArrayList credentialArrayList, + @NonNull CopyOnWriteArrayList credentialArrayList, @NonNull String packageName, @NonNull CredentialAutofillService.WebDomainResult domain) { ArrayList matchingDomainCred = new ArrayList<>(); diff --git a/app/src/main/java/es/wolfi/app/passman/fragments/CredentialItemFragment.java b/app/src/main/java/es/wolfi/app/passman/fragments/CredentialItemFragment.java index 7ae8ca680..aeb10b919 100644 --- a/app/src/main/java/es/wolfi/app/passman/fragments/CredentialItemFragment.java +++ b/app/src/main/java/es/wolfi/app/passman/fragments/CredentialItemFragment.java @@ -39,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; import es.wolfi.app.passman.R; import es.wolfi.app.passman.SettingValues; @@ -134,7 +135,7 @@ public void applyFilters(Vault vault, EditText searchInput) { filterTask.cancel(true); } filterTask = new FilterListAsyncTask(searchText, recyclerView, mListener); - ArrayList input[] = new ArrayList[]{vault.getCredentials()}; + CopyOnWriteArrayList input[] = new CopyOnWriteArrayList[]{vault.getCredentials()}; filterTask.execute((Object[]) input); } diff --git a/app/src/main/java/es/wolfi/passman/API/Vault.java b/app/src/main/java/es/wolfi/passman/API/Vault.java index ad3dc2009..ebdce0fb7 100644 --- a/app/src/main/java/es/wolfi/passman/API/Vault.java +++ b/app/src/main/java/es/wolfi/passman/API/Vault.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.concurrent.CopyOnWriteArrayList; import es.wolfi.app.passman.SJCLCrypto; import es.wolfi.app.passman.SettingValues; @@ -51,7 +52,7 @@ public class Vault extends Core implements Filterable { public double last_access; public String challenge_password; - ArrayList credentials; + CopyOnWriteArrayList credentials; HashMap credential_guid; private String encryption_key = ""; @@ -162,7 +163,7 @@ public Date getLastAccessTime() { return new Date((long) last_access * 1000); } - public ArrayList getCredentials() { + public CopyOnWriteArrayList getCredentials() { return credentials; } @@ -227,7 +228,7 @@ public static Vault fromJSON(JSONObject o) throws JSONException { if (o.has("credentials")) { JSONArray j = o.getJSONArray("credentials"); - v.credentials = new ArrayList(); + v.credentials = new CopyOnWriteArrayList(); v.credential_guid = new HashMap<>(); for (int i = 0; i < j.length(); i++) { @@ -246,11 +247,16 @@ public static Vault fromJSON(JSONObject o) throws JSONException { } public void sort(int method) { + ArrayList temp = new ArrayList<>(credentials); credential_guid.clear(); - Collections.sort(credentials, new CredentialLabelSort(method)); - for (int i = 0; i < credentials.size(); i++) { - credential_guid.put(credentials.get(i).getGuid(), i); + + Collections.sort(temp, new CredentialLabelSort(method)); + for (int i = 0; i < temp.size(); i++) { + credential_guid.put(temp.get(i).getGuid(), i); } + + credentials.clear(); + credentials.addAll(temp); } public void addCredential(Credential credential) { @@ -271,6 +277,8 @@ public void deleteCredential(Credential updatedCredential) { for (Credential credential : credentials) { if (credential.getGuid().equals(updatedCredential.getGuid())) { credentials.remove(credential); + credential_guid.remove(updatedCredential.getGuid()); + break; } } } diff --git a/app/src/main/java/es/wolfi/utils/FilterListAsyncTask.java b/app/src/main/java/es/wolfi/utils/FilterListAsyncTask.java index 01adf7c99..b6def8329 100644 --- a/app/src/main/java/es/wolfi/utils/FilterListAsyncTask.java +++ b/app/src/main/java/es/wolfi/utils/FilterListAsyncTask.java @@ -1,23 +1,22 @@ /** - * Passman Android App + * Passman Android App * * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com) * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es) * @license GNU AGPL version 3 or any later version - * + *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + *

* You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . - * */ package es.wolfi.utils; @@ -27,31 +26,31 @@ import androidx.recyclerview.widget.RecyclerView; -import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; -import es.wolfi.app.passman.fragments.CredentialItemFragment; import es.wolfi.app.passman.adapters.CredentialViewAdapter; -import es.wolfi.app.passman.fragments.VaultFragment; import es.wolfi.app.passman.adapters.VaultViewAdapter; +import es.wolfi.app.passman.fragments.CredentialItemFragment; +import es.wolfi.app.passman.fragments.VaultFragment; import es.wolfi.passman.API.Credential; import es.wolfi.passman.API.Vault; -public class FilterListAsyncTask extends AsyncTask, Integer, ArrayList>{ +public class FilterListAsyncTask extends AsyncTask, Integer, CopyOnWriteArrayList> { - private String filter; + private final String filter; RecyclerView recyclerView; CredentialItemFragment.OnListFragmentInteractionListener credentialMListener = null; VaultFragment.OnListFragmentInteractionListener vaultMListener = null; Boolean isVaultFragment; - public FilterListAsyncTask(String filter, RecyclerView recyclerView, CredentialItemFragment.OnListFragmentInteractionListener mListener){ + public FilterListAsyncTask(String filter, RecyclerView recyclerView, CredentialItemFragment.OnListFragmentInteractionListener mListener) { this.filter = filter; this.recyclerView = recyclerView; this.credentialMListener = mListener; this.isVaultFragment = false; } - public FilterListAsyncTask(String filter, RecyclerView recyclerView, VaultFragment.OnListFragmentInteractionListener mListener){ + public FilterListAsyncTask(String filter, RecyclerView recyclerView, VaultFragment.OnListFragmentInteractionListener mListener) { this.filter = filter; this.recyclerView = recyclerView; this.vaultMListener = mListener; @@ -59,17 +58,16 @@ public FilterListAsyncTask(String filter, RecyclerView recyclerView, VaultFragme } @Override - protected ArrayList doInBackground(ArrayList... list) { - return new ListUtils().filterList(filter, list[0]); + protected CopyOnWriteArrayList doInBackground(CopyOnWriteArrayList... list) { + return ListUtils.filterList(filter, list[0]); } @Override - protected void onPostExecute(ArrayList filteredList){ - if(isVaultFragment){ - recyclerView.setAdapter(new VaultViewAdapter((ArrayList)filteredList, vaultMListener)); - } - else { - recyclerView.setAdapter(new CredentialViewAdapter((ArrayList) filteredList, credentialMListener, PreferenceManager.getDefaultSharedPreferences(recyclerView.getContext()))); + protected void onPostExecute(CopyOnWriteArrayList filteredList) { + if (isVaultFragment) { + recyclerView.setAdapter(new VaultViewAdapter((CopyOnWriteArrayList) filteredList, vaultMListener)); + } else { + recyclerView.setAdapter(new CredentialViewAdapter((CopyOnWriteArrayList) filteredList, credentialMListener, PreferenceManager.getDefaultSharedPreferences(recyclerView.getContext()))); } } } diff --git a/app/src/main/java/es/wolfi/utils/ListUtils.java b/app/src/main/java/es/wolfi/utils/ListUtils.java index a0d98794e..9f2583754 100644 --- a/app/src/main/java/es/wolfi/utils/ListUtils.java +++ b/app/src/main/java/es/wolfi/utils/ListUtils.java @@ -1,37 +1,34 @@ /** - * Passman Android App + * Passman Android App * * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com) * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es) * @license GNU AGPL version 3 or any later version - * + *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + *

* You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . - * */ package es.wolfi.utils; -import java.util.ArrayList; -import java.util.Iterator; +import java.util.concurrent.CopyOnWriteArrayList; public class ListUtils { - public static ArrayList filterList(String filter, ArrayList list){ - ArrayList copiedList = new ArrayList(list); - Iterator it = copiedList.iterator(); - while (it.hasNext()) { - if (!it.next().getFilterableAttribute().contains(filter)) { - it.remove(); + public static CopyOnWriteArrayList filterList(String filter, CopyOnWriteArrayList list) { + CopyOnWriteArrayList copiedList = new CopyOnWriteArrayList(); + for (T item : list) { + if (item.getFilterableAttribute().contains(filter)) { + copiedList.add(item); } } return copiedList;