Delivery receipt requests not working for XMPP Android (aSmack) - android

I'm using OpenFire with aSmack.
I can't seem to get DeliveryReceipts working.
I do the following when I create a connection:
//create connection
connection.login(username, password);
DeliveryReceiptManager.getInstanceFor(connection).enableAutoReceipts();
DeliveryReceiptManager.getInstanceFor(connection).addReceiptReceivedListener(new ReceiptReceivedListener()
{
#Override
public void onReceiptReceived(String arg0, String arg1, String arg2)
{
Log.v("app", arg0 + ", " + arg1 + ", " + arg2);
}
});
I'm sending a message to another user using:
//send chat
Message msg = new Message(id, Message.Type.chat);
msg.setBody(chat);
DeliveryReceiptManager.addDeliveryReceiptRequest(msg);
connection.sendPacket(msg);
The above does not work although the message gets sent with the ReceiptRequest. The listener does not get fired at the sender's end although the receiver receives the message. (I confirmed it through debugging that a DeliveryReceiptRequest does indeed get attached to the message that is sent).
I've also tried manually sending back the Receipt by using the following in my PacketListener with (MessageTypeFilter(Message.Type.chat)):
Packet received = new Message();
received.addExtension(new DeliveryReceipt(packet.getPacketID()));
received.setTo(packet.getFrom());
getConnection().sendPacket(received);
Still, the client at the receiving end receives the message alright but the listener does not get fired in the sender's system. Anything I'm missing?

Add these lines before you set up your connection and Auto Receipts will work with ReceiptReceivedListener. Seems like the DeliveryReceipt extensions aren't registered by default.
ProviderManager.getInstance().addExtensionProvider(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE, new DeliveryReceipt.Provider());
ProviderManager.getInstance().addExtensionProvider(DeliveryReceiptRequest.ELEMENT, new DeliveryReceiptRequest().getNamespace(), new DeliveryReceiptRequest.Provider());

