jingle connection and manager. able to trigger dialog in gajim
This commit is contained in:
parent
c30bf75a5d
commit
3f403fb8a9
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -139,4 +139,8 @@ public class Element {
|
|||
content = content.replace("'","'");
|
||||
return content;
|
||||
}
|
||||
|
||||
public void clearChildren() {
|
||||
this.children.clear();
|
||||
}
|
||||
}
|
||||
|
|
67
src/eu/siacs/conversations/xmpp/JingleConnection.java
Normal file
67
src/eu/siacs/conversations/xmpp/JingleConnection.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue