Search in sources :

Example 91 with Conversation

use of eu.siacs.conversations.entities.Conversation in project Conversations by siacs.

the class ConversationFragment method findAndReInitByUuidOrArchive.

private boolean findAndReInitByUuidOrArchive(@NonNull final String uuid) {
    Conversation conversation = activity.xmppConnectionService.findConversationByUuid(uuid);
    if (conversation == null) {
        clearPending();
        activity.onConversationArchived(null);
        return false;
    }
    reInit(conversation);
    ScrollState scrollState = pendingScrollState.pop();
    String lastMessageUuid = pendingLastMessageUuid.pop();
    List<Attachment> attachments = pendingMediaPreviews.pop();
    if (scrollState != null) {
        setScrollPosition(scrollState, lastMessageUuid);
    }
    if (attachments != null && attachments.size() > 0) {
        Log.d(Config.LOGTAG, "had attachments on restore");
        mediaPreviewAdapter.addMediaPreviews(attachments);
        toggleInputMethod();
    }
    return true;
}
Also used : ScrollState(eu.siacs.conversations.ui.util.ScrollState) Conversation(eu.siacs.conversations.entities.Conversation) Attachment(eu.siacs.conversations.ui.util.Attachment)

Example 92 with Conversation

use of eu.siacs.conversations.entities.Conversation in project Conversations by siacs.

the class XmppConnectionService method findOrCreateConversation.

public Conversation findOrCreateConversation(final Account account, final Jid jid, final boolean muc, final boolean joinAfterCreate, final MessageArchiveService.Query query, final boolean async) {
    synchronized (this.conversations) {
        Conversation conversation = find(account, jid);
        if (conversation != null) {
            return conversation;
        }
        conversation = databaseBackend.findConversation(account, jid);
        final boolean loadMessagesFromDb;
        if (conversation != null) {
            conversation.setStatus(Conversation.STATUS_AVAILABLE);
            conversation.setAccount(account);
            if (muc) {
                conversation.setMode(Conversation.MODE_MULTI);
                conversation.setContactJid(jid);
            } else {
                conversation.setMode(Conversation.MODE_SINGLE);
                conversation.setContactJid(jid.asBareJid());
            }
            databaseBackend.updateConversation(conversation);
            loadMessagesFromDb = conversation.messagesLoaded.compareAndSet(true, false);
        } else {
            String conversationName;
            Contact contact = account.getRoster().getContact(jid);
            if (contact != null) {
                conversationName = contact.getDisplayName();
            } else {
                conversationName = jid.getLocal();
            }
            if (muc) {
                conversation = new Conversation(conversationName, account, jid, Conversation.MODE_MULTI);
            } else {
                conversation = new Conversation(conversationName, account, jid.asBareJid(), Conversation.MODE_SINGLE);
            }
            this.databaseBackend.createConversation(conversation);
            loadMessagesFromDb = false;
        }
        final Conversation c = conversation;
        final Runnable runnable = () -> {
            if (loadMessagesFromDb) {
                c.addAll(0, databaseBackend.getMessages(c, Config.PAGE_SIZE));
                updateConversationUi();
                c.messagesLoaded.set(true);
            }
            if (account.getXmppConnection() != null && !c.getContact().isBlocked() && account.getXmppConnection().getFeatures().mam() && !muc) {
                if (query == null) {
                    mMessageArchiveService.query(c);
                } else {
                    if (query.getConversation() == null) {
                        mMessageArchiveService.query(c, query.getStart(), query.isCatchup());
                    }
                }
            }
            if (joinAfterCreate) {
                joinMuc(c);
            }
        };
        if (async) {
            mDatabaseReaderExecutor.execute(runnable);
        } else {
            runnable.run();
        }
        this.conversations.add(conversation);
        updateConversationUi();
        return conversation;
    }
}
Also used : Conversation(eu.siacs.conversations.entities.Conversation) Contact(eu.siacs.conversations.entities.Contact) JabberIdContact(eu.siacs.conversations.android.JabberIdContact)