Hi the above said answer given me NPE, so I used following code to get message notifications which was working perfectly for me:
Don't forget to add this ProviderManager
ProviderManager pm = ProviderManager.getInstance();
pm.addExtensionProvider("x", "jabber:x:event",new MessageEventProvider());
MessageEventManager messageEventManager = new MessageEventManager(connection);
messageEventManager.addMessageEventNotificationListener(m_messageEventNotificationListener);
messageEventManager.addMessageEventRequestListener(m_DefaultMessageEventRequestListener);
/*
* Notifies when message events happend
*
*/
MessageEventNotificationListener m_messageEventNotificationListener = new MessageEventNotificationListener() {
#Override
public void deliveredNotification(String fromJID, String messageID) {
final String _messageID =messageID;
System.out.println("deliveredNotification");
UiUtility.printMe("Message("+messageID+") Was Delivered to "+fromJID);
//WRITE YOUR CUSTOM METHOD WHEN MSG DELIVERED NOTFICATIONN RECIEVED.
}
#Override
public void displayedNotification(String string, String string1) {
}
#Override
public void composingNotification(String string, String string1) {
}
#Override
public void offlineNotification(String string, String string1) {
}
#Override
public void cancelledNotification(String string, String string1) {
}
};
/*
* Send a request when message events occured
*/
DefaultMessageEventRequestListener m_DefaultMessageEventRequestListener = new DefaultMessageEventRequestListener() {
#Override
public void deliveredNotificationRequested(String from, String packetID, MessageEventManager messageEventManager) {
super.deliveredNotificationRequested(from, packetID, messageEventManager); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void displayedNotificationRequested(String from, String packetID, MessageEventManager messageEventManager) {
super.displayedNotificationRequested(from, packetID, messageEventManager); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void offlineNotificationRequested(String from, String packetID, MessageEventManager messageEventManager) {
super.offlineNotificationRequested(from, packetID, messageEventManager); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void composingNotificationRequested(String from, String packetID, MessageEventManager messageEventManager) {
super.composingNotificationRequested(from, packetID, messageEventManager); //To change body of generated methods, choose Tools | Templates.
}
};

It's a bit late but this will help someone, take note of
receiptManager.setAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.always);
Check below code:
DeliveryReceiptManager receiptManager = DeliveryReceiptManager.getInstanceFor(connection);
//automatically enable delivery receipts to every message
receiptManager.autoAddDeliveryReceiptRequests();
receiptManager.setAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.always);
receiptManager.addReceiptReceivedListener(new ReceiptReceivedListener() {
#Override
public void onReceiptReceived(Jid fromJid, Jid toJid, String receiptId, Stanza receipt) {
//handle delivery receipts here
}
});

Related

Not receiving unread messages count in quickblox

I am using quickblox android sdk for a groupchat application and it is working perfectly well except for the fact that i am unable to receive push notification if a message is sent when i was offline. So i decided to query for unread messages count but am getting 0 from the server. I don't know what i have to do to get groupchat dialog for a user to be able to receive notification when the user was not online.
This is the code I used for querying for unread messages:
Set<String> dialogIds = new HashSet<String>();
String groupChatId = groupChat.getDialogId();
System.out.println("GroupChat Id: "+groupChatId);
dialogIds.add(groupChatId);
QBChatDialog chatDialog = new QBChatDialog(groupChatId);
QBMessageGetBuilder messageGetBuilder = new QBMessageGetBuilder();
messageGetBuilder.setLimit(500);
messageGetBuilder.sortDesc("date_sent");
QBRestChatService.getTotalUnreadMessagesCount(dialogsIds).performAsync(new QBEntityCallback<Integer>() {
#Override
public void onSuccess(Integer total, Bundle params) {
Log.i(TAG, "total unread messages: " + total);
// if you have more then one dialog you can get each value with params.getInt(dialog_id)
}
#Override
public void onError(QBResponseException e) {
e.printStackTrace();
}
});
The first part is correct:
Set<String> dialogIds = new HashSet<String>();
String groupChatId = groupChat.getDialogId();
dialogsIds.add(groupChatId);
But, after that you were not using dialogIds. And also, instead of getDialogMessages () you need to use getTotalUnreadMessagesCount() as following:
QBRestChatService.getTotalUnreadMessagesCount(dialogIds).performAsync(new QBEntityCallback<Integer>() {
#Override
public void onSuccess(Integer total, Bundle params) {
Log.i(TAG, "totat messages: " + total);
// if you have more then one dialog you can get each value with params.getInt(dialog_id)
}
#Override
public void onError(QBResponseException e) { }
});

Sending upstream message to GCM from Android app

I am trying to send some data to GCM. I have configured xampp in my local server to accomplish that.
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
Bundle data = new Bundle();
String msgId = "001";
data.putString("myid", id);
data.putString("mylt", la);
data.putString("myln", lo);
data.putString("recid", recid);
gcm.send(recid+ "#gcm.googleapis.com", msgId, data);
} catch (IOException ioexce) {
ioexce.printStackTrace();
msg = ioexce.toString();
Log.e("gcm_error", msg);
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
}
}.execute(null, null, null);
Per the docs the parameters in the send method are, String to, String msgId, Bundle data. I used the token the receiver received when they register with GCM in place of String to. But I get "W/InstanceID/Rpc: Found 10011" in the log when I execute the above code and the message is not sent to my server. Upon some research I found out the "found 10011" meant some parameter is missing. But I don't know what is missing.

How to add custom extension(time) to <message> tag?

