diff --git a/gen/de/gultsch/chat/R.java b/gen/de/gultsch/chat/R.java index b7dde8f47..45083c731 100644 --- a/gen/de/gultsch/chat/R.java +++ b/gen/de/gultsch/chat/R.java @@ -34,8 +34,7 @@ public final class R { public static final int ic_launcher=0x7f020006; public static final int ic_profile=0x7f020007; public static final int message_border=0x7f020008; - public static final int profilemock=0x7f020009; - public static final int section_header=0x7f02000a; + public static final int section_header=0x7f020009; } public static final class id { public static final int account_confirm_password_desc=0x7f0a0011; diff --git a/ic_launcher-web.png b/ic_launcher-web.png deleted file mode 100644 index 8e26a9310..000000000 Binary files a/ic_launcher-web.png and /dev/null differ diff --git a/ic_profile-web.png b/ic_profile-web.png deleted file mode 100644 index c0c6ca8f6..000000000 Binary files a/ic_profile-web.png and /dev/null differ diff --git a/res/drawable-hdpi/es_slidingpane_shadow.xml b/res/drawable-hdpi/es_slidingpane_shadow.xml deleted file mode 100644 index eaca7894e..000000000 --- a/res/drawable-hdpi/es_slidingpane_shadow.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/drawable-mdpi/es_slidingpane_shadow.xml b/res/drawable-mdpi/es_slidingpane_shadow.xml deleted file mode 100644 index eaca7894e..000000000 --- a/res/drawable-mdpi/es_slidingpane_shadow.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/drawable-xxhdpi/es_slidingpane_shadow.xml b/res/drawable-xxhdpi/es_slidingpane_shadow.xml deleted file mode 100644 index eaca7894e..000000000 --- a/res/drawable-xxhdpi/es_slidingpane_shadow.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/drawable-xhdpi/es_slidingpane_shadow.xml b/res/drawable/es_slidingpane_shadow.xml similarity index 82% rename from res/drawable-xhdpi/es_slidingpane_shadow.xml rename to res/drawable/es_slidingpane_shadow.xml index cc711819e..34cc44bf4 100644 --- a/res/drawable-xhdpi/es_slidingpane_shadow.xml +++ b/res/drawable/es_slidingpane_shadow.xml @@ -2,6 +2,6 @@ + android:startColor="#eeeeee" /> \ No newline at end of file diff --git a/res/drawable-xhdpi/section_header.xml b/res/drawable/section_header.xml similarity index 100% rename from res/drawable-xhdpi/section_header.xml rename to res/drawable/section_header.xml diff --git a/res/layout/fragment_conversations_overview.xml b/res/layout/fragment_conversations_overview.xml index ae60de40a..5548cce62 100644 --- a/res/layout/fragment_conversations_overview.xml +++ b/res/layout/fragment_conversations_overview.xml @@ -6,7 +6,9 @@ + android:orientation="vertical" + android:background="#eeeeee" + > diff --git a/src/de/gultsch/chat/entities/Contact.java b/src/de/gultsch/chat/entities/Contact.java index 30dfc05bc..66221f8a3 100644 --- a/src/de/gultsch/chat/entities/Contact.java +++ b/src/de/gultsch/chat/entities/Contact.java @@ -20,9 +20,8 @@ public class Contact implements Serializable { return this.display_name; } - public Uri getProfilePhoto() { - if (photo == null) return null; - return Uri.parse(photo); + public String getProfilePhoto() { + return photo; } public String getJid() { diff --git a/src/de/gultsch/chat/entities/Conversation.java b/src/de/gultsch/chat/entities/Conversation.java index a00dd476a..10eb70797 100644 --- a/src/de/gultsch/chat/entities/Conversation.java +++ b/src/de/gultsch/chat/entities/Conversation.java @@ -33,10 +33,9 @@ public class Conversation extends AbstractEntity { private transient List messages = null; - public Conversation(String name, Uri profilePhoto, Account account, + public Conversation(String name, String profilePhoto, Account account, String contactJid) { - this(java.util.UUID.randomUUID().toString(), name, profilePhoto - .toString(), account.getUuid(), contactJid, System + this(java.util.UUID.randomUUID().toString(), name, profilePhoto, account.getUuid(), contactJid, System .currentTimeMillis(), STATUS_AVAILABLE); } diff --git a/src/de/gultsch/chat/ui/ConversationActivity.java b/src/de/gultsch/chat/ui/ConversationActivity.java index d831f9b8b..79d1e218f 100644 --- a/src/de/gultsch/chat/ui/ConversationActivity.java +++ b/src/de/gultsch/chat/ui/ConversationActivity.java @@ -9,6 +9,7 @@ import de.gultsch.chat.R; import de.gultsch.chat.R.id; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.utils.Beautifier; +import android.net.Uri; import android.os.Bundle; import android.app.FragmentTransaction; import android.content.Context; @@ -106,6 +107,16 @@ public class ConversationActivity extends XmppActivity { ((TextView) view.findViewById(R.id.conversation_lastmsg)).setText(getItem(position).getLatestMessage()); ((TextView) view.findViewById(R.id.conversation_lastupdate)) .setText(Beautifier.readableTimeDifference(getItem(position).getLatestMessageDate())); + + Uri profilePhoto = getItem(position).getProfilePhotoUri(); + ImageView imageView = (ImageView) view.findViewById(R.id.conversation_image); + if (profilePhoto!=null) { + imageView.setImageURI(profilePhoto); + } else { + imageView.setImageBitmap(Beautifier.getUnknownContactPicture(getItem(position).getName(),200)); + } + + ((ImageView) view.findViewById(R.id.conversation_image)) .setImageURI(getItem(position).getProfilePhotoUri()); return view; diff --git a/src/de/gultsch/chat/ui/NewConversationActivity.java b/src/de/gultsch/chat/ui/NewConversationActivity.java index 9df5d5eb8..b8061b23e 100644 --- a/src/de/gultsch/chat/ui/NewConversationActivity.java +++ b/src/de/gultsch/chat/ui/NewConversationActivity.java @@ -9,7 +9,9 @@ import de.gultsch.chat.R; import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; +import de.gultsch.chat.utils.Beautifier; import de.gultsch.chat.utils.Validator; +import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract; import android.text.Editable; @@ -74,8 +76,7 @@ public class NewConversationActivity extends XmppActivity { if (Validator.isValidJid(searchString)) { String name = searchString.split("@")[0]; - Contact newContact = new Contact(name, searchString, - DEFAULT_PROFILE_PHOTO); + Contact newContact = new Contact(name, searchString,null); aggregatedContacts.add(newContact); contactsHeader.setText("Create new contact"); } else { @@ -100,8 +101,6 @@ public class NewConversationActivity extends XmppActivity { + "\") AND (" + ContactsContract.CommonDataKinds.Im.PROTOCOL + "=\"" + ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER + "\")"; - protected static final String DEFAULT_PROFILE_PHOTO = "android.resource://de.gultsch.chat/" - + R.drawable.ic_profile; @Override protected void onCreate(Bundle savedInstanceState) { @@ -150,8 +149,13 @@ public class NewConversationActivity extends XmppActivity { .setText(getItem(position).getDisplayName()); ((TextView) view.findViewById(R.id.contact_jid)) .setText(getItem(position).getJid()); - ((ImageView) view.findViewById(R.id.contact_photo)) - .setImageURI(getItem(position).getProfilePhoto()); + String profilePhoto = getItem(position).getProfilePhoto(); + ImageView imageView = (ImageView) view.findViewById(R.id.contact_photo); + if (profilePhoto!=null) { + imageView.setImageURI(Uri.parse(profilePhoto)); + } else { + imageView.setImageBitmap(Beautifier.getUnknownContactPicture(getItem(position).getDisplayName(),90)); + } return view; } }; @@ -222,9 +226,9 @@ public class NewConversationActivity extends XmppActivity { while (cursor.moveToNext()) { String profilePhoto = cursor.getString(cursor .getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI)); - if (profilePhoto == null) { + /*if (profilePhoto == null) { profilePhoto = DEFAULT_PROFILE_PHOTO; - } + }*/ Contact contact = new Contact( cursor.getString(cursor .getColumnIndex(ContactsContract.Data.DISPLAY_NAME)), diff --git a/src/de/gultsch/chat/utils/Beautifier.java b/src/de/gultsch/chat/utils/Beautifier.java index 43b7acc2c..5184c0c79 100644 --- a/src/de/gultsch/chat/utils/Beautifier.java +++ b/src/de/gultsch/chat/utils/Beautifier.java @@ -3,18 +3,24 @@ package de.gultsch.chat.utils; import java.text.SimpleDateFormat; import java.util.Date; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.DisplayMetrics; + public class Beautifier { public static String readableTimeDifference(long time) { - if (time==0) { + if (time == 0) { return "just now"; } Date date = new Date(time); long difference = (System.currentTimeMillis() - time) / 1000; - if (difference<60) { + if (difference < 60) { return "just now"; - } else if (difference<60*10) { + } else if (difference < 60 * 10) { return difference / 60 + " min ago"; - } else if (difference<60*60*24) { + } else if (difference < 60 * 60 * 24) { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); return sdf.format(date); } else { @@ -22,4 +28,33 @@ public class Beautifier { return sdf.format(date); } } + + public static Bitmap getUnknownContactPicture(String name, int size) { + String firstLetter = name.substring(0, 1).toUpperCase(); + String centerLetter = name.substring(name.length() / 2, + (name.length() / 2) + 1); + + int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713, + 0xFFe92727 }; + + int color = holoColors[centerLetter.charAt(0) % holoColors.length]; + + Bitmap bitmap = Bitmap + .createBitmap(size, size, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + bitmap.eraseColor(color); + + Paint paint = new Paint(); + paint.setColor(0xffe5e5e5); + paint.setTextSize((float) (size * 0.9)); + paint.setAntiAlias(true); + Rect rect = new Rect(); + paint.getTextBounds(firstLetter, 0, 1, rect); + float width = paint.measureText(firstLetter); + canvas.drawText(firstLetter, (size / 2) - (width / 2), (size / 2) + + (rect.height() / 2), paint); + + return bitmap; + } } diff --git a/src/de/gultsch/chat/xml/Element.java b/src/de/gultsch/chat/xml/Element.java index d6d1b23d7..af3d8f1ff 100644 --- a/src/de/gultsch/chat/xml/Element.java +++ b/src/de/gultsch/chat/xml/Element.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import android.util.Log; + public class Element { protected String name; protected Hashtable attributes = new Hashtable(); @@ -26,6 +28,15 @@ public class Element { return this; } + public boolean hasChild(String name) { + for(Element child : this.children) { + if (child.getName().equals(name)) { + return true; + } + } + return false; + } + public Element setAttribute(String name, String value) { this.attributes.put(name, value); return this; @@ -36,6 +47,14 @@ public class Element { return this; } + public String getAttribute(String name) { + if (this.attributes.containsKey(name)) { + return this.attributes.get(name); + } else { + return null; + } + } + public String toString() { StringBuilder elementOutput = new StringBuilder(); if ((content==null)&&(children.size() == 0)) { diff --git a/src/de/gultsch/chat/xmpp/IqPacket.java b/src/de/gultsch/chat/xmpp/IqPacket.java index eec66a64f..d7672540d 100644 --- a/src/de/gultsch/chat/xmpp/IqPacket.java +++ b/src/de/gultsch/chat/xmpp/IqPacket.java @@ -12,9 +12,8 @@ public class IqPacket extends Element { super(name); } - public IqPacket(String id, int type) { + public IqPacket(int type) { super("iq"); - this.setAttribute("id",id); switch (type) { case TYPE_SET: this.setAttribute("type", "set"); @@ -34,4 +33,8 @@ public class IqPacket extends Element { super("iq"); } + public String getId() { + return this.getAttribute("id"); + } + } diff --git a/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java b/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java new file mode 100644 index 000000000..5e69b0cea --- /dev/null +++ b/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java @@ -0,0 +1,5 @@ +package de.gultsch.chat.xmpp; + +public interface OnIqPacketReceived { + public void onIqPacketReceived(IqPacket packet); +} diff --git a/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java b/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java new file mode 100644 index 000000000..9f4e6317b --- /dev/null +++ b/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java @@ -0,0 +1,5 @@ +package de.gultsch.chat.xmpp; + +public interface OnMessagePacketReceived { + public void onMessagePacketReceived(MessagePacket packet); +} diff --git a/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java b/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java new file mode 100644 index 000000000..d48c430da --- /dev/null +++ b/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java @@ -0,0 +1,5 @@ +package de.gultsch.chat.xmpp; + +public interface OnPresencePacketReceived { + public void onPresencePacketReceived(PresencePacket packet); +} diff --git a/src/de/gultsch/chat/xmpp/XmppConnection.java b/src/de/gultsch/chat/xmpp/XmppConnection.java index de35a0ea0..a167bd87f 100644 --- a/src/de/gultsch/chat/xmpp/XmppConnection.java +++ b/src/de/gultsch/chat/xmpp/XmppConnection.java @@ -7,6 +7,7 @@ import java.math.BigInteger; import java.net.Socket; import java.net.UnknownHostException; import java.security.SecureRandom; +import java.util.Hashtable; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -35,12 +36,19 @@ public class XmppConnection implements Runnable { private XmlReader tagReader; private TagWriter tagWriter; - private boolean isTlsEncrypted = true; + private boolean isTlsEncrypted = false; private boolean isAuthenticated = false; + private boolean shouldUseTLS = false; + private boolean shouldReConnect = true; + private boolean shouldBind = true; + private boolean shouldAuthenticate = true; + private Element streamFeatures; private static final int PACKET_IQ = 0; private static final int PACKET_MESSAGE = 1; private static final int PACKET_PRESENCE = 2; + + private Hashtable iqPacketCallbacks = new Hashtable(); public XmppConnection(Account account, PowerManager pm) { this.account = account; @@ -58,17 +66,6 @@ public class XmppConnection implements Runnable { tagWriter.setOutputStream(out); InputStream in = socket.getInputStream(); tagReader.setInputStream(in); - } catch (UnknownHostException e) { - Log.d(LOGTAG, "error during connect. unknown host"); - } catch (IOException e) { - Log.d(LOGTAG, "error during connect. io exception. falscher port?"); - } - } - - @Override - public void run() { - connect(); - try { tagWriter.beginDocument(); sendStartStream(); Tag nextTag; @@ -77,14 +74,25 @@ public class XmppConnection implements Runnable { processStream(nextTag); } else { Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName()); + return; } } - } catch (XmlPullParserException e) { - Log.d(LOGTAG, - "xml error during normal read. maybe missformed xml? " - + e.getMessage()); + } catch (UnknownHostException e) { + Log.d(LOGTAG, "error during connect. unknown host"); + return; } catch (IOException e) { - Log.d(LOGTAG, "io exception during read. connection lost?"); + Log.d(LOGTAG, "error during connect. io exception. falscher port?"); + return; + } catch (XmlPullParserException e) { + Log.d(LOGTAG,"xml exception "+e.getMessage()); + return; + } + } + + @Override + public void run() { + while(shouldReConnect) { + connect(); } } @@ -92,20 +100,11 @@ public class XmppConnection implements Runnable { IOException { Log.d(LOGTAG, "process Stream"); Tag nextTag; - while ((nextTag = tagReader.readTag()) != null) { + while (!(nextTag = tagReader.readTag()).isEnd("stream")) { if (nextTag.isStart("error")) { processStreamError(nextTag); } else if (nextTag.isStart("features")) { processStreamFeatures(nextTag); - if (!isTlsEncrypted) { - sendStartTLS(); - } - if ((!isAuthenticated) && (isTlsEncrypted)) { - sendSaslAuth(); - } - if ((isAuthenticated)&&(isTlsEncrypted)) { - sendBindRequest(); - } } else if (nextTag.isStart("proceed")) { switchOverToTls(nextTag); } else if (nextTag.isStart("success")) { @@ -121,8 +120,6 @@ public class XmppConnection implements Runnable { Log.d(LOGTAG,processMessage(nextTag).toString()); } else if (nextTag.isStart("presence")) { Log.d(LOGTAG,processPresence(nextTag).toString()); - } else if (nextTag.isEnd("stream")) { - break; } else { Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName() + " as child of " + currentTag.getName()); @@ -159,7 +156,12 @@ public class XmppConnection implements Runnable { private IqPacket processIq(Tag currentTag) throws XmlPullParserException, IOException { - return (IqPacket) processPacket(currentTag,PACKET_IQ); + IqPacket packet = (IqPacket) processPacket(currentTag,PACKET_IQ); + if (iqPacketCallbacks.containsKey(packet.getId())) { + iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(packet); + iqPacketCallbacks.remove(packet.getId()); + } + return packet; } private MessagePacket processMessage(Tag currentTag) throws XmlPullParserException, IOException { @@ -212,47 +214,44 @@ public class XmppConnection implements Runnable { private void processStreamFeatures(Tag currentTag) throws XmlPullParserException, IOException { - Log.d(LOGTAG, "processStreamFeatures"); - - Element streamFeatures = new Element("features"); - - Tag nextTag = tagReader.readTag(); - while(!nextTag.isEnd("features")) { - Element element = tagReader.readElement(nextTag); - streamFeatures.addChild(element); - nextTag = tagReader.readTag(); + this.streamFeatures = tagReader.readElement(currentTag); + Log.d(LOGTAG,"process stream features "+streamFeatures); + if (this.streamFeatures.hasChild("starttls")&&shouldUseTLS) { + sendStartTLS(); + } + if (this.streamFeatures.hasChild("mechanisms")&&shouldAuthenticate) { + sendSaslAuth(); + } + if (this.streamFeatures.hasChild("bind")&&shouldBind) { + sendBindRequest(); + if (this.streamFeatures.hasChild("session")) { + IqPacket startSession = new IqPacket(IqPacket.TYPE_SET); + Element session = new Element("session"); + session.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-session"); + session.setContent(""); + startSession.addChild(session); + sendIqPacket(startSession, null); + tagWriter.writeElement(startSession); + tagWriter.flush(); + } + Element presence = new Element("presence"); + + tagWriter.writeElement(presence); + tagWriter.flush(); } - Log.d(LOGTAG,streamFeatures.toString()); } private void sendBindRequest() throws IOException { - IqPacket iq = new IqPacket(nextRandomId(),IqPacket.TYPE_SET); + IqPacket iq = new IqPacket(IqPacket.TYPE_SET); Element bind = new Element("bind"); bind.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-bind"); iq.addChild(bind); - //Element resource = new Element("resource"); - //resource.setContent("mobile"); - //bind.addChild(resource); - Log.d(LOGTAG,"sending bind request: "+iq.toString()); - tagWriter.writeElement(iq); - tagWriter.flush(); - - - //technically not bind stuff - IqPacket startSession = new IqPacket(this.nextRandomId(), IqPacket.TYPE_SET); - Element session = new Element("session"); - session.setAttribute("xmlns","urn:ietf:params:xml:ns:xmpp-session"); - session.setContent(""); - startSession.addChild(session); - - tagWriter.writeElement(startSession); - tagWriter.flush(); - - Element presence = new Element("presence"); - - tagWriter.writeElement(presence); - tagWriter.flush(); - + this.sendIqPacket(iq, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(IqPacket packet) { + Log.d(LOGTAG,"answer for our bind was: "+packet.toString()); + } + }); } private void processStreamError(Tag currentTag) { @@ -273,4 +272,15 @@ public class XmppConnection implements Runnable { private String nextRandomId() { return new BigInteger(50, random).toString(32); } + + public void sendIqPacket(IqPacket packet, OnIqPacketReceived callback) throws IOException { + String id = nextRandomId(); + packet.setAttribute("id",id); + tagWriter.writeElement(packet); + tagWriter.flush(); + if (callback != null) { + iqPacketCallbacks.put(id, callback); + } + Log.d(LOGTAG,"sending: "+packet.toString()); + } }