From ce2ba629bd91897f74e2d1dee38f90671b0f28f8 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Mon, 30 Apr 2018 23:38:29 +0200 Subject: very much unoptimized search functionality --- .../pixart/messenger/services/AvatarService.java | 10 +- .../messenger/services/MessageSearchTask.java | 128 +++++++++++++++++++++ .../messenger/services/NotificationService.java | 37 +++--- .../messenger/services/XmppConnectionService.java | 26 ++++- 4 files changed, 177 insertions(+), 24 deletions(-) create mode 100644 src/main/java/de/pixart/messenger/services/MessageSearchTask.java (limited to 'src/main/java/de/pixart/messenger/services') diff --git a/src/main/java/de/pixart/messenger/services/AvatarService.java b/src/main/java/de/pixart/messenger/services/AvatarService.java index 81afa9342..d734d6f39 100644 --- a/src/main/java/de/pixart/messenger/services/AvatarService.java +++ b/src/main/java/de/pixart/messenger/services/AvatarService.java @@ -28,6 +28,7 @@ import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Bookmark; import de.pixart.messenger.entities.Contact; import de.pixart.messenger.entities.Conversation; +import de.pixart.messenger.entities.Conversational; import de.pixart.messenger.entities.ListItem; import de.pixart.messenger.entities.Message; import de.pixart.messenger.entities.MucOptions; @@ -400,20 +401,21 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { } public Bitmap get(Message message, int size, boolean cachedOnly) { - final Conversation conversation = message.getConversation(); + final Conversational conversation = message.getConversation(); if (message.getType() == Message.TYPE_STATUS && message.getCounterparts() != null && message.getCounterparts().size() > 1) { return get(message.getCounterparts(), size, cachedOnly); } else if (message.getStatus() == Message.STATUS_RECEIVED) { Contact c = message.getContact(); if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) { return get(c, size, cachedOnly); - } else if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + } else if (conversation instanceof Conversation && message.getConversation().getMode() == Conversation.MODE_MULTI) { final Jid trueCounterpart = message.getTrueCounterpart(); + final MucOptions mucOptions = ((Conversation) conversation).getMucOptions(); MucOptions.User user; if (trueCounterpart != null) { - user = conversation.getMucOptions().findUserByRealJid(trueCounterpart); + user = mucOptions.findUserByRealJid(trueCounterpart); } else { - user = conversation.getMucOptions().findUserByFullJid(message.getCounterpart()); + user = mucOptions.findUserByFullJid(message.getCounterpart()); } if (user != null) { return getImpl(user, size, cachedOnly); diff --git a/src/main/java/de/pixart/messenger/services/MessageSearchTask.java b/src/main/java/de/pixart/messenger/services/MessageSearchTask.java new file mode 100644 index 000000000..4911eff75 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/MessageSearchTask.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018, Daniel Gultsch All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package de.pixart.messenger.services; + +import android.database.Cursor; +import android.os.SystemClock; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import de.pixart.messenger.Config; +import de.pixart.messenger.entities.Account; +import de.pixart.messenger.entities.Conversation; +import de.pixart.messenger.entities.Conversational; +import de.pixart.messenger.entities.IndividualMessage; +import de.pixart.messenger.entities.Message; +import de.pixart.messenger.entities.StubConversation; +import de.pixart.messenger.ui.interfaces.OnSearchResultsAvailable; +import de.pixart.messenger.utils.Cancellable; +import de.pixart.messenger.utils.ReplacingSerialSingleThreadExecutor; +import rocks.xmpp.addr.Jid; + +public class MessageSearchTask implements Runnable, Cancellable { + + private static final ReplacingSerialSingleThreadExecutor EXECUTOR = new ReplacingSerialSingleThreadExecutor(MessageSearchTask.class.getName()); + + private final XmppConnectionService xmppConnectionService; + private final String term; + private final OnSearchResultsAvailable onSearchResultsAvailable; + + private boolean isCancelled = false; + + private MessageSearchTask(XmppConnectionService xmppConnectionService, String term, OnSearchResultsAvailable onSearchResultsAvailable) { + this.xmppConnectionService = xmppConnectionService; + this.term = term; + this.onSearchResultsAvailable = onSearchResultsAvailable; + } + + public static void search(XmppConnectionService xmppConnectionService, String term, OnSearchResultsAvailable onSearchResultsAvailable) { + new MessageSearchTask(xmppConnectionService, term, onSearchResultsAvailable).executeInBackground(); + } + + @Override + public void cancel() { + this.isCancelled = true; + } + + @Override + public void run() { + long startTimestamp = SystemClock.elapsedRealtime(); + Cursor cursor = null; + try { + final HashMap conversationCache = new HashMap<>(); + final List result = new ArrayList<>(); + cursor = xmppConnectionService.databaseBackend.getMessageSearchCursor(term); + while (cursor.moveToNext()) { + final String conversationUuid = cursor.getString(cursor.getColumnIndex(Message.CONVERSATION)); + Conversational conversation; + if (conversationCache.containsKey(conversationUuid)) { + conversation = conversationCache.get(conversationUuid); + } else { + String accountUuid = cursor.getString(cursor.getColumnIndex(Conversation.ACCOUNT)); + String contactJid = cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)); + int mode = cursor.getInt(cursor.getColumnIndex(Conversation.MODE)); + conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode); + conversationCache.put(conversationUuid, conversation); + } + Message message = IndividualMessage.fromCursor(cursor, conversation); + result.add(message); + } + long stopTimestamp = SystemClock.elapsedRealtime(); + Log.d(Config.LOGTAG, "found " + result.size() + " messages in " + (stopTimestamp - startTimestamp) + "ms"); + onSearchResultsAvailable.onSearchResultsAvailable(term, result); + } catch (Exception e) { + Log.d(Config.LOGTAG, "exception while searching ", e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + private Conversational findOrGenerateStub(String conversationUuid, String accountUuid, String contactJid, int mode) throws Exception { + Conversation conversation = xmppConnectionService.findConversationByUuid(conversationUuid); + if (conversation != null) { + return conversation; + } + Account account = xmppConnectionService.findAccountByUuid(accountUuid); + Jid jid = Jid.of(contactJid); + if (account != null && jid != null) { + return new StubConversation(account, conversationUuid, jid.asBareJid(), mode); + } + throw new Exception("Unable to generate stub for " + contactJid); + } + + private void executeInBackground() { + EXECUTOR.execute(this); + } +} \ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/services/NotificationService.java b/src/main/java/de/pixart/messenger/services/NotificationService.java index a823c8307..fe167b904 100644 --- a/src/main/java/de/pixart/messenger/services/NotificationService.java +++ b/src/main/java/de/pixart/messenger/services/NotificationService.java @@ -42,6 +42,7 @@ import de.pixart.messenger.R; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.Contact; import de.pixart.messenger.entities.Conversation; +import de.pixart.messenger.entities.Conversational; import de.pixart.messenger.entities.Message; import de.pixart.messenger.persistance.FileBackend; import de.pixart.messenger.ui.ConversationsActivity; @@ -78,11 +79,12 @@ public class NotificationService { } public boolean notify(final Message message) { + final Conversation conversation = (Conversation) message.getConversation(); return message.getStatus() == Message.STATUS_RECEIVED && notificationsEnabled() - && !message.getConversation().isMuted() - && (message.getConversation().alwaysNotify() || wasHighlightedOrPrivate(message)) - && (!message.getConversation().isWithStranger() || notificationsFromStrangers() + && !conversation.isMuted() + && (conversation.alwaysNotify() || wasHighlightedOrPrivate(message)) + && (!conversation.isWithStranger() || notificationsFromStrangers() ); } @@ -113,7 +115,7 @@ public class NotificationService { public void pushFromBacklog(final Message message) { if (notify(message)) { synchronized (notifications) { - getBacklogMessageCounter(message.getConversation()).incrementAndGet(); + getBacklogMessageCounter((Conversation) message.getConversation()).incrementAndGet(); pushToStack(message); } } @@ -244,7 +246,7 @@ public class NotificationService { if (messages != null && messages.size() > 0) { Message last = messages.get(messages.size() - 1); if (last.getStatus() != Message.STATUS_RECEIVED) { - if (mXmppConnectionService.markRead(last.getConversation(), false)) { + if (mXmppConnectionService.markRead((Conversation) last.getConversation(), false)) { mXmppConnectionService.updateConversationUi(); } } @@ -341,7 +343,7 @@ public class NotificationService { Conversation conversation = null; for (final ArrayList messages : notifications.values()) { if (messages.size() > 0) { - conversation = messages.get(0).getConversation(); + conversation = (Conversation) messages.get(0).getConversation(); final String name = conversation.getName().toString(); SpannableString styledString; if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) { @@ -380,7 +382,7 @@ public class NotificationService { private Builder buildSingleConversations(final ArrayList messages) { final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); if (messages.size() >= 1) { - final Conversation conversation = messages.get(0).getConversation(); + final Conversation conversation = (Conversation) messages.get(0).getConversation(); final UnreadConversation.Builder mUnreadBuilder = new UnreadConversation.Builder(conversation.getName().toString()); mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService() .get(conversation, getPixel(64))); @@ -514,7 +516,7 @@ public class NotificationService { private void modifyForTextOnly(final Builder builder, final UnreadConversation.Builder uBuilder, final ArrayList messages) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(mXmppConnectionService.getString(R.string.me)); - Conversation conversation = messages.get(0).getConversation(); + final Conversation conversation = (Conversation) messages.get(0).getConversation(); if (conversation.getMode() == Conversation.MODE_MULTI) { messagingStyle.setConversationTitle(conversation.getName()); } @@ -636,7 +638,7 @@ public class NotificationService { return (actionId * NOTIFICATION_ID_MULTIPLIER) + (uuid.hashCode() % NOTIFICATION_ID_MULTIPLIER); } - private int generateRequestCode(Conversation conversation, int actionId) { + private int generateRequestCode(Conversational conversation, int actionId) { return generateRequestCode(conversation.getUuid(), actionId); } @@ -644,7 +646,7 @@ public class NotificationService { return createContentIntent(message.getConversationUuid(), message.getUuid()); } - private PendingIntent createContentIntent(final Conversation conversation) { + private PendingIntent createContentIntent(final Conversational conversation) { return createContentIntent(conversation.getUuid(), null); } @@ -696,13 +698,18 @@ public class NotificationService { } private boolean wasHighlightedOrPrivate(final Message message) { - final String nick = message.getConversation().getMucOptions().getActualNick(); - final Pattern highlight = generateNickHighlightPattern(nick); - if (message.getBody() == null || nick == null) { + if (message.getConversation() instanceof Conversation) { + Conversation conversation = (Conversation) message.getConversation(); + final String nick = conversation.getMucOptions().getActualNick(); + final Pattern highlight = generateNickHighlightPattern(nick); + if (message.getBody() == null || nick == null) { + return false; + } + final Matcher m = highlight.matcher(message.getBody()); + return (m.find() || message.getType() == Message.TYPE_PRIVATE); + } else { return false; } - final Matcher m = highlight.matcher(message.getBody()); - return (m.find() || message.getType() == Message.TYPE_PRIVATE); } public void setOpenConversation(final Conversation conversation) { diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java index 00baa733a..c2a0378f7 100644 --- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java +++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java @@ -109,6 +109,7 @@ import de.pixart.messenger.persistance.DatabaseBackend; import de.pixart.messenger.persistance.FileBackend; import de.pixart.messenger.ui.SettingsActivity; import de.pixart.messenger.ui.UiCallback; +import de.pixart.messenger.ui.interfaces.OnSearchResultsAvailable; import de.pixart.messenger.utils.ConversationsFileObserver; import de.pixart.messenger.utils.CryptoHelper; import de.pixart.messenger.utils.ExceptionHelper; @@ -559,6 +560,10 @@ public class XmppConnectionService extends Service { return find(getConversations(), account, jid); } + public void search(String term, OnSearchResultsAvailable onSearchResultsAvailable) { + MessageSearchTask.search(this, term, onSearchResultsAvailable); + } + @Override public int onStartCommand(Intent intent, int flags, int startId) { final String action = intent == null ? null : intent.getAction(); @@ -813,7 +818,7 @@ public class XmppConnectionService extends Service { message.setEncryption(Message.ENCRYPTION_DECRYPTED); sendMessage(message); if (dismissAfterReply) { - markRead(message.getConversation(), true); + markRead((Conversation) message.getConversation(), true); } else { mNotificationService.pushFromDirectReply(message); } @@ -1279,7 +1284,7 @@ public class XmppConnectionService extends Service { databaseBackend.updateAccount(account); mNotificationService.updateErrorNotification(); } - final Conversation conversation = message.getConversation(); + final Conversation conversation = (Conversation) message.getConversation(); account.deactivateGracePeriod(); MessagePacket packet = null; final boolean addToConversation = (conversation.getMode() != Conversation.MODE_MULTI @@ -1289,8 +1294,8 @@ public class XmppConnectionService extends Service { message.setStatus(Message.STATUS_WAITING); if (!resend && message.getEncryption() != Message.ENCRYPTION_OTR) { - message.getConversation().endOtrIfNeeded(); - message.getConversation().findUnsentMessagesWithEncryption(Message.ENCRYPTION_OTR, + conversation.endOtrIfNeeded(); + conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_OTR, new Conversation.OnMessageFound() { @Override public void onMessageFound(Message message) { @@ -3592,6 +3597,15 @@ public class XmppConnectionService extends Service { return null; } + public Account findAccountByUuid(final String uuid) { + for (Account account : this.accounts) { + if (account.getUuid().equals(uuid)) { + return account; + } + } + return null; + } + public Conversation findConversationByUuid(String uuid) { for (Conversation conversation : getConversations()) { if (conversation.getUuid().equals(uuid)) { @@ -3885,7 +3899,9 @@ public class XmppConnectionService extends Service { markMessage(msg, Message.STATUS_WAITING); this.resendMessage(msg, false); } - message.getConversation().sort(); + if (message.getConversation() instanceof Conversation) { + ((Conversation) message.getConversation()).sort(); + } updateConversationUi(); } -- cgit v1.2.3