diff options
Diffstat (limited to 'src/eu/siacs')
6 files changed, 244 insertions, 2 deletions
diff --git a/src/eu/siacs/conversations/persistance/FileBackend.java b/src/eu/siacs/conversations/persistance/FileBackend.java index 1ee68a27..8895a2c8 100644 --- a/src/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/eu/siacs/conversations/persistance/FileBackend.java @@ -1,5 +1,7 @@ package eu.siacs.conversations.persistance; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -7,19 +9,28 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.RectF; import android.media.ExifInterface; import android.net.Uri; +import android.util.Base64; +import android.util.Base64OutputStream; import android.util.Log; import android.util.LruCache; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xmpp.jingle.JingleFile; +import eu.siacs.conversations.xmpp.pep.Avatar; public class FileBackend { @@ -215,10 +226,102 @@ public class FileBackend { public File getIncomingFile() { return new File(context.getFilesDir().getAbsolutePath() + "/incoming"); } - + public Uri getIncomingUri() { return Uri.parse(context.getFilesDir().getAbsolutePath() + "/incoming"); } + + public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) { + try { + Avatar avatar = new Avatar(); + Bitmap bm = cropCenterSquare(image, size); + ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream(); + Base64OutputStream mBase64OutputSttream = new Base64OutputStream(mByteArrayOutputStream, Base64.DEFAULT); + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + DigestOutputStream mDigestOutputStream = new DigestOutputStream(mBase64OutputSttream, digest); + bm.compress(format, 75, mDigestOutputStream); + avatar.sha1sum = CryptoHelper.bytesToHex(digest.digest()); + avatar.image = new String(mByteArrayOutputStream.toByteArray()); + return avatar; + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + public void save(Avatar avatar) { + String path = context.getFilesDir().getAbsolutePath() + "/avatars/"; + File file = new File(path+"/"+avatar.getFilename()); + file.getParentFile().mkdirs(); + Log.d("xmppService",file.getAbsolutePath()); + try { + file.createNewFile(); + FileOutputStream mFileOutputStream = new FileOutputStream(file); + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + DigestOutputStream mDigestOutputStream = new DigestOutputStream(mFileOutputStream, digest); + mDigestOutputStream.write(avatar.getImageAsBytes()); + mDigestOutputStream.flush(); + mDigestOutputStream.close(); + Log.d("xmppService","sha1sum after write: "+CryptoHelper.bytesToHex(digest.digest())); + } catch (FileNotFoundException e) { + + } catch (IOException e) { + Log.d("xmppService",e.getMessage()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public Bitmap cropCenterSquare(Uri image, int size) { + try { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = calcSampleSize(image, size); + InputStream is = context.getContentResolver() + .openInputStream(image); + Bitmap input = BitmapFactory.decodeStream(is, null, options); + int w = input.getWidth(); + int h = input.getHeight(); + + float scale = Math.max((float) size / h, (float) size / w); + + float outWidth = scale * w; + float outHeight = scale * h; + float left = (size - outWidth) / 2; + float top = (size - outHeight) / 2; + RectF target = new RectF(left, top, left + outWidth, top + + outHeight); + + Bitmap output = Bitmap.createBitmap(size, size, input.getConfig()); + Canvas canvas = new Canvas(output); + canvas.drawBitmap(input, null, target, null); + return output; + } catch (FileNotFoundException e) { + return null; + } + } + + private int calcSampleSize(Uri image, int size) + throws FileNotFoundException { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(context.getContentResolver() + .openInputStream(image), null, options); + int height = options.outHeight; + int width = options.outWidth; + int inSampleSize = 1; + + if (height > size || width > size) { + int halfHeight = height / 2; + int halfWidth = width / 2; + + while ((halfHeight / inSampleSize) > size + && (halfWidth / inSampleSize) > size) { + inSampleSize *= 2; + } + } + return inSampleSize; + + } public class ImageCopyException extends Exception { private static final long serialVersionUID = -1010013599132881427L; diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java index 3f9b3bfb..4ba0954f 100644 --- a/src/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/eu/siacs/conversations/services/XmppConnectionService.java @@ -53,6 +53,7 @@ import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; +import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; @@ -64,6 +65,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.ContentObserver; +import android.graphics.Bitmap; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; @@ -1183,6 +1185,17 @@ public class XmppConnectionService extends Service { } } + + public void pushAvatar(Account account, Uri image) { + Avatar avatar = getFileBackend().getPepAvatar(image, 192, Bitmap.CompressFormat.WEBP); + if (avatar!=null) { + Log.d(LOGTAG,avatar.sha1sum); + Log.d(LOGTAG,avatar.image); + avatar.type = "image/webp"; + getFileBackend().save(avatar); + } + } + public void deleteContactOnServer(Contact contact) { contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); contact.resetOption(Contact.Options.DIRTY_PUSH); diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java index 15f904c3..105275ce 100644 --- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -99,6 +99,8 @@ public class ManageAccountActivity extends XmppActivity { xmppConnectionService .updateAccount(selectedAccountForActionMode); mode.finish(); + } else if (item.getItemId() == R.id.mgmt_account_publish_avatar) { + startActivity(new Intent(getApplicationContext(), PublishProfilePictureActivity.class)); } else if (item.getItemId() == R.id.mgmt_account_delete) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(getString(R.string.mgmt_account_are_you_sure)); diff --git a/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java new file mode 100644 index 00000000..0e369a97 --- /dev/null +++ b/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -0,0 +1,101 @@ +package eu.siacs.conversations.ui; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import eu.siacs.conversations.R; +import eu.siacs.conversations.utils.PhoneHelper; + +public class PublishProfilePictureActivity extends XmppActivity { + + private static final int REQUEST_CHOOSE_FILE = 0xac23; + + private ImageView avatar; + private TextView explanation; + private Button cancelButton; + private Button publishButton; + + private Uri avatarUri; + + @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.publishButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (avatarUri!=null) { + xmppConnectionService.pushAvatar(null, avatarUri); + finish(); + } + } + }); + 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(); + attachFileIntent.setType("image/*"); + attachFileIntent.setAction(Intent.ACTION_GET_CONTENT); + Intent chooser = Intent.createChooser(attachFileIntent, + getString(R.string.attach_file)); + startActivityForResult(chooser, REQUEST_CHOOSE_FILE); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.d("xmppService","on activity result"); + if (resultCode == RESULT_OK) { + if (requestCode == REQUEST_CHOOSE_FILE) { + Log.d("xmppService","bla"); + this.avatarUri = data.getData(); + } + } + } + + @Override + protected void onBackendConnected() { + Log.d("xmppService","on backend connected"); + if (this.avatarUri == null) { + avatarUri = PhoneHelper.getSefliUri(getApplicationContext()); + } + loadImageIntoPreview(avatarUri); + String explainText = getString(R.string.publish_avatar_explanation,"daniel@gultsch.de"); + this.explanation.setText(explainText); + } + + protected void loadImageIntoPreview(Uri uri) { + Bitmap bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, 384); + this.avatar.setImageBitmap(bm); + enablePublishButton(); + } + + protected void enablePublishButton() { + this.publishButton.setEnabled(true); + this.publishButton.setTextColor(getPrimaryTextColor()); + } + +} diff --git a/src/eu/siacs/conversations/utils/PhoneHelper.java b/src/eu/siacs/conversations/utils/PhoneHelper.java index 67623ea3..63c17761 100644 --- a/src/eu/siacs/conversations/utils/PhoneHelper.java +++ b/src/eu/siacs/conversations/utils/PhoneHelper.java @@ -70,7 +70,7 @@ public class PhoneHelper { public static Uri getSefliUri(Context context) { String[] mProjection = new String[] { Profile._ID, - Profile.PHOTO_THUMBNAIL_URI }; + Profile.PHOTO_URI }; Cursor mProfileCursor = context.getContentResolver().query( Profile.CONTENT_URI, mProjection, null, null, null); diff --git a/src/eu/siacs/conversations/xmpp/pep/Avatar.java b/src/eu/siacs/conversations/xmpp/pep/Avatar.java new file mode 100644 index 00000000..196c876c --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/pep/Avatar.java @@ -0,0 +1,23 @@ +package eu.siacs.conversations.xmpp.pep; + +import android.util.Base64; + +public class Avatar { + public String type; + public String sha1sum; + public String image; + public byte[] getImageAsBytes() { + return Base64.decode(image, Base64.DEFAULT); + } + public String getFilename() { + if (type==null) { + return sha1sum; + } else if (type.equalsIgnoreCase("image/webp")) { + return sha1sum+".webp"; + } else if (type.equalsIgnoreCase("image/png")) { + return sha1sum+".png"; + } else { + return sha1sum; + } + } +} |