Search in sources :

Example 1 with Conversation

use of de.pixart.messenger.entities.Conversation in project Pix-Art-Messenger by kriztan.

the class NotificationService method buildSingleConversations.

private Builder buildSingleConversations(final ArrayList<Message> messages) {
    final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
    if (messages.size() >= 1) {
        final Conversation conversation = messages.get(0).getConversation();
        final UnreadConversation.Builder mUnreadBuilder = new UnreadConversation.Builder(conversation.getName());
        mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService().get(conversation, getPixel(64)));
        mBuilder.setContentTitle(conversation.getName());
        if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
            int count = messages.size();
            mBuilder.setContentText(mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages, count, count));
        } else {
            Message message;
            if ((message = getImage(messages)) != null) {
                modifyForImage(mBuilder, mUnreadBuilder, message, messages);
            } else {
                modifyForTextOnly(mBuilder, mUnreadBuilder, messages);
            }
            RemoteInput remoteInput = new RemoteInput.Builder("text_reply").setLabel(UIHelper.getMessageHint(mXmppConnectionService, conversation)).build();
            PendingIntent markAsReadPendingIntent = createReadPendingIntent(conversation);
            NotificationCompat.Action markReadAction = new NotificationCompat.Action.Builder(R.drawable.ic_email_open_outline_white_24dp, mXmppConnectionService.getString(R.string.mark_as_read), markAsReadPendingIntent).build();
            String replyLabel = mXmppConnectionService.getString(R.string.reply);
            NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(R.drawable.ic_reply_white_24dp, replyLabel, createReplyIntent(conversation, false)).addRemoteInput(remoteInput).build();
            NotificationCompat.Action wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_wear_reply, replyLabel, createReplyIntent(conversation, true)).addRemoteInput(remoteInput).build();
            mBuilder.extend(new NotificationCompat.WearableExtender().addAction(wearReplyAction));
            mUnreadBuilder.setReplyAction(createReplyIntent(conversation, true), remoteInput);
            mUnreadBuilder.setReadPendingIntent(markAsReadPendingIntent);
            mBuilder.extend(new NotificationCompat.CarExtender().setUnreadConversation(mUnreadBuilder.build()));
            int addedActionsCount = 1;
            mBuilder.addAction(markReadAction);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                mBuilder.addAction(replyAction);
                ++addedActionsCount;
            }
            if (displaySnoozeAction(messages)) {
                String label = mXmppConnectionService.getString(R.string.snooze);
                PendingIntent pendingSnoozeIntent = createSnoozeIntent(conversation);
                NotificationCompat.Action snoozeAction = new NotificationCompat.Action.Builder(R.drawable.ic_notifications_paused_white_24dp, label, pendingSnoozeIntent).build();
                mBuilder.addAction(snoozeAction);
                ++addedActionsCount;
            }
            if (addedActionsCount < 3) {
                final Message firstLocationMessage = getFirstLocationMessage(messages);
                if (firstLocationMessage != null) {
                    String label = mXmppConnectionService.getResources().getString(R.string.show_location);
                    PendingIntent pendingShowLocationIntent = createShowLocationIntent(firstLocationMessage);
                    NotificationCompat.Action locationAction = new NotificationCompat.Action.Builder(R.drawable.ic_room_white_24dp, label, pendingShowLocationIntent).build();
                    mBuilder.addAction(locationAction);
                    ++addedActionsCount;
                }
            }
            if (addedActionsCount < 3) {
                Message firstDownloadableMessage = getFirstDownloadableMessage(messages);
                if (firstDownloadableMessage != null) {
                    String label = mXmppConnectionService.getResources().getString(R.string.download_x_file, UIHelper.getFileDescriptionString(mXmppConnectionService, firstDownloadableMessage));
                    PendingIntent pendingDownloadIntent = createDownloadIntent(firstDownloadableMessage);
                    NotificationCompat.Action downloadAction = new NotificationCompat.Action.Builder(R.drawable.ic_file_download_white_24dp, label, pendingDownloadIntent).build();
                    mBuilder.addAction(downloadAction);
                    ++addedActionsCount;
                }
            }
        }
        if (conversation.getMode() == Conversation.MODE_SINGLE) {
            Contact contact = conversation.getContact();
            Uri systemAccount = contact.getSystemAccount();
            if (systemAccount != null) {
                mBuilder.addPerson(systemAccount.toString());
            }
        }
        mBuilder.setWhen(conversation.getLatestMessage().getTimeSent());
        mBuilder.setSmallIcon(R.drawable.ic_notification);
        mBuilder.setDeleteIntent(createDeleteIntent(conversation));
        mBuilder.setContentIntent(createContentIntent(conversation));
    }
    return mBuilder;
}
Also used : RemoteInput(android.support.v4.app.RemoteInput) Message(de.pixart.messenger.entities.Message) UnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation) Builder(android.support.v4.app.NotificationCompat.Builder) UnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation) Conversation(de.pixart.messenger.entities.Conversation) SpannableString(android.text.SpannableString) Uri(android.net.Uri) Contact(de.pixart.messenger.entities.Contact) NotificationCompat(android.support.v4.app.NotificationCompat) PendingIntent(android.app.PendingIntent)

