publish avatars

This commit is contained in:
iNPUTmice 2014-08-05 01:36:17 +02:00
parent 629ff3afcd
commit f8b4d5f338
12 changed files with 197 additions and 35 deletions

View file

@ -75,13 +75,20 @@
android:paddingLeft="8dp"
android:paddingRight="8dp" >
<TextView
android:id="@+id/account"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/primarytext"
android:textSize="18sp"/>
<TextView
android:id="@+id/explanation"
android:layout_marginTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/publish_avatar_explanation"
android:textColor="@color/primarytext"
android:textSize="18sp" />
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

View file

@ -270,5 +270,5 @@
<string name="contact_has_read_up_to_this_point">%s has read up to this point</string>
<string name="publish_avatar">Publish avatar</string>
<string name="touch_to_choose_picture">Touch avatar to select picture from gallary</string>
<string name="publish_avatar_explanation">Publish avatar for <b>%s</b>. Everyone subscribed to your presence updates will also be able to see this picture.</string>
<string name="publish_avatar_explanation">Please note: Everyone subscribed to your presence updates will be allowed to see this picture.</string>
</resources>

View file

@ -18,7 +18,8 @@ public abstract class AbstractGenerator {
"http://jabber.org/protocol/muc",
"jabber:x:conference",
"http://jabber.org/protocol/caps",
"http://jabber.org/protocol/disco#info"};
"http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify"};
public final String IDENTITY_NAME = "Conversations 0.5";
public final String IDENTITY_TYPE = "phone";
/*public final String[] FEATURES = { "http://jabber.org/protocol/muc","http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/caps" };

View file

@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.List;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.pep.Avatar;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class IqGenerator extends AbstractGenerator {
@ -28,4 +29,34 @@ public class IqGenerator extends AbstractGenerator {
}
return packet;
}
protected IqPacket publish(String node, Element item) {
IqPacket packet = new IqPacket(IqPacket.TYPE_SET);
Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub");
Element publish = pubsub.addChild("publish");
publish.setAttribute("node", node);
publish.addChild(item);
return packet;
}
public IqPacket publishAvatar(Avatar avatar) {
Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
Element data = item.addChild("data","urn:xmpp:avatar:data");
data.setContent(avatar.image);
return publish("urn:xmpp:avatar:data", item);
}
public IqPacket publishAvatarMetadata(Avatar avatar) {
Element item = new Element("item");
item.setAttribute("id", avatar.sha1sum);
Element metadata = item.addChild("metadata","urn:xmpp:avatar:metadata");
Element info = metadata.addChild("info");
info.setAttribute("bytes",avatar.size);
info.setAttribute("id",avatar.sha1sum);
info.setAttribute("height",avatar.height);
info.setAttribute("width",avatar.height);
info.setAttribute("type", avatar.type);
return publish("urn:xmpp:avatar:metadata",item);
}
}

View file

@ -1,6 +1,7 @@
package eu.siacs.conversations.parser;
import android.os.SystemClock;
import android.util.Log;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.entities.Account;
@ -213,6 +214,10 @@ public class MessageParser extends AbstractParser implements
}
private void parseNormal(Element packet, Account account) {
if (packet.hasChild("event","http://jabber.org/protocol/pubsub#event")) {
Element event = packet.findChild("event","http://jabber.org/protocol/pubsub#event");
parseEvent(event,packet.getAttribute("from"),account);
}
if (packet.hasChild("displayed", "urn:xmpp:chat-markers:0")) {
String id = packet
.findChild("displayed", "urn:xmpp:chat-markers:0")
@ -254,6 +259,16 @@ public class MessageParser extends AbstractParser implements
}
}
private void parseEvent(Element event, String from, Account account) {
Element items = event.findChild("items");
String node = items.getAttribute("node");
if (node!=null) {
Log.d("xmppService",account.getJid()+": "+node+" from "+from);
} else {
Log.d("xmppService",event.toString());
}
}
private String getPgpBody(Element message) {
Element child = message.findChild("x", "jabber:x:encrypted");
if (child == null) {
@ -324,6 +339,9 @@ public class MessageParser extends AbstractParser implements
} else if (packet.getType() == MessagePacket.TYPE_NORMAL) {
this.parseNormal(packet, account);
return;
} else if (packet.getType() == MessagePacket.TYPE_HEADLINE) {
this.parseHeadline(packet, account);
return;
}
if ((message == null) || (message.getBody() == null)) {
return;
@ -346,4 +364,11 @@ public class MessageParser extends AbstractParser implements
}
mXmppConnectionService.notifyUi(conversation, notify);
}
private void parseHeadline(MessagePacket packet, Account account) {
if (packet.hasChild("event","http://jabber.org/protocol/pubsub#event")) {
Element event = packet.findChild("event","http://jabber.org/protocol/pubsub#event");
parseEvent(event,packet.getFrom(),account);
}
}
}

View file

@ -261,7 +261,7 @@ public class FileBackend {
mDigestOutputStream.write(avatar.getImageAsBytes());
mDigestOutputStream.flush();
mDigestOutputStream.close();
Log.d("xmppService","sha1sum after write: "+CryptoHelper.bytesToHex(digest.digest()));
avatar.size = file.length();
} catch (FileNotFoundException e) {
} catch (IOException e) {

View file

@ -0,0 +1,11 @@
package eu.siacs.conversations.services;
import android.graphics.Bitmap;
public final class Defaults {
public static final int AVATAR_SIZE = 192;
public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
private Defaults() {
}
}

View file

@ -20,6 +20,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Bookmark;
@ -1186,13 +1187,46 @@ public class XmppConnectionService extends Service {
}
public void pushAvatar(Account account, Uri image) {
Avatar avatar = getFileBackend().getPepAvatar(image, 192, Bitmap.CompressFormat.WEBP);
public void publishAvatar(Account account, Uri image, final UiCallback<Avatar> callback) {
final Bitmap.CompressFormat format = Defaults.AVATAR_FORMAT;
final int size = Defaults.AVATAR_SIZE;
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
if (avatar!=null) {
Log.d(LOGTAG,avatar.sha1sum);
Log.d(LOGTAG,avatar.image);
avatar.type = "image/webp";
avatar.height = size;
avatar.width = size;
if (format.equals(Bitmap.CompressFormat.WEBP)) {
avatar.type = "image/webp";
} else if (format.equals(Bitmap.CompressFormat.JPEG)) {
avatar.type = "image/jpeg";
} else if (format.equals(Bitmap.CompressFormat.PNG)) {
avatar.type = "image/png";
}
getFileBackend().save(avatar);
IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
if (result.getType() == IqPacket.TYPE_RESULT) {
IqPacket packet = XmppConnectionService.this.mIqGenerator.publishAvatarMetadata(avatar);
sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
if (result.getType() == IqPacket.TYPE_RESULT) {
callback.success(avatar);
} else {
callback.error(R.string.error, avatar);
}
}
});
} else {
callback.error(R.string.error, avatar);
}
}
});
} else {
callback.error(R.string.error, null);
}
}

View file

@ -1,10 +1,11 @@
package eu.siacs.conversations.ui;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@ -13,47 +14,69 @@ import android.widget.TextView;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.xmpp.pep.Avatar;
public class PublishProfilePictureActivity extends XmppActivity {
private static final int REQUEST_CHOOSE_FILE = 0xac23;
private ImageView avatar;
private TextView explanation;
private TextView accountTextView;
private Button cancelButton;
private Button publishButton;
private Uri avatarUri;
private Account account;
private UiCallback<Avatar> avatarPublication = new UiCallback<Avatar>() {
@Override
public void success(Avatar object) {
finish();
}
@Override
public void error(int errorCode, Avatar object) {
// TODO Auto-generated method stub
}
@Override
public void userInputRequried(PendingIntent pi, Avatar object) {
// TODO Auto-generated method stub
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_publish_profile_picture);
this.avatar = (ImageView) findViewById(R.id.account_image);
this.explanation = (TextView) findViewById(R.id.explanation);
this.cancelButton = (Button) findViewById(R.id.cancel_button);
this.publishButton = (Button) findViewById(R.id.publish_button);
this.accountTextView = (TextView) findViewById(R.id.account);
this.publishButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (avatarUri!=null) {
xmppConnectionService.pushAvatar(account, avatarUri);
finish();
if (avatarUri != null) {
disablePublishButton();
xmppConnectionService.publishAvatar(account, avatarUri,
avatarPublication);
}
}
});
this.cancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
this.avatar.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent attachFileIntent = new Intent();
@ -65,45 +88,61 @@ public class PublishProfilePictureActivity extends XmppActivity {
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_CHOOSE_FILE) {
Log.d("xmppService","bla");
this.avatarUri = data.getData();
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
super.onOptionsItemSelected(menuItem);
switch (menuItem.getItemId()) {
case android.R.id.home:
finish();
break;
}
return true;
}
@Override
protected void onBackendConnected() {
if (getIntent()!=null) {
if (getIntent() != null) {
String jid = getIntent().getStringExtra("account");
if (jid!=null) {
if (jid != null) {
this.account = xmppConnectionService.findAccountByJid(jid);
if (this.avatarUri == null) {
avatarUri = PhoneHelper.getSefliUri(getApplicationContext());
avatarUri = PhoneHelper
.getSefliUri(getApplicationContext());
}
loadImageIntoPreview(avatarUri);
String explainText = getString(R.string.publish_avatar_explanation,account.getJid());
this.explanation.setText(explainText);
this.accountTextView.setText(this.account.getJid());
}
}
}
protected void loadImageIntoPreview(Uri uri) {
Bitmap bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, 384);
Bitmap bm = xmppConnectionService.getFileBackend().cropCenterSquare(
uri, 384);
this.avatar.setImageBitmap(bm);
enablePublishButton();
}
protected void enablePublishButton() {
this.publishButton.setEnabled(true);
this.publishButton.setTextColor(getPrimaryTextColor());
}
protected void disablePublishButton() {
this.publishButton.setEnabled(false);
this.publishButton.setTextColor(getSecondaryTextColor());
}
}

View file

@ -144,4 +144,12 @@ public class Element {
public void clearChildren() {
this.children.clear();
}
public void setAttribute(String name, long value) {
this.setAttribute(name, ""+value);
}
public void setAttribute(String name, int value) {
this.setAttribute(name, ""+value);
}
}

View file

@ -6,6 +6,9 @@ public class Avatar {
public String type;
public String sha1sum;
public String image;
public int height;
public int width;
public long size;
public byte[] getImageAsBytes() {
return Base64.decode(image, Base64.DEFAULT);
}

View file

@ -8,6 +8,7 @@ public class MessagePacket extends AbstractStanza {
public static final int TYPE_NORMAL = 2;
public static final int TYPE_GROUPCHAT = 3;
public static final int TYPE_ERROR = 4;
public static final int TYPE_HEADLINE = 5;
public MessagePacket() {
super("message");
@ -59,6 +60,8 @@ public class MessagePacket extends AbstractStanza {
return TYPE_GROUPCHAT;
} else if (type.equals("error")) {
return TYPE_ERROR;
} else if (type.equals("headline")) {
return TYPE_HEADLINE;
} else {
return TYPE_UNKNOWN;
}