static boolean canDelay(@Nonnull final Packet stanza)
    {
        if (stanza instanceof IQ) {
            return false;
        }

        if (stanza instanceof Presence) {
            final Presence presence = (Presence) stanza;
            if (presence.getType() == null || presence.getType() == Presence.Type.unavailable) {
                // Presence updates are generally unimportant, unless it is a MUC self-presence stanza, as that suggests
                // that the user joined or left a room.
                final Element muc = presence.getChildElement("x", "http://jabber.org/protocol/muc#user");
                final boolean isSelfPresence = muc != null && muc.elements("status").stream().anyMatch(status -> "110".equals(status.attributeValue("code")));
                return !isSelfPresence;
            }
        }

        if (stanza instanceof Message)
        {
            final Message message = (Message) stanza;
            if (message.getBody() == null) {
                if (message.getType() == Message.Type.groupchat && !message.getElement().elements("subject").isEmpty()) {
                    // A subject (which can be empty) is sent to indicate that a room join has completed.
                    return false;
                }

                final Element muc = message.getChildElement("x", "http://jabber.org/protocol/muc#user");
                if (muc != null && !muc.elements("invite").isEmpty()) {
                    // Invitations to MUC rooms should be shown immediately.
                    return false;
                }

                if (!message.getElement().elements("encrypted").isEmpty()) {
                    // OMEMO messages never have a body element. We do not know what is being encrypted, but let's assume it's important to err on the side of caution.
                    return false;
                }

                if (message.getElement().elements().stream().anyMatch(element -> element.getNamespaceURI().startsWith("urn:xmpp:jingle-message:"))) {
                    // Typically, things that have to do with setting up an audio/video call. The user wants to see this as soon as possible, so do not delay. (OF-2750)
                    return false;
                }

                // No message body, and none of the exemptions above? It can probably wait.
                return true;
            }
        }

        return false;
    }
@Test
    public void testJinglePropose() throws Exception
    {
        // Setup test fixture.
        final Packet input = parse("<message type=\"chat\" id=\"jm-propose-LE3clSJQobTiFcrAoSD52\" to=\"user@example.com\">\n" +
            "   <propose xmlns=\"urn:xmpp:jingle-message:0\" id=\"LE3clSJQobTiFcrAoNLR2A\">\n" +
            "      <description xmlns=\"urn:xmpp:jingle:apps:rtp:1\" media=\"audio\" />\n" +
            "      <description xmlns=\"urn:xmpp:jingle:apps:rtp:1\" media=\"video\" />\n" +
            "   </propose>\n" +
            "   <request xmlns=\"urn:xmpp:receipts\" />\n" +
            "   <store xmlns=\"urn:xmpp:hints\" />\n" +
            "</message>");

        // Execute system under test.
        final boolean result = CsiManager.canDelay(input);

        // Verify results.
        assertFalse(result);
    }