Example 2 with Conversation

use of de.pixart.messenger.entities.Conversation in project Pix-Art-Messenger by kriztan.

the class XmppConnectionService method onStartCommand.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    final String action = intent == null ? null : intent.getAction();
    String pushedAccountHash = null;
    boolean interactive = false;
    if (action != null) {
        final String uuid = intent.getStringExtra("uuid");
        switch(action) {
            case ConnectivityManager.CONNECTIVITY_ACTION:
                if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) {
                    resetAllAttemptCounts(true, false);
                }
                break;
            case ACTION_MERGE_PHONE_CONTACTS:
                if (restoredFromDatabaseLatch.getCount() == 0) {
                    loadPhoneContacts();
                }
                return START_STICKY;
            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_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);
                if (body == null || body.length() <= 0) {
                    break;
                }
                mNotificationExecutor.execute(() -> {
                    try {
                        restoredFromDatabaseLatch.await();
                        final Conversation c = findConversationByUuid(uuid);
                        if (c != null) {
                            directReply(c, body.toString(), 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);
                    } 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:
                if (dndOnSilentMode()) {
                    refreshAllPresences();
                }
                break;
            case Intent.ACTION_SCREEN_ON:
                deactivateGracePeriod();
            case Intent.ACTION_SCREEN_OFF:
                if (awayWhenScreenOff()) {
                    refreshAllPresences();
                }
                break;
            case ACTION_GCM_TOKEN_REFRESH:
                refreshAllGcmTokens();
                break;
            case ACTION_IDLE_PING:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    scheduleNextIdlePing();
                }
                break;
            case ACTION_GCM_MESSAGE_RECEIVED:
                Log.d(Config.LOGTAG, "gcm push message arrived in service. extras=" + intent.getExtras());
                pushedAccountHash = intent.getStringExtra("account");
                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) {
        this.wakeLock.acquire();
        boolean pingNow = ConnectivityManager.CONNECTIVITY_ACTION.equals(action);
        HashSet<Account> pingCandidates = new HashSet<>();
        for (Account account : accounts) {
            pingNow |= processAccountState(account, interactive, "ui".equals(action), CryptoHelper.getAccountFingerprint(account).equals(pushedAccountHash), pingCandidates);
        }
        if (pingNow) {
            for (Account account : pingCandidates) {
                List<Conversation> conversations = getConversations();
                for (Conversation conversation : conversations) {
                    if (conversation.getAccount() == account && !account.pendingConferenceJoins.contains(conversation)) {
                        resendFailedFileMessages(conversation);
                    }
                }
                final boolean lowTimeout = isInLowPingTimeoutMode(account);
                account.getXmppConnection().sendPing();
                Log.d(Config.LOGTAG, account.getJid().toBareJid() + " send ping (action=" + action + ", lowTimeout=" + Boolean.toString(lowTimeout) + ")");
                scheduleWakeUpCall(lowTimeout ? Config.LOW_PING_TIMEOUT : Config.PING_TIMEOUT, account.getUuid().hashCode());
            }
        }
        if (wakeLock.isHeld()) {
            try {
                wakeLock.release();
            } catch (final RuntimeException ignored) {
            }
        }
    }
    if (SystemClock.elapsedRealtime() - mLastExpiryRun.get() >= Config.EXPIRY_INTERVAL) {
        expireOldMessages();
    }
    return START_STICKY;
}
Also used : Account(de.pixart.messenger.entities.Account) Bundle(android.os.Bundle) Conversation(de.pixart.messenger.entities.Conversation) Uri(android.net.Uri) XmppUri(de.pixart.messenger.utils.XmppUri) HashSet(java.util.HashSet)

