From 88ceffeee2e30a93dd88afb89e0ef0b0f5ad51cd Mon Sep 17 00:00:00 2001 From: alansley Date: Wed, 17 Jan 2024 08:47:27 +1100 Subject: [PATCH 01/10] Investigation in progress --- .../thoughtcrime/securesms/components/SearchToolbar.java | 4 ++++ .../conversation/v2/menus/ConversationMenuHelper.kt | 6 ++++++ .../java/org/thoughtcrime/securesms/home/HomeActivity.kt | 3 +++ 3 files changed, 13 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java b/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java index 8a56acd658..e9af37b05d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java @@ -16,6 +16,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; +import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.util.AnimationCompleteListener; import network.loki.messenger.R; @@ -69,6 +70,9 @@ public class SearchToolbar extends LinearLayout { @Override public boolean onQueryTextChange(String newText) { + + Log.d("[ACL]", "IT'S NOT THIS ONE - Search text changed to: " + newText); + return onQueryTextSubmit(newText); } }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 02ee4ae45f..d2459a952d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -29,6 +29,7 @@ import org.session.libsession.utilities.GroupUtil.doubleDecodeGroupID import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.getColorFromAttr import org.session.libsession.utilities.recipients.Recipient +import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.guava.Optional import org.session.libsignal.utilities.toHexString import org.thoughtcrime.securesms.MediaOverviewActivity @@ -124,6 +125,11 @@ object ConversationMenuHelper { } override fun onQueryTextChange(query: String): Boolean { + + // *** Crashes when searching for non-alphanumeric first char *** + Log.d("[ACL]", "THIS ONE - CMH search query changed to: $query") + + context.onSearchQueryUpdated(query) return true } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index f255455727..d0713860f2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -294,6 +294,9 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), val newData = contactResults + messageResults + + Log.d("[ACL]", "THIS IS THE GLOBAL SEARCH - Result query is: ${result.query}") + globalSearchAdapter.setNewData(result.query, newData) } } From cfe2dbca7babb9248929405d469615f17435001e Mon Sep 17 00:00:00 2001 From: alansley Date: Wed, 17 Jan 2024 12:13:27 +1100 Subject: [PATCH 02/10] Working fix push before cleanup --- .../conversation/v2/ConversationActivityV2.kt | 3 ++ .../conversation/v2/ConversationAdapter.kt | 3 ++ .../v2/menus/ConversationMenuHelper.kt | 3 +- .../securesms/database/SearchDatabase.java | 3 ++ .../securesms/search/SearchRepository.java | 46 +++++++++++++++++-- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 8c566c060b..401901607a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -2066,8 +2066,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } fun onSearchQueryUpdated(query: String) { + Log.d("[ACL]", "1") searchViewModel.onQueryUpdated(query, viewModel.threadId) + Log.d("[ACL]", "2") binding?.searchBottomBar?.showLoading() + Log.d("[ACL]", "3") adapter.onSearchQueryUpdated(query) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 6013af5ba4..1ac7419d9a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.launch import network.loki.messenger.R import network.loki.messenger.databinding.ViewVisibleMessageBinding import org.session.libsession.messaging.contacts.Contact +import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate @@ -268,7 +269,9 @@ class ConversationAdapter( } fun onSearchQueryUpdated(query: String?) { + Log.d("[ACL]", "4") this.searchQuery = query + Log.d("[ACL]", "5") notifyDataSetChanged() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index d2459a952d..744dc579a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -127,8 +127,7 @@ object ConversationMenuHelper { override fun onQueryTextChange(query: String): Boolean { // *** Crashes when searching for non-alphanumeric first char *** - Log.d("[ACL]", "THIS ONE - CMH search query changed to: $query") - + Log.d("[ACL]", "[ConversationMenuHelper] Query text changed to: $query") context.onSearchQueryUpdated(query) return true diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java index eac6a5fbc3..92b0bed9a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java @@ -10,6 +10,7 @@ import com.annimon.stream.Stream; import net.zetetic.database.sqlcipher.SQLiteDatabase; import org.session.libsession.utilities.Util; +import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import java.util.List; @@ -118,6 +119,8 @@ public class SearchDatabase extends Database { int queryLimit = Math.min(query.length()*50,500); + Log.d("[ACL]", "[SearchDatabase] Query is:\n" + MESSAGES_QUERY); + Cursor cursor = db.rawQuery(MESSAGES_QUERY, new String[] { prefixQuery, prefixQuery, String.valueOf(queryLimit) }); setNotifyConverationListListeners(cursor); return cursor; diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index ddfe85515c..737322d2cb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -95,6 +95,16 @@ public class SearchRepository { Stopwatch timer = new Stopwatch("FtsQuery"); String cleanQuery = sanitizeQuery(query); + + // If the search is for a single character and it was stripped by `sanitizeQuery` then abort + // the search for an empty string to avoid SQLite error. + if (cleanQuery.length() == 0) + { + Log.d(TAG, "Aborting empty search query."); + timer.stop(TAG); + return; + } + timer.split("clean"); Pair, List> contacts = queryContacts(cleanQuery); @@ -114,15 +124,30 @@ public class SearchRepository { public void query(@NonNull String query, long threadId, @NonNull Callback> callback) { if (TextUtils.isEmpty(query)) { + Log.d("[ACL]", "Recognised empty query!"); + callback.onResult(CursorList.emptyList()); return; } + else { + Log.d("[ACL]", "Non-empty query is: " + query); + } executor.execute(() -> { - long startTime = System.currentTimeMillis(); - CursorList messages = queryMessages(sanitizeQuery(query), threadId); - Log.d(TAG, "[ConversationQuery] " + (System.currentTimeMillis() - startTime) + " ms"); + Log.d("[ACL]", "Hit query.execute!"); + + // If the search is for a single character and it was stripped by `sanitizeQuery` then abort + // the search for an empty string to avoid SQLite error. + String cleanQuery = sanitizeQuery(query); + Log.d("[ACL]", "clean query is: \"" + cleanQuery + "\""); + if (cleanQuery.isEmpty() || cleanQuery.equalsIgnoreCase(" ")) + { + Log.d("[ACL]", "Aborting empty search query."); + return; + } + + CursorList messages = queryMessages(cleanQuery, threadId); callback.onResult(messages); }); } @@ -186,12 +211,19 @@ public class SearchRepository { } private CursorList queryMessages(@NonNull String query) { + + Log.d("[ACL]", "[SearchRepository] Query is:\n" + query); + + Cursor messages = searchDatabase.queryMessages(query); return messages != null ? new CursorList<>(messages, new MessageModelBuilder(context)) : CursorList.emptyList(); } private CursorList queryMessages(@NonNull String query, long threadId) { + + Log.d("[ACL]", "[SearchRepository] 6 - query is: " + query); + Cursor messages = searchDatabase.queryMessages(query, threadId); return messages != null ? new CursorList<>(messages, new MessageModelBuilder(context)) : CursorList.emptyList(); @@ -205,6 +237,9 @@ public class SearchRepository { * However, if we replace the apostrophe with a space, then the query will find the match. */ private String sanitizeQuery(@NonNull String query) { + + Log.d("[ACL]", "[SearchRepository] Hit sanitizeQuery - initial query is: " + query); + StringBuilder out = new StringBuilder(); for (int i = 0; i < query.length(); i++) { @@ -216,7 +251,10 @@ public class SearchRepository { } } - return out.toString(); + Log.d("[ACL]", "[SearchRepository] Hit sanitizeQuery - sanitized query is: " + out.toString()); + + // Querying for an empty string causes a crash so we'll que + if (out.toString().length() > 0) { return out.toString(); } else { return " "; } } private static class ContactModelBuilder implements CursorList.ModelBuilder { From 09e48fdc5cb72d9136524eebfc8a976f9bab9cd0 Mon Sep 17 00:00:00 2001 From: alansley Date: Wed, 17 Jan 2024 12:51:11 +1100 Subject: [PATCH 03/10] Fixes #1346 --- .../securesms/components/SearchToolbar.java | 7 +--- .../conversation/v2/ConversationActivityV2.kt | 3 -- .../conversation/v2/ConversationAdapter.kt | 2 -- .../v2/menus/ConversationMenuHelper.kt | 4 --- .../securesms/database/SearchDatabase.java | 4 --- .../securesms/home/HomeActivity.kt | 4 --- .../securesms/search/SearchRepository.java | 36 +++---------------- 7 files changed, 5 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java b/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java index e9af37b05d..0648f609c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java @@ -69,12 +69,7 @@ public class SearchToolbar extends LinearLayout { } @Override - public boolean onQueryTextChange(String newText) { - - Log.d("[ACL]", "IT'S NOT THIS ONE - Search text changed to: " + newText); - - return onQueryTextSubmit(newText); - } + public boolean onQueryTextChange(String newText) { return onQueryTextSubmit(newText); } }); searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 401901607a..8c566c060b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -2066,11 +2066,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } fun onSearchQueryUpdated(query: String) { - Log.d("[ACL]", "1") searchViewModel.onQueryUpdated(query, viewModel.threadId) - Log.d("[ACL]", "2") binding?.searchBottomBar?.showLoading() - Log.d("[ACL]", "3") adapter.onSearchQueryUpdated(query) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 1ac7419d9a..160388865b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -269,9 +269,7 @@ class ConversationAdapter( } fun onSearchQueryUpdated(query: String?) { - Log.d("[ACL]", "4") this.searchQuery = query - Log.d("[ACL]", "5") notifyDataSetChanged() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 744dc579a6..989bea39be 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -125,10 +125,6 @@ object ConversationMenuHelper { } override fun onQueryTextChange(query: String): Boolean { - - // *** Crashes when searching for non-alphanumeric first char *** - Log.d("[ACL]", "[ConversationMenuHelper] Query text changed to: $query") - context.onSearchQueryUpdated(query) return true } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java index 92b0bed9a0..93c163f632 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java @@ -116,11 +116,7 @@ public class SearchDatabase extends Database { public Cursor queryMessages(@NonNull String query) { SQLiteDatabase db = databaseHelper.getReadableDatabase(); String prefixQuery = adjustQuery(query); - int queryLimit = Math.min(query.length()*50,500); - - Log.d("[ACL]", "[SearchDatabase] Query is:\n" + MESSAGES_QUERY); - Cursor cursor = db.rawQuery(MESSAGES_QUERY, new String[] { prefixQuery, prefixQuery, String.valueOf(queryLimit) }); setNotifyConverationListListeners(cursor); return cursor; diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index d0713860f2..ecb8ee60c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -293,10 +293,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), } val newData = contactResults + messageResults - - - Log.d("[ACL]", "THIS IS THE GLOBAL SEARCH - Result query is: ${result.query}") - globalSearchAdapter.setNewData(result.query, newData) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index 737322d2cb..3641b39c62 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -124,28 +124,15 @@ public class SearchRepository { public void query(@NonNull String query, long threadId, @NonNull Callback> callback) { if (TextUtils.isEmpty(query)) { - Log.d("[ACL]", "Recognised empty query!"); - callback.onResult(CursorList.emptyList()); return; } - else { - Log.d("[ACL]", "Non-empty query is: " + query); - } executor.execute(() -> { - - Log.d("[ACL]", "Hit query.execute!"); - - // If the search is for a single character and it was stripped by `sanitizeQuery` then abort - // the search for an empty string to avoid SQLite error. + // If the sanitized search query is empty or just contains a single space (" ") then abort + // the search to prevent SQLite errors. String cleanQuery = sanitizeQuery(query); - Log.d("[ACL]", "clean query is: \"" + cleanQuery + "\""); - if (cleanQuery.isEmpty() || cleanQuery.equalsIgnoreCase(" ")) - { - Log.d("[ACL]", "Aborting empty search query."); - return; - } + if (cleanQuery.equalsIgnoreCase(" ") || cleanQuery.isEmpty()) { return; } CursorList messages = queryMessages(cleanQuery, threadId); callback.onResult(messages); @@ -211,19 +198,12 @@ public class SearchRepository { } private CursorList queryMessages(@NonNull String query) { - - Log.d("[ACL]", "[SearchRepository] Query is:\n" + query); - - Cursor messages = searchDatabase.queryMessages(query); return messages != null ? new CursorList<>(messages, new MessageModelBuilder(context)) : CursorList.emptyList(); } private CursorList queryMessages(@NonNull String query, long threadId) { - - Log.d("[ACL]", "[SearchRepository] 6 - query is: " + query); - Cursor messages = searchDatabase.queryMessages(query, threadId); return messages != null ? new CursorList<>(messages, new MessageModelBuilder(context)) : CursorList.emptyList(); @@ -237,11 +217,7 @@ public class SearchRepository { * However, if we replace the apostrophe with a space, then the query will find the match. */ private String sanitizeQuery(@NonNull String query) { - - Log.d("[ACL]", "[SearchRepository] Hit sanitizeQuery - initial query is: " + query); - StringBuilder out = new StringBuilder(); - for (int i = 0; i < query.length(); i++) { char c = query.charAt(i); if (!BANNED_CHARACTERS.contains(c)) { @@ -250,11 +226,7 @@ public class SearchRepository { out.append(' '); } } - - Log.d("[ACL]", "[SearchRepository] Hit sanitizeQuery - sanitized query is: " + out.toString()); - - // Querying for an empty string causes a crash so we'll que - if (out.toString().length() > 0) { return out.toString(); } else { return " "; } + return out.toString(); } private static class ContactModelBuilder implements CursorList.ModelBuilder { From 42e58c477bd0f81feb4272105412dce431aa5ed4 Mon Sep 17 00:00:00 2001 From: alansley Date: Wed, 17 Jan 2024 13:00:30 +1100 Subject: [PATCH 04/10] Removed unused logging imports --- .../org/thoughtcrime/securesms/components/SearchToolbar.java | 2 -- .../securesms/conversation/v2/ConversationAdapter.kt | 1 - .../securesms/conversation/v2/menus/ConversationMenuHelper.kt | 1 - .../org/thoughtcrime/securesms/database/SearchDatabase.java | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java b/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java index 0648f609c6..9032b26a2b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/SearchToolbar.java @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.components; - import android.animation.Animator; import android.content.Context; import android.os.Build; @@ -16,7 +15,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; -import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.util.AnimationCompleteListener; import network.loki.messenger.R; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 160388865b..6013af5ba4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -22,7 +22,6 @@ import kotlinx.coroutines.launch import network.loki.messenger.R import network.loki.messenger.databinding.ViewVisibleMessageBinding import org.session.libsession.messaging.contacts.Contact -import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 989bea39be..02ee4ae45f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -29,7 +29,6 @@ import org.session.libsession.utilities.GroupUtil.doubleDecodeGroupID import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.getColorFromAttr import org.session.libsession.utilities.recipients.Recipient -import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.guava.Optional import org.session.libsignal.utilities.toHexString import org.thoughtcrime.securesms.MediaOverviewActivity diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java index 93c163f632..31564668a8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java @@ -10,7 +10,7 @@ import com.annimon.stream.Stream; import net.zetetic.database.sqlcipher.SQLiteDatabase; import org.session.libsession.utilities.Util; -import org.session.libsignal.utilities.Log; + import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import java.util.List; From cab1ffec1e297163c68ac690b818cb0d6f531e8c Mon Sep 17 00:00:00 2001 From: alansley Date: Wed, 17 Jan 2024 13:01:55 +1100 Subject: [PATCH 05/10] Put back some whitespace --- .../org/thoughtcrime/securesms/search/SearchRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index 3641b39c62..cfd620542c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -218,6 +218,7 @@ public class SearchRepository { */ private String sanitizeQuery(@NonNull String query) { StringBuilder out = new StringBuilder(); + for (int i = 0; i < query.length(); i++) { char c = query.charAt(i); if (!BANNED_CHARACTERS.contains(c)) { @@ -226,6 +227,7 @@ public class SearchRepository { out.append(' '); } } + return out.toString(); } From b21cdab0e404152022e86585f6077c7e8890d192 Mon Sep 17 00:00:00 2001 From: alansley Date: Fri, 1 Mar 2024 11:56:33 +1100 Subject: [PATCH 06/10] Minor cleanup --- .../thoughtcrime/securesms/search/SearchRepository.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index cfd620542c..a5669aa351 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -129,11 +129,10 @@ public class SearchRepository { } executor.execute(() -> { - // If the sanitized search query is empty or just contains a single space (" ") then abort - // the search to prevent SQLite errors. - String cleanQuery = sanitizeQuery(query); - if (cleanQuery.equalsIgnoreCase(" ") || cleanQuery.isEmpty()) { return; } - + // If the sanitized search query is empty then abort the search to prevent SQLite errors. + String cleanQuery = sanitizeQuery(query).trim(); + if (cleanQuery.isEmpty()) { return; } + CursorList messages = queryMessages(cleanQuery, threadId); callback.onResult(messages); }); From d65705c845cad9774b2c6d55f4fe0682077ac0a1 Mon Sep 17 00:00:00 2001 From: Al Lansley Date: Thu, 4 Apr 2024 10:15:15 +1100 Subject: [PATCH 07/10] Push before cleanup --- .../home/search/GlobalSearchViewModel.kt | 15 +++++-- .../securesms/search/SearchRepository.java | 40 +++++++++++++------ .../securesms/util/Stopwatch.java | 6 ++- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt index 8908554b03..712e8819d1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.plus +import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.SettableFuture import org.thoughtcrime.securesms.search.SearchRepository import org.thoughtcrime.securesms.search.model.SearchResult @@ -31,6 +32,9 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se private val _queryText: MutableStateFlow = MutableStateFlow("") + private var settableFuture = SettableFuture() + + fun postQuery(charSequence: CharSequence?) { charSequence ?: return _queryText.value = charSequence @@ -41,6 +45,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se _queryText .buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST) .mapLatest { query -> + // Minimum search term is 2 characters - for a single char we do nothing if (query.trim().length < 2) { SearchResult.EMPTY } else { @@ -48,7 +53,13 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se // this coroutine will be cancelled and expensive query will not be run if typing quickly // first query of 2 characters will be instant however delay(300) - val settableFuture = SettableFuture() + + // If we already have a search running then stop it + if (!settableFuture.isDone) { + Log.w("[ACL]", "Cancelling settable future..") + settableFuture.cancel(true); } + + settableFuture = SettableFuture() searchRepository.query(query.toString(), settableFuture::set) try { // search repository doesn't play nicely with suspend functions (yet) @@ -64,6 +75,4 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se } .launchIn(executor) } - - } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index a5669aa351..ba4535e1ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -86,7 +86,15 @@ public class SearchRepository { } public void query(@NonNull String query, @NonNull Callback callback) { - if (TextUtils.isEmpty(query)) { + + Log.w("[ACL]", "Hit SearchRepository.query - query string is: \"" + query + "\""); + + String cleanQuery = sanitizeQuery(query).trim(); + Log.w("[ACL]", "When sanitized and trimmed this is: \"" + cleanQuery + "\""); + + // If the sanitized search is empty or is less than 2 chars then abort + if (cleanQuery.isEmpty() || cleanQuery.length() < 2) { + Log.w("[ACL]", "Trimmed query is empty or less than 2 chars so returning empty SearchResult"); callback.onResult(SearchResult.EMPTY); return; } @@ -94,25 +102,36 @@ public class SearchRepository { executor.execute(() -> { Stopwatch timer = new Stopwatch("FtsQuery"); - String cleanQuery = sanitizeQuery(query); + // ACL + //String cleanQuery = sanitizeQuery(query).trim(); - // If the search is for a single character and it was stripped by `sanitizeQuery` then abort - // the search for an empty string to avoid SQLite error. - if (cleanQuery.length() == 0) + + /* + if (cleanQuery.isEmpty()) { + Log.w("[ACL]", "Aborting empty search query."); Log.d(TAG, "Aborting empty search query."); timer.stop(TAG); return; } + else { + Log.w("[ACL]", "Clean query is non-empty and is: \"" + cleanQuery + "\""); + } + */ + timer.split("clean"); + Log.w("[ACL]", "About to query contacts."); Pair, List> contacts = queryContacts(cleanQuery); timer.split("contacts"); + + Log.w("[ACL]", "About to query conversations."); CursorList conversations = queryConversations(cleanQuery, contacts.getSecond()); timer.split("conversations"); + Log.w("[ACL]", "About to query messages."); CursorList messages = queryMessages(cleanQuery); timer.split("messages"); @@ -123,23 +142,20 @@ public class SearchRepository { } public void query(@NonNull String query, long threadId, @NonNull Callback> callback) { - if (TextUtils.isEmpty(query)) { + // If the sanitized search query is empty or less than 2 chars then abort the search + String cleanQuery = sanitizeQuery(query).trim(); + if (cleanQuery.isEmpty() || cleanQuery.length() < 2) { callback.onResult(CursorList.emptyList()); return; } executor.execute(() -> { - // If the sanitized search query is empty then abort the search to prevent SQLite errors. - String cleanQuery = sanitizeQuery(query).trim(); - if (cleanQuery.isEmpty()) { return; } - CursorList messages = queryMessages(cleanQuery, threadId); callback.onResult(messages); }); } private Pair, List> queryContacts(String query) { - Cursor contacts = contactDatabase.queryContactsByName(query); List
contactList = new ArrayList<>(); List contactStrings = new ArrayList<>(); @@ -189,9 +205,7 @@ public class SearchRepository { membersGroupList.close(); } - Cursor conversations = threadDatabase.getFilteredConversationList(new ArrayList<>(addresses)); - return conversations != null ? new CursorList<>(conversations, new GroupModelBuilder(threadDatabase, groupDatabase)) : CursorList.emptyList(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java b/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java index cac53899fb..75bc760c31 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java @@ -37,13 +37,15 @@ public class Stopwatch { for (int i = 1; i < splits.size(); i++) { out.append(splits.get(i).label).append(": "); out.append(splits.get(i).time - splits.get(i - 1).time); - out.append(" "); + out.append("ms "); } - out.append("total: ").append(splits.get(splits.size() - 1).time - startTime); + out.append("total: ").append(splits.get(splits.size() - 1).time - startTime).append("ms."); } Log.d(tag, out.toString()); + + Log.w("[ACL]", out.toString()); } private static class Split { From 04fb2967871c4d4d74ec5bb51cc29275d1ec105e Mon Sep 17 00:00:00 2001 From: Al Lansley Date: Thu, 4 Apr 2024 11:27:47 +1100 Subject: [PATCH 08/10] Fixes #1346 - properly this time! --- .../securesms/home/HomeActivity.kt | 9 +++ .../home/search/GlobalSearchViewModel.kt | 17 +++-- .../securesms/search/SearchRepository.java | 73 ++++--------------- .../securesms/util/Stopwatch.java | 4 - 4 files changed, 32 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index 917fc13fcf..ebb5a90da2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -12,6 +12,7 @@ import android.os.Build import android.os.Bundle import android.text.SpannableString import android.widget.Toast + import androidx.activity.viewModels import androidx.core.os.bundleOf import androidx.core.view.isVisible @@ -21,20 +22,25 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView + import dagger.hilt.android.AndroidEntryPoint + import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext + import network.loki.messenger.R import network.loki.messenger.databinding.ActivityHomeBinding import network.loki.messenger.databinding.ViewMessageRequestBannerBinding import network.loki.messenger.libsession_util.ConfigBase + import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode + import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.sending_receiving.MessageSender @@ -47,6 +53,7 @@ import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.ThreadUtils import org.session.libsignal.utilities.toHexString + import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.start.NewConversationFragment @@ -82,8 +89,10 @@ import org.thoughtcrime.securesms.util.disableClipping import org.thoughtcrime.securesms.util.push import org.thoughtcrime.securesms.util.show import org.thoughtcrime.securesms.util.themeState + import java.io.IOException import java.util.Locale + import javax.inject.Inject @AndroidEntryPoint diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt index 712e8819d1..4a917fd291 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt @@ -2,7 +2,9 @@ package org.thoughtcrime.securesms.home.search import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope + import dagger.hilt.android.lifecycle.HiltViewModel + import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.delay @@ -13,11 +15,14 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.plus -import org.session.libsignal.utilities.Log + import org.session.libsignal.utilities.SettableFuture + import org.thoughtcrime.securesms.search.SearchRepository import org.thoughtcrime.securesms.search.model.SearchResult + import java.util.concurrent.TimeUnit + import javax.inject.Inject @HiltViewModel @@ -25,8 +30,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se private val executor = viewModelScope + SupervisorJob() - private val _result: MutableStateFlow = - MutableStateFlow(GlobalSearchResult.EMPTY) + private val _result: MutableStateFlow = MutableStateFlow(GlobalSearchResult.EMPTY) val result: StateFlow = _result @@ -34,7 +38,6 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se private var settableFuture = SettableFuture() - fun postQuery(charSequence: CharSequence?) { charSequence ?: return _queryText.value = charSequence @@ -45,7 +48,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se _queryText .buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST) .mapLatest { query -> - // Minimum search term is 2 characters - for a single char we do nothing + // Minimum search term is 2 characters if (query.trim().length < 2) { SearchResult.EMPTY } else { @@ -55,9 +58,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se delay(300) // If we already have a search running then stop it - if (!settableFuture.isDone) { - Log.w("[ACL]", "Cancelling settable future..") - settableFuture.cancel(true); } + if (!settableFuture.isDone) { settableFuture.cancel(true) } settableFuture = SettableFuture() searchRepository.query(query.toString(), settableFuture::set) diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index ba4535e1ac..11ce07d06a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -4,7 +4,6 @@ import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.MergeCursor; -import android.text.TextUtils; import androidx.annotation.NonNull; @@ -36,28 +35,18 @@ import java.util.concurrent.Executor; import kotlin.Pair; -/** - * Manages data retrieval for search. - */ +// Class to manage data retrieval for search public class SearchRepository { - private static final String TAG = SearchRepository.class.getSimpleName(); private static final Set BANNED_CHARACTERS = new HashSet<>(); static { - // Several ranges of invalid ASCII characters - for (int i = 33; i <= 47; i++) { - BANNED_CHARACTERS.add((char) i); - } - for (int i = 58; i <= 64; i++) { - BANNED_CHARACTERS.add((char) i); - } - for (int i = 91; i <= 96; i++) { - BANNED_CHARACTERS.add((char) i); - } - for (int i = 123; i <= 126; i++) { - BANNED_CHARACTERS.add((char) i); - } + // Construct a list containing several ranges of invalid ASCII characters + // See: https://www.ascii-code.com/ + for (int i = 33; i <= 47; i++) { BANNED_CHARACTERS.add((char) i); } // !, ", #, $, %, &, ', (, ), *, +, ,, -, ., / + for (int i = 58; i <= 64; i++) { BANNED_CHARACTERS.add((char) i); } // :, ;, <, =, >, ?, @ + for (int i = 91; i <= 96; i++) { BANNED_CHARACTERS.add((char) i); } // [, \, ], ^, _, ` + for (int i = 123; i <= 126; i++) { BANNED_CHARACTERS.add((char) i); } // {, |, }, ~ } private final Context context; @@ -86,54 +75,25 @@ public class SearchRepository { } public void query(@NonNull String query, @NonNull Callback callback) { - - Log.w("[ACL]", "Hit SearchRepository.query - query string is: \"" + query + "\""); - - String cleanQuery = sanitizeQuery(query).trim(); - Log.w("[ACL]", "When sanitized and trimmed this is: \"" + cleanQuery + "\""); - // If the sanitized search is empty or is less than 2 chars then abort + String cleanQuery = sanitizeQuery(query).trim(); if (cleanQuery.isEmpty() || cleanQuery.length() < 2) { - Log.w("[ACL]", "Trimmed query is empty or less than 2 chars so returning empty SearchResult"); callback.onResult(SearchResult.EMPTY); return; } executor.execute(() -> { Stopwatch timer = new Stopwatch("FtsQuery"); - - // ACL - //String cleanQuery = sanitizeQuery(query).trim(); - - - /* - if (cleanQuery.isEmpty()) - { - Log.w("[ACL]", "Aborting empty search query."); - Log.d(TAG, "Aborting empty search query."); - timer.stop(TAG); - return; - } - else { - Log.w("[ACL]", "Clean query is non-empty and is: \"" + cleanQuery + "\""); - } - */ - - timer.split("clean"); - Log.w("[ACL]", "About to query contacts."); Pair, List> contacts = queryContacts(cleanQuery); - timer.split("contacts"); + timer.split("Contacts"); - - Log.w("[ACL]", "About to query conversations."); CursorList conversations = queryConversations(cleanQuery, contacts.getSecond()); - timer.split("conversations"); + timer.split("Conversations"); - Log.w("[ACL]", "About to query messages."); CursorList messages = queryMessages(cleanQuery); - timer.split("messages"); + timer.split("Messages"); timer.stop(TAG); @@ -182,11 +142,10 @@ public class SearchRepository { MergeCursor merged = new MergeCursor(new Cursor[]{addressThreads, individualRecipients}); return new Pair<>(new CursorList<>(merged, new ContactModelBuilder(contactDatabase, threadDatabase)), contactStrings); - } private CursorList queryConversations(@NonNull String query, List matchingAddresses) { - List numbers = contactAccessor.getNumbersForThreadSearchFilter(context, query); + List numbers = contactAccessor.getNumbersForThreadSearchFilter(context, query); String localUserNumber = TextSecurePreferences.getLocalNumber(context); if (localUserNumber != null) { matchingAddresses.remove(localUserNumber); @@ -270,9 +229,7 @@ public class SearchRepository { private final Context context; - RecipientModelBuilder(@NonNull Context context) { - this.context = context; - } + RecipientModelBuilder(@NonNull Context context) { this.context = context; } @Override public Recipient build(@NonNull Cursor cursor) { @@ -315,9 +272,7 @@ public class SearchRepository { private final Context context; - MessageModelBuilder(@NonNull Context context) { - this.context = context; - } + MessageModelBuilder(@NonNull Context context) { this.context = context; } @Override public MessageResult build(@NonNull Cursor cursor) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java b/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java index 75bc760c31..d92fc7546d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/Stopwatch.java @@ -39,13 +39,9 @@ public class Stopwatch { out.append(splits.get(i).time - splits.get(i - 1).time); out.append("ms "); } - out.append("total: ").append(splits.get(splits.size() - 1).time - startTime).append("ms."); } - Log.d(tag, out.toString()); - - Log.w("[ACL]", out.toString()); } private static class Split { From f6d21534e0e06ba8ac993ce811bb28b788cb380a Mon Sep 17 00:00:00 2001 From: Al Lansley Date: Thu, 4 Apr 2024 13:34:08 +1100 Subject: [PATCH 09/10] Addressed PR feedback --- .../thoughtcrime/securesms/home/HomeActivity.kt | 9 --------- .../home/search/GlobalSearchInputLayout.kt | 4 ++++ .../home/search/GlobalSearchViewModel.kt | 16 +++++----------- .../securesms/search/SearchRepository.java | 13 ++++--------- 4 files changed, 13 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index 5be0d275df..ccfa16beef 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -12,7 +12,6 @@ import android.os.Build import android.os.Bundle import android.text.SpannableString import android.widget.Toast - import androidx.activity.viewModels import androidx.core.os.bundleOf import androidx.core.view.isVisible @@ -22,25 +21,20 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView - import dagger.hilt.android.AndroidEntryPoint - import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext - import network.loki.messenger.R import network.loki.messenger.databinding.ActivityHomeBinding import network.loki.messenger.databinding.ViewMessageRequestBannerBinding import network.loki.messenger.libsession_util.ConfigBase - import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode - import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.sending_receiving.MessageSender @@ -53,7 +47,6 @@ import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.ThreadUtils import org.session.libsignal.utilities.toHexString - import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.start.NewConversationFragment @@ -89,10 +82,8 @@ import org.thoughtcrime.securesms.util.disableClipping import org.thoughtcrime.securesms.util.push import org.thoughtcrime.securesms.util.show import org.thoughtcrime.securesms.util.themeState - import java.io.IOException import java.util.Locale - import javax.inject.Inject @AndroidEntryPoint diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt index 1537769cdc..c70979f852 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt @@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.home.search import android.content.Context import android.text.Editable +import android.text.InputFilter +import android.text.InputFilter.LengthFilter import android.text.TextWatcher import android.util.AttributeSet import android.view.KeyEvent @@ -15,6 +17,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import network.loki.messenger.databinding.ViewGlobalSearchInputBinding + class GlobalSearchInputLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : LinearLayout(context, attrs), @@ -34,6 +37,7 @@ class GlobalSearchInputLayout @JvmOverloads constructor( binding.searchInput.onFocusChangeListener = this binding.searchInput.addTextChangedListener(this) binding.searchInput.setOnEditorActionListener(this) + binding.searchInput.setFilters( arrayOf(LengthFilter(100)) ) // 100 char search limit binding.searchCancel.setOnClickListener(this) binding.searchClear.setOnClickListener(this) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt index 4a917fd291..4232754c4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt @@ -36,8 +36,6 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se private val _queryText: MutableStateFlow = MutableStateFlow("") - private var settableFuture = SettableFuture() - fun postQuery(charSequence: CharSequence?) { charSequence ?: return _queryText.value = charSequence @@ -48,19 +46,15 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se _queryText .buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST) .mapLatest { query -> - // Minimum search term is 2 characters - if (query.trim().length < 2) { + // Early exit on empty search query + if (query.trim().isEmpty()) { SearchResult.EMPTY } else { - // user input delay here in case we get a new query within a few hundred ms - // this coroutine will be cancelled and expensive query will not be run if typing quickly - // first query of 2 characters will be instant however + // User input delay in case we get a new query within a few hundred ms this + // coroutine will be cancelled and expensive query will not be run delay(300) - // If we already have a search running then stop it - if (!settableFuture.isDone) { settableFuture.cancel(true) } - - settableFuture = SettableFuture() + val settableFuture = SettableFuture() searchRepository.query(query.toString(), settableFuture::set) try { // search repository doesn't play nicely with suspend functions (yet) diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index d2c51ad10f..f2adbf2349 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -4,11 +4,8 @@ import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.MergeCursor; - import androidx.annotation.NonNull; - import com.annimon.stream.Stream; - import org.session.libsession.messaging.contacts.Contact; import org.session.libsession.utilities.Address; import org.session.libsession.utilities.GroupRecord; @@ -26,13 +23,11 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.search.model.MessageResult; import org.thoughtcrime.securesms.search.model.SearchResult; import org.thoughtcrime.securesms.util.Stopwatch; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; - import kotlin.Pair; // Class to manage data retrieval for search @@ -75,9 +70,9 @@ public class SearchRepository { } public void query(@NonNull String query, @NonNull Callback callback) { - // If the sanitized search is empty or is less than 2 chars then abort without search + // If the sanitized search is empty then abort without search String cleanQuery = sanitizeQuery(query).trim(); - if (cleanQuery.isEmpty() || cleanQuery.length() < 2) { + if (cleanQuery.isEmpty()) { callback.onResult(SearchResult.EMPTY); return; } @@ -102,9 +97,9 @@ public class SearchRepository { } public void query(@NonNull String query, long threadId, @NonNull Callback> callback) { - // If the sanitized search query is empty or less than 2 chars then abort the search + // If the sanitized search query is empty then abort the search String cleanQuery = sanitizeQuery(query).trim(); - if (cleanQuery.isEmpty() || cleanQuery.length() < 2) { + if (cleanQuery.isEmpty()) { callback.onResult(CursorList.emptyList()); return; } From 0146a2975f7c85eb37aeed64fc8ead2a6b41f3ce Mon Sep 17 00:00:00 2001 From: Al Lansley Date: Thu, 4 Apr 2024 13:36:14 +1100 Subject: [PATCH 10/10] Cleanup --- .../securesms/home/search/GlobalSearchInputLayout.kt | 1 - .../securesms/home/search/GlobalSearchViewModel.kt | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt index c70979f852..c22ccde1f1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchInputLayout.kt @@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import network.loki.messenger.databinding.ViewGlobalSearchInputBinding - class GlobalSearchInputLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null ) : LinearLayout(context, attrs), diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt index 4232754c4e..1ff0a395fe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchViewModel.kt @@ -2,9 +2,7 @@ package org.thoughtcrime.securesms.home.search import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope - import dagger.hilt.android.lifecycle.HiltViewModel - import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.delay @@ -15,14 +13,10 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.plus - import org.session.libsignal.utilities.SettableFuture - import org.thoughtcrime.securesms.search.SearchRepository import org.thoughtcrime.securesms.search.model.SearchResult - import java.util.concurrent.TimeUnit - import javax.inject.Inject @HiltViewModel @@ -51,7 +45,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se SearchResult.EMPTY } else { // User input delay in case we get a new query within a few hundred ms this - // coroutine will be cancelled and expensive query will not be run + // coroutine will be cancelled and the expensive query will not be run. delay(300) val settableFuture = SettableFuture()