I'm trying to add time extension to message with custom packet extension. It seems like time gets added while sending message. But at receiver end, it shows null.
This is my packet extension class and EmbeddedExtensionProvider
public class TimestampExtension implements PacketExtension {
public static final String ELEMENT = "timestamp";
public static final String NAMESPACE = "urn:xmpp:timestamp";
public String TIME = null;
public TimestampExtension() {
}
public void setTime() {
SimpleDateFormat time = new SimpleDateFormat("hh:mm a");
Date dateTime = new Date();
String strTime = time.format(dateTime);
this.TIME = strTime;
}
public String getTime() {
return TIME;
}
#Override
public String getElementName() {
return ELEMENT;
}
#Override
public String getNamespace() {
return NAMESPACE;
}
#Override
public String toXML() {
return "<" + ELEMENT + " xmlns='" + NAMESPACE + "'><time>" + TIME
+ "</time></" + ELEMENT + ">";
}
public static class Provider extends EmbeddedExtensionProvider {
#Override
protected PacketExtension createReturnExtension(String arg0,
String arg1, Map<String, String> arg2,
List<? extends PacketExtension> arg3) {
return new TimestampExtension();
}
}
}
Registering provider
ProviderManager.getInstance().addExtensionProvider(
TimestampExtension.ELEMENT, TimestampExtension.NAMESPACE,
new TimestampExtension.Provider());
Sending message with extension
TimestampExtension timeExt = new TimestampExtension();
timeExt.setTime();
msg.addExtension(timeExt);
connection.sendPacket(msg);
Message xml output at sender:
<message id="m55K5-7" to="testfirzan#sushant" type="chat">
<body>hi</body><request xmlns='urn:xmpp:receipts'/>
<timestamp xmlns='urn:xmpp:timestamp'>
<time>01:04 PM</time>
</timestamp>
Message xml output at receiver:
<message id="m55K5-7" to="testfirzan#sushant" from="testsushant#sushant/Smack" type="chat">
<body>hi</body><request xmlns='urn:xmpp:receipts'/>
<timestamp xmlns='urn:xmpp:timestamp'>
<time>null</time>
</timestamp>
It's supposed to show sending time in time element. What i'm doing wrong ?
Sushant's answer is correct but with latest version of org.igniterealtime.smack:smack-android:4.2.0-beta2 they have changed the DefaultPacketExtension to StandardExtensionElement for adding custom element in message.
Code to add extension
//Creating Standard packet extension with name as 'timestamp' and urn as 'urn:xmpp:timestamp'
StandardExtensionElement extTimeStamp = StandardExtensionElement.builder(
"timestamp", "urn:xmpp:timestamp")
.addAttribute("timestamp", String.valueOf(System.currentTimeMillis())) //Setting value in extension
.build();
//Add extension to message tag
message.addExtension(extTimeStamp);
Hope this will help future developers.
Sorry folks for late answer.
Since time was mandatory parameter for me, i end up using DefaultPacketExtension
//To sent message
private void sendMessage(String message, String recipient) {
Message msg = new Message(recipient, Message.Type.chat);
msg.setBody(message);
//Getting current timestamp in string format
String messageTimeStamp = String.valueOf(System.currentTimeMillis());
//Creating default packet extension with name as 'timestamp' and urn as 'urn:xmpp:timestamp'
DefaultPacketExtension extTimeStamp = new DefaultPacketExtension(
"timestamp", "urn:xmpp:timestamp");
//Setting value in extension
extTimeStamp.setValue("timestamp", messageTimestamp);
//Add extension to message tag
msg.addExtension(extTimeStamp);
//Send message
xmppConnection.sendPacket(message);
}
//To receive and parse message with extension implement PacketListener
#Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
//Get the extension from message
DefaultPacketExtension extTimestamp = (DefaultPacketExtension) message
.getExtension("urn:xmpp:timestamp");
//Get the value from extension
long timestamp = Long.parseLong(extTimestamp.getValue("timestamp"));
System.out.println("Message :" + message.getBody() + " Timestamp: "+timestamp);
}
The problem is in your Provider
return new TimestampExtension();
you need to get time element from the XmlPullParser when parsed the message and set it to your extension instance.

How to enable the XEP-0199 in Smack?

I'm using aSmack. My app listens a chatroom and reacts to the messages but it never send a message. The app doesn't receive more messages if the chatroom remains in silence for a while and then a new message is sent. I researched and I think that XEP-0199 is the solution here. I see that #Flow (the current Smack maintainer) implemented it and the issue related was closed.
I think that I need to use PingProvider but I really don't know how to connect this class with the Connection.
How can I enable the XEP-0199? How can I use PingProvider?
Connection code:
smack = SmackAndroid.init(getActivity().getApplicationContext());
connection = new XMPPConnection(App.getServer());
connection.addConnectionListener(new ConnectionListener() {
private final static String SMACK = "SMACK";
#Override
public void reconnectionSuccessful() {
Log.i(SMACK , "reconnectionSuccessful");
}
#Override
public void reconnectionFailed(Exception e) {
Log.i(SMACK, "reconnectionFailed", e);
}
#Override
public void reconnectingIn(int seconds) {
Log.i(SMACK, "reconnectingIn " + seconds);
}
#Override
public void connectionClosedOnError(Exception e) {
Log.i(SMACK, "connectionClosedOnError", e);
}
#Override
public void connectionClosed() {
Log.i(SMACK, "connectionClosed");
}
});
connection.connect();
connection.login(user, password);
I fix the problem implementing the ping response manually:
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
connection.sendPacket(new Pong((Ping) packet));
}
}, new PacketFilter() {
#Override
public boolean accept(Packet packet) {
return packet instanceof Ping;
}
});
To prevent user from disconnecting your session
PingManager pm = PingManager.getInstanceFor(MyApplication.connection) ;
pm.setPingInterval(5) ; // 5 sec
pm.pingMyServer() ;
pm.registerPingFailedListener(new PingFailedListener() {
#Override
public void pingFailed() {
Log.e(TAG , "pingFailed") ;
}
});
XEP 0199 is not a solution, Ping is used to check weather the server is up or not. actually you will send ping to the server.
Now as fas as your problem is concerned. Show me the message stanza that you are trying to send. and also check if the chat-room is public or private. you can not send a message to a private chat room.
Answer Updated:
Try using this code for detecting message recieve
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
Network.connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message.getFrom());
Log.i("XMPPClient", "Got text [" + message.getBody() + "] from [" + fromName + "]");
//recieve.setText(message.getBody());
/*messages.add(fromName + ":");
messages.add(message.getBody());*/
// Add the incoming message to the list view
item = new RowItem(R.drawable.billing, message.getBody());
adapter = new CustomListViewAdapter(getBaseContext(),
R.layout.list_item, rowItems);
rowItems.add(item);
//listView.setAdapter(adapter);
}
}
}, filter);
I called PingManager.getInstanceFor method to enable XEP-0199 support.