Example 3 with Conversation

use of de.pixart.messenger.entities.Conversation in project Pix-Art-Messenger by kriztan.

the class XmppConnectionService method findConversation.

public Conversation findConversation(final Account account, final Jid jid, final boolean muc) {
    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.toBareJid());
            }
            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.getLocalpart();
            }
            if (muc) {
                conversation = new Conversation(conversationName, account, jid, Conversation.MODE_MULTI);
            } else {
                conversation = new Conversation(conversationName, account, jid.toBareJid(), Conversation.MODE_SINGLE);
            }
            this.databaseBackend.createConversation(conversation);
            loadMessagesFromDb = false;
        }
        final Conversation c = conversation;
        mDatabaseReaderExecutor.execute(new Runnable() {

            @Override
            public void run() {
                if (loadMessagesFromDb) {
                    c.addAll(0, databaseBackend.getMessages(c, Config.PAGE_SIZE));
                    updateConversationUi();
                    c.messagesLoaded.set(true);
                }
                checkDeletedFiles(c);
            }
        });
        updateConversationUi();
        return conversation;
    }
}
Also used : Conversation(de.pixart.messenger.entities.Conversation) Contact(de.pixart.messenger.entities.Contact)

Example 4 with Conversation

use of de.pixart.messenger.entities.Conversation in project Pix-Art-Messenger by kriztan.

the class XmppConnectionService method joinMuc.

private void joinMuc(Conversation conversation, final OnConferenceJoined onConferenceJoined, final boolean followedInvite) {
    Account account = conversation.getAccount();
    account.pendingConferenceJoins.remove(conversation);
    account.pendingConferenceLeaves.remove(conversation);
    if (account.getStatus() == Account.State.ONLINE) {
        // disabled for testing strange MUC leaves
        sendPresencePacket(account, mPresenceGenerator.leave(conversation.getMucOptions()));
        conversation.resetMucOptions();
        if (onConferenceJoined != null) {
            conversation.getMucOptions().flagNoAutoPushConfiguration();
        }
        conversation.setHasMessagesLeftOnServer(false);
        fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() {

            private void join(Conversation conversation) {
                Account account = conversation.getAccount();
                final MucOptions mucOptions = conversation.getMucOptions();
                final Jid joinJid = mucOptions.getSelf().getFullJid();
                Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString());
                PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, mucOptions.nonanonymous() || onConferenceJoined != null);
                packet.setTo(joinJid);
                Element x = packet.addChild("x", "http://jabber.org/protocol/muc");
                if (conversation.getMucOptions().getPassword() != null) {
                    x.addChild("password").setContent(mucOptions.getPassword());
                }
                if (mucOptions.mamSupport()) {
                    // Use MAM instead of the limited muc history to get history
                    x.addChild("history").setAttribute("maxchars", "0");
                } else {
                    // Fallback to muc history
                    x.addChild("history").setAttribute("since", PresenceGenerator.getTimestamp(conversation.getLastMessageTransmitted().getTimestamp()));
                }
                sendPresencePacket(account, packet);
                if (onConferenceJoined != null) {
                    onConferenceJoined.onConferenceJoined(conversation);
                }
                if (!joinJid.equals(conversation.getJid())) {
                    conversation.setContactJid(joinJid);
                    databaseBackend.updateConversation(conversation);
                }
                if (mucOptions.mamSupport()) {
                    getMessageArchiveService().catchupMUC(conversation);
                }
                if (mucOptions.isPrivateAndNonAnonymous()) {
                    fetchConferenceMembers(conversation);
                    if (followedInvite && conversation.getBookmark() == null) {
                        saveConversationAsBookmark(conversation, null);
                    }
                }
                sendUnsentMessages(conversation);
            }

            @Override
            public void onConferenceConfigurationFetched(Conversation conversation) {
                join(conversation);
            }

            @Override
            public void onFetchFailed(final Conversation conversation, Element error) {
                if (error != null && "remote-server-not-found".equals(error.getName())) {
                    conversation.getMucOptions().setError(MucOptions.Error.SERVER_NOT_FOUND);
                    updateConversationUi();
                } else {
                    join(conversation);
                    fetchConferenceConfiguration(conversation);
                }
            }
        });
        updateConversationUi();
    } else {
        account.pendingConferenceJoins.add(conversation);
        conversation.resetMucOptions();
        conversation.setHasMessagesLeftOnServer(false);
        updateConversationUi();
    }
}
Also used : Account(de.pixart.messenger.entities.Account) MucOptions(de.pixart.messenger.entities.MucOptions) Jid(de.pixart.messenger.xmpp.jid.Jid) Element(de.pixart.messenger.xml.Element) Conversation(de.pixart.messenger.entities.Conversation) PresencePacket(de.pixart.messenger.xmpp.stanzas.PresencePacket)

Example 5 with Conversation

use of de.pixart.messenger.entities.Conversation in project Pix-Art-Messenger by kriztan.

the class DatabaseBackend method findConversation.

public Conversation findConversation(final Account account, final Jid contactJid) {
    SQLiteDatabase db = this.getReadableDatabase();
    String[] selectionArgs = { account.getUuid(), contactJid.toBareJid().toPreppedString() + "/%", contactJid.toBareJid().toPreppedString() };
    Cursor cursor = db.query(Conversation.TABLENAME, null, Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID + " like ? OR " + Conversation.CONTACTJID + "=?)", selectionArgs, null, null, null);
    if (cursor.getCount() == 0) {
        cursor.close();
        return null;
    }
    cursor.moveToFirst();
    Conversation conversation = Conversation.fromCursor(cursor);
    cursor.close();
    return conversation;
}
Also used : SQLiteDatabase(android.database.sqlite.SQLiteDatabase) Conversation(de.pixart.messenger.entities.Conversation) Cursor(android.database.Cursor)

Aggregations

Conversation (de.pixart.messenger.entities.Conversation)69 Jid (de.pixart.messenger.xmpp.jid.Jid)20 Account (de.pixart.messenger.entities.Account)18 InvalidJidException (de.pixart.messenger.xmpp.jid.InvalidJidException)16 Message (de.pixart.messenger.entities.Message)15 Contact (de.pixart.messenger.entities.Contact)11 MucOptions (de.pixart.messenger.entities.MucOptions)9 Intent (android.content.Intent)7 SuppressLint (android.annotation.SuppressLint)6 Uri (android.net.Uri)6 SpannableString (android.text.SpannableString)6 View (android.view.View)6 XmppAxolotlMessage (de.pixart.messenger.crypto.axolotl.XmppAxolotlMessage)6 DownloadableFile (de.pixart.messenger.entities.DownloadableFile)6 Element (de.pixart.messenger.xml.Element)6 MessagePacket (de.pixart.messenger.xmpp.stanzas.MessagePacket)6 IOException (java.io.IOException)6 Fragment (android.app.Fragment)5 SharedPreferences (android.content.SharedPreferences)5 Bitmap (android.graphics.Bitmap)5