jingle connection and manager. able to trigger dialog in gajim

This commit is contained in:
Daniel Gultsch 2014-04-07 20:05:45 +02:00
parent c30bf75a5d
commit 3f403fb8a9
10 changed files with 288 additions and 82 deletions

View File

@ -26,7 +26,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:maxHeight="300dp"
android:maxHeight="288dp"
android:maxWidth="288dp"
/>
<TextView

View File

@ -25,7 +25,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:maxHeight="300dp"
android:maxHeight="288dp"
android:maxWidth="288dp"
/>
<TextView

View File

@ -6,65 +6,82 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import android.util.LruCache;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
public class FileBackend {
private static int IMAGE_SIZE = 1920;
private Context context;
private LruCache<String, Bitmap> thumbnailCache;
public FileBackend(Context context) {
this.context = context;
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
thumbnailCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
}
private File getImageFile(Message message) {
public File getImageFile(Message message) {
Conversation conversation = message.getConversation();
String prefix = context.getFilesDir().getAbsolutePath();
String path = prefix+"/"+conversation.getAccount().getJid()+"/"+conversation.getContactJid();
String prefix = context.getFilesDir().getAbsolutePath();
String path = prefix + "/" + conversation.getAccount().getJid() + "/"
+ conversation.getContactJid();
String filename = message.getUuid() + ".webp";
return new File(path+"/"+filename);
return new File(path + "/" + filename);
}
private Bitmap resize(Bitmap originalBitmap, int size) {
int w = originalBitmap.getWidth();
int h = originalBitmap.getHeight();
if (Math.max(w, h) > size) {
int scalledW;
int scalledH;
if (w <= h) {
scalledW = (int) (w / ((double) h / size));
scalledH = size;
} else {
scalledW = size;
scalledH = (int) (h / ((double) w / size));
}
Bitmap scalledBitmap = Bitmap.createScaledBitmap(
originalBitmap, scalledW, scalledH, true);
return scalledBitmap;
} else {
return originalBitmap;
}
}
public File copyImageToPrivateStorage(Message message, Uri image) {
try {
InputStream is = context.getContentResolver().openInputStream(image);
InputStream is = context.getContentResolver()
.openInputStream(image);
File file = getImageFile(message);
file.getParentFile().mkdirs();
file.createNewFile();
OutputStream os = new FileOutputStream(file);
Bitmap originalBitmap = BitmapFactory.decodeStream(is);
is.close();
int w = originalBitmap.getWidth();
int h = originalBitmap.getHeight();
boolean success;
if (Math.max(w, h) > IMAGE_SIZE) {
int scalledW;
int scalledH;
if (w<=h) {
scalledW = (int) (w / ((double) h/IMAGE_SIZE));
scalledH = IMAGE_SIZE;
} else {
scalledW = IMAGE_SIZE;
scalledH = (int) (h / ((double) w/IMAGE_SIZE));
}
Bitmap scalledBitmap = Bitmap.createScaledBitmap(originalBitmap, scalledW,scalledH, true);
success = scalledBitmap.compress(Bitmap.CompressFormat.WEBP, 75, os);
} else {
success = originalBitmap.compress(Bitmap.CompressFormat.WEBP, 75, os);
}
Bitmap scalledBitmap = resize(originalBitmap, IMAGE_SIZE);
boolean success = scalledBitmap.compress(Bitmap.CompressFormat.WEBP,75,os);
if (!success) {
Log.d("xmppService","couldnt compress");
Log.d("xmppService", "couldnt compress");
}
os.close();
return file;
@ -75,12 +92,24 @@ public class FileBackend {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public Bitmap getImageFromMessage(Message message) {
return BitmapFactory.decodeFile(getImageFile(message).getAbsolutePath());
return BitmapFactory
.decodeFile(getImageFile(message).getAbsolutePath());
}
public Bitmap getThumbnailFromMessage(Message message, int size) {
Bitmap thumbnail = thumbnailCache.get(message.getUuid());
if (thumbnail==null) {
Log.d("xmppService","creating new thumbnail" + message.getUuid());
Bitmap fullsize = BitmapFactory.decodeFile(getImageFile(message)
.getAbsolutePath());
thumbnail = resize(fullsize, size);
this.thumbnailCache.put(message.getUuid(), thumbnail);
}
return thumbnail;
}
}

View File

@ -0,0 +1,50 @@
package eu.siacs.conversations.services;
import java.util.concurrent.ConcurrentHashMap;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.JingleConnection;
import eu.siacs.conversations.xmpp.stanzas.jingle.JinglePacket;
public class JingleConnectionManager {
private XmppConnectionService xmppConnectionService;
private ConcurrentHashMap<String, JingleConnection> connections = new ConcurrentHashMap<String, JingleConnection>();
public JingleConnectionManager(XmppConnectionService service) {
this.xmppConnectionService = service;
}
public void deliverPacket(Account account, JinglePacket packet) {
String id = generateInternalId(account.getJid(), packet.getFrom(), packet.getSessionId());
}
public JingleConnection createNewConnection(Message message) {
Account account = message.getConversation().getAccount();
JingleConnection connection = new JingleConnection(this,account, message.getCounterpart());
String id = generateInternalId(account.getJid(), message.getCounterpart(), connection.getSessionId());
connection.init(message);
return connection;
}
private String generateInternalId(String account, String counterpart, String sid) {
return account+"#"+counterpart+"#"+sid;
}
public XmppConnectionService getXmppConnectionService() {
return this.xmppConnectionService;
}
public Element getPrimaryCanditate(String jid) {
Element canditate = new Element("canditate");
canditate.setAttribute("cid","122");
canditate.setAttribute("port","1234");
canditate.setAttribute("jid", jid);
canditate.setAttribute("type", "assisted");
return canditate;
}
}

View File

@ -87,7 +87,8 @@ public class XmppConnectionService extends Service {
private List<Account> accounts;
private List<Conversation> conversations = null;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(this);
public OnConversationListChangedListener convChangedListener = null;
private int convChangedListenerCount = 0;
private OnAccountListChangedListener accountChangedListener = null;
@ -389,13 +390,15 @@ public class XmppConnectionService extends Service {
return this.fileBackend;
}
public void attachImageToConversation(Conversation conversation, Uri uri) {
public Message attachImageToConversation(Conversation conversation, Uri uri) {
Message message = new Message(conversation, "", Message.ENCRYPTION_NONE);
message.setType(Message.TYPE_IMAGE);
File file = this.fileBackend.copyImageToPrivateStorage(message, uri);
Log.d(LOGTAG,"new file"+file.getAbsolutePath());
conversation.getMessages().add(message);
databaseBackend.createMessage(message);
sendMessage(message, null);
return message;
}
@ -655,48 +658,52 @@ public class XmppConnectionService extends Service {
boolean saveInDb = false;
boolean addToConversation = false;
if (account.getStatus() == Account.STATUS_ONLINE) {
MessagePacket packet;
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
if (!conv.hasValidOtrSession()) {
// starting otr session. messages will be send later
conv.startOtrSession(getApplicationContext(), presence,true);
} else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
// otr session aleary exists, creating message packet
// accordingly
packet = prepareMessagePacket(account, message,
conv.getOtrSession());
account.getXmppConnection().sendMessagePacket(packet);
message.setStatus(Message.STATUS_SEND);
}
saveInDb = true;
addToConversation = true;
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
message.getConversation().endOtrIfNeeded();
long keyId = message.getConversation().getContact()
.getPgpKeyId();
packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_CHAT);
packet.setFrom(message.getConversation().getAccount()
.getFullJid());
packet.setTo(message.getCounterpart());
packet.setBody("This is an XEP-0027 encryted message");
packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody());
account.getXmppConnection().sendMessagePacket(packet);
message.setStatus(Message.STATUS_SEND);
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
saveInDb = true;
addToConversation = true;
if (message.getType() == Message.TYPE_IMAGE) {
mJingleConnectionManager.createNewConnection(message);
} else {
message.getConversation().endOtrIfNeeded();
// don't encrypt
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
message.setStatus(Message.STATUS_SEND);
MessagePacket packet;
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
if (!conv.hasValidOtrSession()) {
// starting otr session. messages will be send later
conv.startOtrSession(getApplicationContext(), presence,true);
} else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
// otr session aleary exists, creating message packet
// accordingly
packet = prepareMessagePacket(account, message,
conv.getOtrSession());
account.getXmppConnection().sendMessagePacket(packet);
message.setStatus(Message.STATUS_SEND);
}
saveInDb = true;
addToConversation = true;
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
message.getConversation().endOtrIfNeeded();
long keyId = message.getConversation().getContact()
.getPgpKeyId();
packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_CHAT);
packet.setFrom(message.getConversation().getAccount()
.getFullJid());
packet.setTo(message.getCounterpart());
packet.setBody("This is an XEP-0027 encryted message");
packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody());
account.getXmppConnection().sendMessagePacket(packet);
message.setStatus(Message.STATUS_SEND);
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
saveInDb = true;
addToConversation = true;
} else {
message.getConversation().endOtrIfNeeded();
// don't encrypt
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
message.setStatus(Message.STATUS_SEND);
saveInDb = true;
addToConversation = true;
}
packet = prepareMessagePacket(account, message, null);
account.getXmppConnection().sendMessagePacket(packet);
}
packet = prepareMessagePacket(account, message, null);
account.getXmppConnection().sendMessagePacket(packet);
}
} else {
// account is offline

View File

@ -33,6 +33,7 @@ import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -148,6 +149,8 @@ public class ConversationFragment extends Fragment {
public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
this.inflater = inflater;
final View view = inflater.inflate(R.layout.fragment_conversation,
@ -264,7 +267,7 @@ public class ConversationFragment extends Fragment {
}
if (item.getType() == Message.TYPE_IMAGE) {
viewHolder.image.setVisibility(View.VISIBLE);
viewHolder.image.setImageBitmap(activity.xmppConnectionService.getFileBackend().getImageFromMessage(item));
viewHolder.image.setImageBitmap(activity.xmppConnectionService.getFileBackend().getThumbnailFromMessage(item,(int) (metrics.density * 288)));
viewHolder.messageBody.setVisibility(View.GONE);
} else {
if (viewHolder.image != null) viewHolder.image.setVisibility(View.GONE);

View File

@ -139,4 +139,8 @@ public class Element {
content = content.replace("'","&apos;");
return content;
}
public void clearChildren() {
this.children.clear();
}
}

View File

@ -0,0 +1,67 @@
package eu.siacs.conversations.xmpp;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import android.util.Log;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.JingleConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.stanzas.jingle.Content;
import eu.siacs.conversations.xmpp.stanzas.jingle.JinglePacket;
public class JingleConnection {
private JingleConnectionManager mJingleConnectionManager;
private XmppConnectionService mXmppConnectionService;
private String sessionId;
private Account account;
private String counterpart;
private List<Element> canditates = new ArrayList<Element>();
public JingleConnection(JingleConnectionManager mJingleConnectionManager, Account account, String counterpart) {
this.mJingleConnectionManager = mJingleConnectionManager;
this.mXmppConnectionService = mJingleConnectionManager.getXmppConnectionService();
this.account = account;
this.counterpart = counterpart;
SecureRandom random = new SecureRandom();
sessionId = new BigInteger(100, random).toString(32);
this.canditates.add(this.mJingleConnectionManager.getPrimaryCanditate(account.getJid()));
}
public String getSessionId() {
return this.sessionId;
}
public void init(Message message) {
JinglePacket packet = this.bootstrapPacket();
packet.setAction("session-initiate");
packet.setInitiator(this.account.getFullJid());
Content content = new Content();
if (message.getType() == Message.TYPE_IMAGE) {
//creator='initiator' name='a-file-offer'
content.setAttribute("creator", "initiator");
content.setAttribute("name", "a-file-offer");
content.offerFile(this.mXmppConnectionService.getFileBackend().getImageFile(message));
content.setCanditates(this.canditates);
packet.setContent(content);
Log.d("xmppService",packet.toString());
account.getXmppConnection().sendIqPacket(packet, null);
}
}
private JinglePacket bootstrapPacket() {
JinglePacket packet = new JinglePacket();
packet.setFrom(account.getFullJid());
packet.setTo(this.counterpart+"/Gajim");
packet.setSessionId(this.sessionId);
return packet;
}
}

View File

@ -1,5 +1,8 @@
package eu.siacs.conversations.xmpp.stanzas.jingle;
import java.io.File;
import java.util.List;
import eu.siacs.conversations.xml.Element;
public class Content extends Element {
@ -10,4 +13,23 @@ public class Content extends Element {
public Content() {
super("content");
}
public void offerFile(File actualFile) {
Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3");
Element offer = description.addChild("offer");
Element file = offer.addChild("file");
file.addChild("size").setContent(""+actualFile.length());
file.addChild("name").setContent(actualFile.getName());
}
public void setCanditates(List<Element> canditates) {
Element transport = this.findChild("transport", "urn:xmpp:jingle:transports:s5b:1");
if (transport==null) {
transport = this.addChild("transport", "urn:xmpp:jingle:transports:s5b:1");
}
transport.clearChildren();
for(Element canditate : canditates) {
transport.addChild(canditate);
}
}
}

View File

@ -6,6 +6,7 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class JinglePacket extends IqPacket {
Content content = null;
Reason reason = null;
Element jingle = new Element("jingle");
@Override
public Element addChild(Element child) {
@ -22,27 +23,25 @@ public class JinglePacket extends IqPacket {
this.reason.setChildren(reasonElement.getChildren());
this.reason.setAttributes(reasonElement.getAttributes());
}
this.build();
this.findChild("jingle").setAttributes(child.getAttributes());
this.jingle.setAttributes(child.getAttributes());
}
return child;
}
public JinglePacket setContent(Content content) {
this.content = content;
this.build();
return this;
}
public JinglePacket setReason(Reason reason) {
this.reason = reason;
this.build();
return this;
}
private void build() {
this.children.clear();
Element jingle = addChild("jingle", "urn:xmpp:jingle:1");
this.jingle.clearChildren();
this.jingle.setAttribute("xmlns", "urn:xmpp:jingle:1");
if (this.content!=null) {
jingle.addChild(this.content);
}
@ -50,5 +49,28 @@ public class JinglePacket extends IqPacket {
jingle.addChild(this.reason);
}
this.children.add(jingle);
this.setAttribute("type", "set");
}
public String getSessionId() {
return this.jingle.getAttribute("sid");
}
public void setSessionId(String sid) {
this.jingle.setAttribute("sid", sid);
}
@Override
public String toString() {
this.build();
return super.toString();
}
public void setAction(String action) {
this.jingle.setAttribute("action", action);
}
public void setInitiator(String initiator) {
this.jingle.setAttribute("initiator", initiator);
}
}