From d645c435fd2205eb5710f946dc2ed6a4338f3da1 Mon Sep 17 00:00:00 2001 From: str4d <str4d@mail.i2p> Date: Tue, 5 Jan 2016 03:38:26 +0000 Subject: [PATCH] Identicon generation code from Android-Identicons Source: https://github.com/saiimons/Android-Identicons License: Apache License, Version 2.0 --- .../identicons/AsymmetricIdenticon.java | 71 +++++++++++ .../android/identicons/IdenticonBase.java | 120 ++++++++++++++++++ .../android/identicons/IdenticonDrawable.java | 85 +++++++++++++ .../android/identicons/IdenticonView.java | 118 +++++++++++++++++ .../identicons/SymmetricIdenticon.java | 81 ++++++++++++ 5 files changed, 475 insertions(+) create mode 100644 briar-android/src/im/delight/android/identicons/AsymmetricIdenticon.java create mode 100644 briar-android/src/im/delight/android/identicons/IdenticonBase.java create mode 100644 briar-android/src/im/delight/android/identicons/IdenticonDrawable.java create mode 100644 briar-android/src/im/delight/android/identicons/IdenticonView.java create mode 100644 briar-android/src/im/delight/android/identicons/SymmetricIdenticon.java diff --git a/briar-android/src/im/delight/android/identicons/AsymmetricIdenticon.java b/briar-android/src/im/delight/android/identicons/AsymmetricIdenticon.java new file mode 100644 index 0000000000..bce32ff9e1 --- /dev/null +++ b/briar-android/src/im/delight/android/identicons/AsymmetricIdenticon.java @@ -0,0 +1,71 @@ +package im.delight.android.identicons; + +/** + * Copyright 2014 www.delight.im <info@delight.im> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.content.Context; +import android.graphics.Color; +import android.util.AttributeSet; + +public class AsymmetricIdenticon extends IdenticonView { + + private IdenticonBase mDelegate; + + public AsymmetricIdenticon(Context context) { + super(context); + initDelegate(); + } + + public AsymmetricIdenticon(Context context, AttributeSet attrs) { + super(context, attrs); + initDelegate(); + } + + public AsymmetricIdenticon(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initDelegate(); + } + + @Override + protected IdenticonBase getDelegate() { + return mDelegate; + } + + private void initDelegate() { + mDelegate = new IdenticonBase() { + @Override + protected int getRowCount() { + return 4; + } + + @Override + protected int getColumnCount() { + return 4; + } + + @Override + protected boolean isCellVisible(int row, int column) { + return getByte(3 + row * getColumnCount() + column) >= 0; + } + + @Override + protected int getIconColor() { + return Color.rgb(getByte(0) + 128, getByte(1) + 128, getByte(2) + 128); + } + }; + } + +} diff --git a/briar-android/src/im/delight/android/identicons/IdenticonBase.java b/briar-android/src/im/delight/android/identicons/IdenticonBase.java new file mode 100644 index 0000000000..a1a5d5dd30 --- /dev/null +++ b/briar-android/src/im/delight/android/identicons/IdenticonBase.java @@ -0,0 +1,120 @@ +package im.delight.android.identicons; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; + +import java.security.MessageDigest; + +/** + * Created by saiimons on 05/10/14. + */ +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 == null ? new byte[0] : 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; + } + + protected 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); + } + } + } + } +} diff --git a/briar-android/src/im/delight/android/identicons/IdenticonDrawable.java b/briar-android/src/im/delight/android/identicons/IdenticonDrawable.java new file mode 100644 index 0000000000..19a5094b91 --- /dev/null +++ b/briar-android/src/im/delight/android/identicons/IdenticonDrawable.java @@ -0,0 +1,85 @@ +package im.delight.android.identicons; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.Log; + +/** + * Created by saiimons on 05/10/14. + */ +public class IdenticonDrawable extends Drawable { + private IdenticonBase mDelegate; + + private static final int CENTER_COLUMN_INDEX = 3; + + public IdenticonDrawable(String toShow) { + super(); + mDelegate = new IdenticonBase() { + @Override + protected int getRowCount() { + return 5; + } + + @Override + protected int getColumnCount() { + return 5; + } + + @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); + } + }; + mDelegate.show(toShow); + } + + @Override + public void setBounds(Rect bounds) { + super.setBounds(bounds); + Log.d("IDENTICON", "SIZE : " + (bounds.right - bounds.left) + " " + (bounds.bottom - bounds.top)); + mDelegate.updateSize(bounds.right - bounds.left, bounds.bottom - bounds.top); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + mDelegate.updateSize(right - left, bottom - top); + } + + @Override + public void draw(Canvas canvas) { + Log.d("IDENTICON", "DRAW IN PROGRESS"); + mDelegate.draw(canvas); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + + @Override + public int getOpacity() { + return 0; + } + + protected int getSymmetricColumnIndex(int row) { + if (row < CENTER_COLUMN_INDEX) { + return row; + } else { + return mDelegate.getColumnCount() - row - 1; + } + } +} diff --git a/briar-android/src/im/delight/android/identicons/IdenticonView.java b/briar-android/src/im/delight/android/identicons/IdenticonView.java new file mode 100644 index 0000000000..061ba953cb --- /dev/null +++ b/briar-android/src/im/delight/android/identicons/IdenticonView.java @@ -0,0 +1,118 @@ +package im.delight.android.identicons; + +/** + * Copyright 2014 www.delight.im <info@delight.im> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.os.Build; +import android.util.AttributeSet; +import android.view.View; + +abstract public class IdenticonView extends View { + + + public IdenticonView(Context context) { + super(context); + init(); + } + + public IdenticonView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public IdenticonView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + @SuppressLint("NewApi") + protected void init() { + setWillNotDraw(false); + if (Build.VERSION.SDK_INT >= 11) { + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + } + + public void show(String input) { + getDelegate().show(input); + invalidate(); + } + + public void show(int input) { + show(String.valueOf(input)); + } + + public void show(long input) { + show(String.valueOf(input)); + } + + public void show(float input) { + show(String.valueOf(input)); + } + + public void show(double input) { + show(String.valueOf(input)); + } + + public void show(byte input) { + show(String.valueOf(input)); + } + + public void show(char input) { + show(String.valueOf(input)); + } + + public void show(boolean input) { + show(String.valueOf(input)); + } + + public void show(Object input) { + if (input == null) { + getDelegate().show(null); + } else { + show(String.valueOf(input)); + } + } + + protected byte getByte(int index) { + return getDelegate().getByte(index); + } + + abstract protected IdenticonBase getDelegate(); + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + getDelegate().updateSize(w, h); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int size = Math.min(getMeasuredWidth(), getMeasuredHeight()); + setMeasuredDimension(size, size); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + getDelegate().draw(canvas); + } + +} diff --git a/briar-android/src/im/delight/android/identicons/SymmetricIdenticon.java b/briar-android/src/im/delight/android/identicons/SymmetricIdenticon.java new file mode 100644 index 0000000000..170ed77ef5 --- /dev/null +++ b/briar-android/src/im/delight/android/identicons/SymmetricIdenticon.java @@ -0,0 +1,81 @@ +package im.delight.android.identicons; + +/** + * Copyright 2014 www.delight.im <info@delight.im> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.content.Context; +import android.graphics.Color; +import android.util.AttributeSet; + +public class SymmetricIdenticon extends IdenticonView { + + private static final int CENTER_COLUMN_INDEX = 3; + + private IdenticonBase mDelegate; + + public SymmetricIdenticon(Context context) { + super(context); + initDelegate(); + } + + public SymmetricIdenticon(Context context, AttributeSet attrs) { + super(context, attrs); + initDelegate(); + } + + public SymmetricIdenticon(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initDelegate(); + } + + private void initDelegate() { + mDelegate = new IdenticonBase() { + @Override + protected int getRowCount() { + return 5; + } + + @Override + protected int getColumnCount() { + return 5; + } + + @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); + } + }; + } + + @Override + protected IdenticonBase getDelegate() { + return mDelegate; + } + + protected int getSymmetricColumnIndex(int row) { + if (row < CENTER_COLUMN_INDEX) { + return row; + } else { + return getDelegate().getColumnCount() - row - 1; + } + } + +} -- GitLab