Identicons for EmailDestinations with no associated picture

Identicon generation code adapted from Android-Identicons
Source: https://github.com/saiimons/Android-Identicons
License: Apache License, Version 2.0
This commit is contained in:
str4d
2014-10-22 11:28:05 +00:00
parent 9060a0f572
commit 6ceaca86f2
9 changed files with 242 additions and 52 deletions

View File

@@ -84,6 +84,10 @@ public class EmailListAdapter extends ArrayAdapter<Email> {
Bitmap pic = BoteHelper.getPictureForAddress(otherAddress);
if (pic != null)
picture.setImageBitmap(pic);
else if (!email.isAnonymous()) {
ViewGroup.LayoutParams lp = picture.getLayoutParams();
picture.setImageBitmap(BoteHelper.getIdenticonForAddress(otherAddress, lp.width, lp.height));
}
subject.setText(email.getSubject());
address.setText(BoteHelper.getNameAndShortDestination(otherAddress));

View File

@@ -1,15 +1,5 @@
package i2p.bote.android;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import javax.mail.Address;
import javax.mail.MessagingException;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.email.Email;
import i2p.bote.fileencryption.PasswordException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -25,6 +15,17 @@ import android.widget.LinearLayout;
import android.widget.TableRow;
import android.widget.TextView;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import javax.mail.Address;
import javax.mail.MessagingException;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.email.Email;
import i2p.bote.fileencryption.PasswordException;
public class ViewEmailFragment extends Fragment {
private String mFolderName;
private String mMessageId;
@@ -89,6 +90,10 @@ public class ViewEmailFragment extends Fragment {
Bitmap pic = BoteHelper.getPictureForAddress(fromAddress);
if (pic != null)
picture.setImageBitmap(pic);
else if (!email.isAnonymous()) {
ViewGroup.LayoutParams lp = picture.getLayoutParams();
picture.setImageBitmap(BoteHelper.getIdenticonForAddress(fromAddress, lp.width, lp.height));
}
sender.setText(BoteHelper.getDisplayAddress(fromAddress));

View File

@@ -1,11 +1,5 @@
package i2p.bote.android.addressbook;
import i2p.bote.android.R;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.packet.dht.Contact;
import java.util.SortedSet;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -14,6 +8,12 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.SortedSet;
import i2p.bote.android.R;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.packet.dht.Contact;
public class ContactAdapter extends ArrayAdapter<Contact> {
private final LayoutInflater mInflater;
@@ -42,6 +42,10 @@ public class ContactAdapter extends ArrayAdapter<Contact> {
String pic = contact.getPictureBase64();
if (pic != null && !pic.isEmpty())
picture.setImageBitmap(BoteHelper.decodePicture(pic));
else {
ViewGroup.LayoutParams lp = picture.getLayoutParams();
picture.setImageBitmap(BoteHelper.getIdenticonForAddress(contact.getBase64Dest(), lp.width, lp.height));
}
name.setText(contact.getName());

View File

@@ -95,6 +95,10 @@ public class ViewContactFragment extends Fragment {
Bitmap picture = BoteHelper.decodePicture(mContact.getPictureBase64());
if (picture != null)
mContactPicture.setImageBitmap(picture);
else {
ViewGroup.LayoutParams lp = mContactPicture.getLayoutParams();
mContactPicture.setImageBitmap(BoteHelper.getIdenticonForAddress(mDestination, lp.width, lp.height));
}
mNameField.setText(mContact.getName());
mTextField.setText(mContact.getText());

View File

@@ -106,6 +106,10 @@ public class ViewIdentityFragment extends Fragment {
Bitmap picture = BoteHelper.decodePicture(mIdentity.getPictureBase64());
if (picture != null)
mIdentityPicture.setImageBitmap(picture);
else {
ViewGroup.LayoutParams lp = mIdentityPicture.getLayoutParams();
mIdentityPicture.setImageBitmap(BoteHelper.getIdenticonForAddress(mKey, lp.width, lp.height));
}
mNameField.setText(mIdentity.getPublicName());
mDescField.setText(mIdentity.getDescription());

View File

@@ -1,29 +1,5 @@
package i2p.bote.android.service;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.List;
import javax.mail.MessagingException;
import net.i2p.android.router.service.IRouterState;
import net.i2p.android.router.service.IRouterStateCallback;
import net.i2p.android.router.service.State;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.RouterLaunch;
import i2p.bote.I2PBote;
import i2p.bote.android.EmailListActivity;
import i2p.bote.android.R;
import i2p.bote.android.ViewEmailActivity;
import i2p.bote.android.service.Init.RouterChoice;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.email.Email;
import i2p.bote.fileencryption.PasswordException;
import i2p.bote.folder.EmailFolder;
import i2p.bote.folder.NewEmailListener;
import i2p.bote.network.NetworkStatusListener;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
@@ -36,6 +12,31 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import net.i2p.android.router.service.IRouterState;
import net.i2p.android.router.service.IRouterStateCallback;
import net.i2p.android.router.service.State;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.RouterLaunch;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.List;
import javax.mail.MessagingException;
import i2p.bote.I2PBote;
import i2p.bote.android.EmailListActivity;
import i2p.bote.android.R;
import i2p.bote.android.ViewEmailActivity;
import i2p.bote.android.service.Init.RouterChoice;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.email.Email;
import i2p.bote.fileencryption.PasswordException;
import i2p.bote.folder.EmailFolder;
import i2p.bote.folder.NewEmailListener;
import i2p.bote.network.NetworkStatusListener;
public class BoteService extends Service implements NetworkStatusListener, NewEmailListener {
public static final String ROUTER_CHOICE = "router_choice";
public static final int NOTIF_ID_SERVICE = 8073;
@@ -235,14 +236,17 @@ public class BoteService extends Service implements NetworkStatusListener, NewEm
case 1:
Email email = newEmails.get(0);
Bitmap picture = BoteHelper.getPictureForAddress(email.getOneFromAddress());
String fromAddress = email.getOneFromAddress();
Bitmap picture = BoteHelper.getPictureForAddress(fromAddress);
if (picture != null)
b.setLargeIcon(picture);
else if (!email.isAnonymous())
b.setLargeIcon(BoteHelper.getIdenticonForAddress(fromAddress, 56, 56)); // TODO fix size
else
b.setSmallIcon(R.drawable.ic_contact_picture);
b.setContentTitle(BoteHelper.getNameAndShortDestination(
email.getOneFromAddress()));
fromAddress));
b.setContentText(email.getSubject());
Intent vei = new Intent(this, ViewEmailActivity.class);

View File

@@ -1,15 +1,5 @@
package i2p.bote.android.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Iterator;
import java.util.List;
import javax.mail.Address;
import javax.mail.Flags.Flag;
import javax.mail.MessagingException;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
@@ -18,6 +8,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.view.LayoutInflater;
@@ -29,6 +20,16 @@ import android.widget.TextView;
import com.lambdaworks.codec.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Iterator;
import java.util.List;
import javax.mail.Address;
import javax.mail.Flags.Flag;
import javax.mail.MessagingException;
import i2p.bote.android.R;
import i2p.bote.email.Email;
import i2p.bote.email.EmailDestination;
@@ -38,6 +39,7 @@ import i2p.bote.folder.EmailFolder;
import i2p.bote.folder.Outbox.EmailStatus;
import i2p.bote.packet.dht.Contact;
import i2p.bote.util.GeneralHelper;
import im.delight.android.identicons.Identicon;
public class BoteHelper extends GeneralHelper {
/**
@@ -172,6 +174,17 @@ public class BoteHelper extends GeneralHelper {
return new String(Base64.encode(baos.toByteArray()));
}
public static Bitmap getIdenticonForAddress(String address, int width, int height) {
String base64dest = extractEmailDestination(address);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Identicon identicon = new Identicon();
identicon.show(base64dest == null ? address : base64dest);
identicon.updateSize(canvas.getWidth(), canvas.getHeight());
identicon.draw(canvas);
return bitmap;
}
public static boolean isSentEmail(Email email) throws PasswordException, IOException, GeneralSecurityException, MessagingException {
// Is the sender anonymous and we are not the recipient?
if (email.isAnonymous()) {

View File

@@ -0,0 +1,35 @@
package im.delight.android.identicons;
import android.graphics.Color;
public class Identicon extends IdenticonBase {
private static final int CENTER_COLUMN_INDEX = 3;
@Override
protected int getRowCount() {
return 5;
}
@Override
protected int getColumnCount() {
return 5;
}
protected int getSymmetricColumnIndex(int row) {
if (row < CENTER_COLUMN_INDEX) {
return row;
} else {
return getColumnCount() - row - 1;
}
}
@Override
protected boolean isCellVisible(int row, int column) {
return getByte(3 + row * CENTER_COLUMN_INDEX + getSymmetricColumnIndex(column)) >= 0;
}
@Override
protected int getIconColor() {
return Color.rgb(getByte(0) + 128, getByte(1) + 128, getByte(2) + 128);
}
}

View File

@@ -0,0 +1,117 @@
package im.delight.android.identicons;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import java.security.MessageDigest;
public abstract class IdenticonBase {
private static final String HASH_ALGORITHM = "SHA-256";
private final int mRowCount;
private final int mColumnCount;
private final Paint mPaint;
private volatile int mCellWidth;
private volatile int mCellHeight;
private volatile byte[] mHash;
private volatile int[][] mColors;
private volatile boolean mReady;
public IdenticonBase() {
mRowCount = getRowCount();
mColumnCount = getColumnCount();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
}
public static byte[] getHash(String input) {
byte[] mHash;
// if the input was null
if (input == null) {
// we can't create a hash value and have nothing to show (draw to the view)
mHash = null;
}
// if the input was a proper string (non-null)
else {
// generate a hash from the string to get unique but deterministic byte values
try {
final MessageDigest digest = java.security.MessageDigest.getInstance(HASH_ALGORITHM);
digest.update(input.getBytes());
mHash = digest.digest();
} catch (Exception e) {
mHash = null;
}
}
return mHash;
}
protected void setupColors() {
mColors = new int[mRowCount][mColumnCount];
int colorVisible = getIconColor();
for (int r = 0; r < mRowCount; r++) {
for (int c = 0; c < mColumnCount; c++) {
if (isCellVisible(r, c)) {
mColors[r][c] = colorVisible;
} else {
mColors[r][c] = Color.TRANSPARENT;
}
}
}
}
public void show(String input) {
if (input != null) {
mHash = IdenticonBase.getHash(input);
} else {
mHash = null;
}
// set up the cell colors according to the input that was provided via show(...)
setupColors();
// this view may now be drawn (and thus must be re-drawn)
mReady = true;
}
public byte getByte(int index) {
if (mHash == null) {
return -128;
} else {
return mHash[index % mHash.length];
}
}
abstract protected int getRowCount();
abstract protected int getColumnCount();
abstract protected boolean isCellVisible(int row, int column);
abstract protected int getIconColor();
public void updateSize(int w, int h) {
mCellWidth = w / mColumnCount;
mCellHeight = h / mRowCount;
}
public void draw(Canvas canvas) {
if (mReady) {
int x, y;
for (int r = 0; r < mRowCount; r++) {
for (int c = 0; c < mColumnCount; c++) {
x = mCellWidth * c;
y = mCellHeight * r;
mPaint.setColor(mColors[r][c]);
canvas.drawRect(x, y + mCellHeight, x + mCellWidth, y, mPaint);
}
}
}
}
}