Example 93 with Conversation

use of eu.siacs.conversations.entities.Conversation in project Conversations by siacs.

the class XmppConnectionService method onStartCommand.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    final String action = intent == null ? null : intent.getAction();
    final boolean needsForegroundService = intent != null && intent.getBooleanExtra(EventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE, false);
    if (needsForegroundService) {
        Log.d(Config.LOGTAG, "toggle forced foreground service after receiving event (action=" + action + ")");
        toggleForegroundService(true);
    }
    String pushedAccountHash = null;
    boolean interactive = false;
    if (action != null) {
        final String uuid = intent.getStringExtra("uuid");
        switch(action) {
            case QuickConversationsService.SMS_RETRIEVED_ACTION:
                mQuickConversationsService.handleSmsReceived(intent);
                break;
            case ConnectivityManager.CONNECTIVITY_ACTION:
                if (hasInternetConnection()) {
                    if (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0) {
                        schedulePostConnectivityChange();
                    }
                    if (Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) {
                        resetAllAttemptCounts(true, false);
                    }
                    Resolver.clearCache();
                }
                break;
            case Intent.ACTION_SHUTDOWN:
                logoutAndSave(true);
                return START_NOT_STICKY;
            case ACTION_CLEAR_NOTIFICATION:
                mNotificationExecutor.execute(() -> {
                    try {
                        final Conversation c = findConversationByUuid(uuid);
                        if (c != null) {
                            mNotificationService.clear(c);
                        } else {
                            mNotificationService.clear();
                        }
                        restoredFromDatabaseLatch.await();
                    } catch (InterruptedException e) {
                        Log.d(Config.LOGTAG, "unable to process clear notification");
                    }
                });
                break;
            case ACTION_DISMISS_CALL:
                {
                    final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID);
                    Log.d(Config.LOGTAG, "received intent to dismiss call with session id " + sessionId);
                    mJingleConnectionManager.rejectRtpSession(sessionId);
                    break;
                }
            case TorServiceUtils.ACTION_STATUS:
                final String status = intent.getStringExtra(TorServiceUtils.EXTRA_STATUS);
                // TODO port and host are in 'extras' - but this may not be a reliable source?
                if ("ON".equals(status)) {
                    handleOrbotStartedEvent();
                    return START_STICKY;
                }
                break;
            case ACTION_END_CALL:
                {
                    final String sessionId = intent.getStringExtra(RtpSessionActivity.EXTRA_SESSION_ID);
                    Log.d(Config.LOGTAG, "received intent to end call with session id " + sessionId);
                    mJingleConnectionManager.endRtpSession(sessionId);
                }
                break;
            case ACTION_PROVISION_ACCOUNT:
                {
                    final String address = intent.getStringExtra("address");
                    final String password = intent.getStringExtra("password");
                    if (QuickConversationsService.isQuicksy() || Strings.isNullOrEmpty(address) || Strings.isNullOrEmpty(password)) {
                        break;
                    }
                    provisionAccount(address, password);
                    break;
                }
            case ACTION_DISMISS_ERROR_NOTIFICATIONS:
                dismissErrorNotifications();
                break;
            case ACTION_TRY_AGAIN:
                resetAllAttemptCounts(false, true);
                interactive = true;
                break;
            case ACTION_REPLY_TO_CONVERSATION:
                Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
                if (remoteInput == null) {
                    break;
                }
                final CharSequence body = remoteInput.getCharSequence("text_reply");
                final boolean dismissNotification = intent.getBooleanExtra("dismiss_notification", false);
                final String lastMessageUuid = intent.getStringExtra("last_message_uuid");
                if (body == null || body.length() <= 0) {
                    break;
                }
                mNotificationExecutor.execute(() -> {
                    try {
                        restoredFromDatabaseLatch.await();
                        final Conversation c = findConversationByUuid(uuid);
                        if (c != null) {
                            directReply(c, body.toString(), lastMessageUuid, dismissNotification);
                        }
                    } catch (InterruptedException e) {
                        Log.d(Config.LOGTAG, "unable to process direct reply");
                    }
                });
                break;
            case ACTION_MARK_AS_READ:
                mNotificationExecutor.execute(() -> {
                    final Conversation c = findConversationByUuid(uuid);
                    if (c == null) {
                        Log.d(Config.LOGTAG, "received mark read intent for unknown conversation (" + uuid + ")");
                        return;
                    }
                    try {
                        restoredFromDatabaseLatch.await();
                        sendReadMarker(c, null);
                    } catch (InterruptedException e) {
                        Log.d(Config.LOGTAG, "unable to process notification read marker for conversation " + c.getName());
                    }
                });
                break;
            case ACTION_SNOOZE:
                mNotificationExecutor.execute(() -> {
                    final Conversation c = findConversationByUuid(uuid);
                    if (c == null) {
                        Log.d(Config.LOGTAG, "received snooze intent for unknown conversation (" + uuid + ")");
                        return;
                    }
                    c.setMutedTill(System.currentTimeMillis() + 30 * 60 * 1000);
                    mNotificationService.clear(c);
                    updateConversation(c);
                });
            case AudioManager.RINGER_MODE_CHANGED_ACTION:
            case NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED:
                if (dndOnSilentMode()) {
                    refreshAllPresences();
                }
                break;
            case Intent.ACTION_SCREEN_ON:
                deactivateGracePeriod();
            case Intent.ACTION_USER_PRESENT:
            case Intent.ACTION_SCREEN_OFF:
                if (awayWhenScreenLocked()) {
                    refreshAllPresences();
                }
                break;
            case ACTION_FCM_TOKEN_REFRESH:
                refreshAllFcmTokens();
                break;
            case ACTION_IDLE_PING:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    scheduleNextIdlePing();
                }
                break;
            case ACTION_FCM_MESSAGE_RECEIVED:
                pushedAccountHash = intent.getStringExtra("account");
                Log.d(Config.LOGTAG, "push message arrived in service. account=" + pushedAccountHash);
                break;
            case Intent.ACTION_SEND:
                Uri uri = intent.getData();
                if (uri != null) {
                    Log.d(Config.LOGTAG, "received uri permission for " + uri.toString());
                }
                return START_STICKY;
        }
    }
    synchronized (this) {
        WakeLockHelper.acquire(wakeLock);
        boolean pingNow = ConnectivityManager.CONNECTIVITY_ACTION.equals(action) || (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0 && ACTION_POST_CONNECTIVITY_CHANGE.equals(action));
        final HashSet<Account> pingCandidates = new HashSet<>();
        final String androidId = PhoneHelper.getAndroidId(this);
        for (Account account : accounts) {
            final boolean pushWasMeantForThisAccount = CryptoHelper.getAccountFingerprint(account, androidId).equals(pushedAccountHash);
            pingNow |= processAccountState(account, interactive, "ui".equals(action), pushWasMeantForThisAccount, pingCandidates);
        }
        if (pingNow) {
            for (Account account : pingCandidates) {
                final boolean lowTimeout = isInLowPingTimeoutMode(account);
                account.getXmppConnection().sendPing();
                Log.d(Config.LOGTAG, account.getJid().asBareJid() + " send ping (action=" + action + ",lowTimeout=" + lowTimeout + ")");
                scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
            }
        }
        WakeLockHelper.release(wakeLock);
    }
    if (SystemClock.elapsedRealtime() - mLastExpiryRun.get() >= Config.EXPIRY_INTERVAL) {
        expireOldMessages();
    }
    return START_STICKY;
}
Also used : Account(eu.siacs.conversations.entities.Account) Bundle(android.os.Bundle) Conversation(eu.siacs.conversations.entities.Conversation) Uri(android.net.Uri) XmppUri(eu.siacs.conversations.utils.XmppUri) HashSet(java.util.HashSet)