Android runnable on thread called multiple times

I am trying to implement MUC with aSmack, but seem to be unable to update the UI with the ArrayAdapter correctly.
I have set up my listener in my ChatService.java like this:
connection.addPacketListener(new MessageListener(), new PacketFilter() {
public boolean accept(Packet packet) {
Message msg = (Message) packet;
return msg.getBody() != null;
}});
And my listener class looks like this:
private class MessageListener implements PacketListener {
/**
* Constructor.
*/
public MessageListener() {
}
public void processPacket(Packet packet) {
if(packet instanceof Message ) {
Message message = (Message) packet;
android.os.Message aosMessage = new android.os.Message();
aosMessage.what = message.getType().ordinal();
aosMessage.obj = message;
messageHandler.handleMessage(aosMessage);
}
}
}
Now the problem is as follows;
First, I tried updating the UI via the handler (the handler is defined in my ChatActivity.java):
private final Handler messageHandler = new Handler() {
private Message chatMessage;
#Override
public void handleMessage(final android.os.Message msg) {
chatMessage = (Message) msg.obj;
if(Message.Type.values()[msg.what].equals(Message.Type.groupchat)) {
conversationArrayAdapter.add("Received group message: " + chatMessage.getBody());
} else if (Message.Type.values()[msg.what].equals(Message.Type.chat)) {
conversationArrayAdapter.add("Received private message: " + chatMessage.getBody());
}
}
};
But this won't update the UI until an interaction is introduced from the user's end.
After a little web-digging, I realized I need to use the post (or runonUIthread) method to implement this, and so I tried:
private final Handler messageHandler = new Handler() {
private Message chatMessage;
#Override
public void handleMessage(final android.os.Message msg) {
chatMessage = (Message) msg.obj;
this.post(new Runnable() {
public void run() {
if(Message.Type.values()[msg.what].equals(Message.Type.groupchat)) {
conversationArrayAdapter.add("Received group message: " + chatMessage.getBody());
conversationArrayAdapter.notifyDataSetChanged();
} else if (Message.Type.values()[msg.what].equals(Message.Type.chat)) {
conversationArrayAdapter.add("Received private message: " + chatMessage.getBody());
conversationArrayAdapter.notifyDataSetChanged();
}
}
});
}
};
But now the run() method is called multiple times (confirmed on debug), and the UI is updated with a seemingly-random-amount of the same messages (different amount of repetitions for every message, but all the messages are shown).
This is my first android app (but I am a java developer by trade), and I am quite sure I am doing something wrong in regards to the architecture here. Any assistance (preferably a detailed one - with code samples and / or references to the correct areas of the documentation) would be greatly appreciated.
Thanks in advance!
Corrected working snippet after #Emil's answer
private class MessageListener implements PacketListener {
/**
* Constructor.
*/
public MessageListener() {
}
public void processPacket(Packet packet) {
if(packet instanceof Message ) {
Message message = (Message) packet;
android.os.Message aosMessage = new android.os.Message();
aosMessage.what = message.getType().ordinal();
aosMessage.obj = message;
aosMessage.setTarget(messageHandler);
aosMessage.sendToTarget();
}
}
}
Don't call handleMessage directly :
messageHandler.handleMessage(aosMessage);
You should obtain a message from a given Handler or setTarget(Handler handler) on a message and then call sendToTarget() on the message to get it to be sent and processed by the Handler. If you implement the Handler correctly you don't need the post for this.

Categories

Resources