Example 94 with Conversation

use of eu.siacs.conversations.entities.Conversation in project Conversations by siacs.

the class ConversationFragment method saveMessageDraftStopAudioPlayer.

private void saveMessageDraftStopAudioPlayer() {
    final Conversation previousConversation = this.conversation;
    if (this.activity == null || this.binding == null || previousConversation == null) {
        return;
    }
    Log.d(Config.LOGTAG, "ConversationFragment.saveMessageDraftStopAudioPlayer()");
    final String msg = this.binding.textinput.getText().toString();
    storeNextMessage(msg);
    updateChatState(this.conversation, msg);
    messageListAdapter.stopAudioPlayer();
    mediaPreviewAdapter.clearPreviews();
    toggleInputMethod();
}
Also used : Conversation(eu.siacs.conversations.entities.Conversation)

Example 95 with Conversation

use of eu.siacs.conversations.entities.Conversation in project Conversations by siacs.

the class ConversationFragment method resendMessage.

private void resendMessage(final Message message) {
    if (message.isFileOrImage()) {
        if (!(message.getConversation() instanceof Conversation)) {
            return;
        }
        final Conversation conversation = (Conversation) message.getConversation();
        final DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message);
        if ((file.exists() && file.canRead()) || message.hasFileOnRemoteHost()) {
            final XmppConnection xmppConnection = conversation.getAccount().getXmppConnection();
            if (!message.hasFileOnRemoteHost() && xmppConnection != null && conversation.getMode() == Conversational.MODE_SINGLE && !xmppConnection.getFeatures().httpUpload(message.getFileParams().getSize())) {
                activity.selectPresence(conversation, () -> {
                    message.setCounterpart(conversation.getNextCounterpart());
                    activity.xmppConnectionService.resendFailedMessages(message);
                    new Handler().post(() -> {
                        int size = messageList.size();
                        this.binding.messagesView.setSelection(size - 1);
                    });
                });
                return;
            }
        } else if (!Compatibility.hasStoragePermission(getActivity())) {
            Toast.makeText(activity, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
            return;
        } else {
            Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show();
            message.setDeleted(true);
            activity.xmppConnectionService.updateMessage(message, false);
            activity.onConversationsListItemUpdated();
            refresh();
            return;
        }
    }
    activity.xmppConnectionService.resendFailedMessages(message);
    new Handler().post(() -> {
        int size = messageList.size();
        this.binding.messagesView.setSelection(size - 1);
    });
}
Also used : XmppConnection(eu.siacs.conversations.xmpp.XmppConnection) Handler(android.os.Handler) Conversation(eu.siacs.conversations.entities.Conversation) DownloadableFile(eu.siacs.conversations.entities.DownloadableFile) SuppressLint(android.annotation.SuppressLint)

Aggregations

Conversation (eu.siacs.conversations.entities.Conversation)110 Account (eu.siacs.conversations.entities.Account)27 Message (eu.siacs.conversations.entities.Message)24 Jid (eu.siacs.conversations.xmpp.Jid)22 Contact (eu.siacs.conversations.entities.Contact)17 MucOptions (eu.siacs.conversations.entities.MucOptions)10 Intent (android.content.Intent)9 Element (eu.siacs.conversations.xml.Element)9 PendingIntent (android.app.PendingIntent)8 XmppAxolotlMessage (eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage)8 MessagePacket (eu.siacs.conversations.xmpp.stanzas.MessagePacket)8 Uri (android.net.Uri)7 Conversational (eu.siacs.conversations.entities.Conversational)7 InvalidJidException (eu.siacs.conversations.xmpp.jid.InvalidJidException)7 SuppressLint (android.annotation.SuppressLint)6 SpannableString (android.text.SpannableString)6 XmppConnection (eu.siacs.conversations.xmpp.XmppConnection)6 Jid (eu.siacs.conversations.xmpp.jid.Jid)6 ArrayList (java.util.ArrayList)6 Fragment (android.app.Fragment)4