Skip to content

Instantly share code, notes, and snippets.

@akbarsha03
Last active July 13, 2016 16:11
Show Gist options
  • Save akbarsha03/b5e51e31b8c701c6c66b to your computer and use it in GitHub Desktop.
Save akbarsha03/b5e51e31b8c701c6c66b to your computer and use it in GitHub Desktop.
Pattern Locker
<declare-styleable name="KustamPidichaLockPattern">
<attr name="nodeSrc" format="color|reference" />
<attr name="nodeOnSrc" format="color|reference" />
<attr name="lineColor" format="color" />
<attr name="lineWidth" format="dimension" />
</declare-styleable>
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* <P> Android-Lock9View </p>
* <P> Squares lock screen view components, provide a squared gesture view screen lock feature.
* </p>
* <P> gesture processing and wire drawing have internal components, you simply need to bind this
* component and set callback object can be accomplished after the gesture. </p>
* <P> Please use setCallBack (CallBack callBack) function sets the callback object. </p>
* <P> It should be noted that regardless of the setting, the height of the component is always
* equal to the width. </p>
* author TakWolf (<a href="mailto:[email protected]"> [email protected] </a>)
* <p/>
* Modified by Akbar Sha Ebrahim (<a href="mailto:[email protected]"> [email protected]</a>) on 5/28/2015.
*/
public class KustamPidichaLockPattern extends ViewGroup {
private Vibrator vibrator;
private Paint paint;
private Bitmap bitmap;
private Canvas canvas;
private List<Pair<NodeView, NodeView>> lineList;
private NodeView currentNode;
private StringBuilder pwdSb;
private CallBack callBack;
private Drawable nodeSrc;
private Drawable nodeOnSrc;
public KustamPidichaLockPattern(Context context) {
this(context, null);
}
public KustamPidichaLockPattern(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public KustamPidichaLockPattern(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public KustamPidichaLockPattern(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr); // TODO api 21
initFromAttributes(attrs, defStyleAttr);
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
private void initFromAttributes(AttributeSet attrs, int defStyleAttr) {
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.KustamPidichaLockPattern, defStyleAttr, 0);
nodeSrc = a.getDrawable(R.styleable.KustamPidichaLockPattern_nodeSrc);
nodeOnSrc = a.getDrawable(R.styleable.KustamPidichaLockPattern_nodeOnSrc);
int lineColor = Color.argb(0, 0, 0, 0);
lineColor = a.getColor(R.styleable.KustamPidichaLockPattern_lineColor, lineColor);
float lineWidth = 20.0f;
lineWidth = a.getDimension(R.styleable.KustamPidichaLockPattern_lineWidth, lineWidth);
a.recycle();
paint = new Paint(Paint.DITHER_FLAG);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(lineWidth);
paint.setColor(lineColor);
paint.setAntiAlias(true);
DisplayMetrics dm = getResources().getDisplayMetrics(); // Bitmap width is the screen width, enough to use
bitmap = Bitmap.createBitmap(dm.widthPixels, dm.widthPixels, Bitmap.Config.ARGB_8888);
canvas = new Canvas();
canvas.setBitmap(bitmap);
for (int n = 0; n < 9; n++) {
NodeView node = new NodeView(getContext(), n + 1);
addView(node);
}
lineList = new ArrayList<Pair<NodeView, NodeView>>();
pwdSb = new StringBuilder();
// Clear FLAG, otherwise onDraw () is not called, because the ViewGroup default transparent
// background need to call onDraw ()
setWillNotDraw(false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec); // We let the height equal to the width
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (!changed) {
return;
}
int width = right - left;
int nodeWidth = width / 3;
int nodePadding = nodeWidth / 6;
for (int n = 0; n < 9; n++) {
NodeView node = (NodeView) getChildAt(n);
int row = n / 3;
int col = n % 3;
int l = col * nodeWidth + nodePadding;
int t = row * nodeWidth + nodePadding;
int r = col * nodeWidth + nodeWidth - nodePadding;
int b = row * nodeWidth + nodeWidth - nodePadding;
node.layout(l, t, r, b);
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
NodeView nodeAt = getNodeAt(event.getX(), event.getY());
if (nodeAt == null && currentNode == null) { // Do not need to draw the line, not before the point of contact, there is no point of contact current
return true;
} else { // Need to draw the line
clearScreenAndDrawList(); // Clear all images, if you already have cable, then redrawn
if (currentNode == null) { // The first point is not null nodeAt
currentNode = nodeAt;
currentNode.setHighLighted(true);
pwdSb.append(currentNode.getNum());
vibrator.vibrate(100);
} else if (nodeAt == null || nodeAt.isHighLighted()) { // Has been a bit up, is currently not touch the new point
// To currentNode center and current touch point to start the line
canvas.drawLine(currentNode.getCenterX(), currentNode.getCenterY(), event.getX(), event.getY(), paint);
} else { // Move to a new point
canvas.drawLine(currentNode.getCenterX(), currentNode.getCenterY(), nodeAt.getCenterX(), nodeAt.getCenterY(), paint);// Draw a line
nodeAt.setHighLighted(true);
Pair<NodeView, NodeView> pair = new Pair<NodeView, NodeView>(currentNode, nodeAt);
lineList.add(pair);
// Assign the current node
currentNode = nodeAt;
pwdSb.append(currentNode.getNum());
vibrator.vibrate(100);
}
// Redraw notice onDraw
invalidate();
}
return true;
case MotionEvent.ACTION_UP:
// Not a touch point
if (pwdSb.length() <= 0) {
return super.onTouchEvent(event);
}
// Callback Results
if (callBack != null) {
callBack.onFinish(pwdSb.toString());
pwdSb.setLength(0); // Clear
}
// Set empty save point
currentNode = null;
lineList.clear();
clearScreenAndDrawList();
// Clear Highlight
for (int n = 0; n < getChildCount(); n++) {
NodeView node = (NodeView) getChildAt(n);
node.setHighLighted(false);
}
// Redraw notice onDraw
invalidate();
return true;
}
return super.onTouchEvent(event);
}
/**
* Cleared away all the lines on the screen, and then draw a line inside the collection
*/
private void clearScreenAndDrawList() {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (Pair<NodeView, NodeView> pair : lineList) {
canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(), pair.second.getCenterX(), pair.second.getCenterY(), paint);
}
}
/**
* Get Node, or null indicates that the current finger between two Node
*/
private NodeView getNodeAt(float x, float y) {
for (int n = 0; n < getChildCount(); n++) {
NodeView node = (NodeView) getChildAt(n);
if (!(x >= node.getLeft() && x < node.getRight())) {
continue;
}
if (!(y >= node.getTop() && y < node.getBottom())) {
continue;
}
return node;
}
return null;
}
/**
* The results set callback listeners gesture
*
* @param callBack
*/
public void setCallBack(CallBack callBack) {
this.callBack = callBack;
}
/**
* Node Description Class
*/
public class NodeView extends View {
private int num;
private boolean highLighted;
private NodeView(Context context) {
super(context);
}
public NodeView(Context context, int num) {
this(context);
this.num = num;
highLighted = false;
if (nodeSrc == null) {
setBackgroundResource(0);
} else {
setBackgroundDrawable(nodeSrc);
}
}
public boolean isHighLighted() {
return highLighted;
}
public void setHighLighted(boolean highLighted) {
this.highLighted = highLighted;
if (highLighted) {
if (nodeOnSrc == null) {
setBackgroundResource(0);
} else {
setBackgroundDrawable(nodeOnSrc);
}
} else {
if (nodeSrc == null) {
setBackgroundResource(0);
} else {
setBackgroundDrawable(nodeSrc);
}
}
}
public int getCenterX() {
return (getLeft() + getRight()) / 2;
}
public int getCenterY() {
return (getTop() + getBottom()) / 2;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
/**
* Results callback listener interface
*/
public interface CallBack {
void onFinish(String password);
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/nextContentBg"
tools:context="com.raloktech.apps.anti_theftalarm.patternlocker.PatternLocker">
<KustamPidichaLockPattern
android:id="@+id/lockPattern"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
app:lineColor="@android:color/white"
app:lineWidth="8dp"
app:nodeOnSrc="@drawable/abc_btn_radio_to_on_mtrl_000"
app:nodeSrc="@drawable/abc_btn_radio_to_on_mtrl_015" />
<TextView
android:id="@+id/pattern_lock_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/lockPattern"
android:layout_centerHorizontal="true"
android:text="Patten lock status"
android:textAppearance="?android:textAppearanceLarge"
android:textColor="@color/textColorPrimary" />
</RelativeLayout>
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
public class PatternLocker extends Activity {
private static final String CLASSNAME = PatternLocker.class.getName();
public static final String ACTION_CREATE_PATTERN = CLASSNAME + ".create_pattern";
public static final String ACTION_COMPARE_PATTERN = CLASSNAME + ".compare_pattern";
private TextView patternLockStatus;
private String tempPassword;
private boolean firstPassCreated = false;
private int patternMode = 0;
public class PatternMode {
public static final int CREATE_PATTERN = 153;
public static final int COMPARE_PATTERN = 275;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pattern_locker);
final AppPreferences appPreferences = new AppPreferences(this);
KustamPidichaLockPattern lockPattern = (KustamPidichaLockPattern) findViewById(R.id.lockPattern);
patternLockStatus = (TextView) findViewById(R.id.pattern_lock_status);
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
patternLockStatus.setText("Create new pattern");
patternMode = PatternMode.CREATE_PATTERN;
}
if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
patternLockStatus.setText("Enter your pattern");
patternMode = PatternMode.COMPARE_PATTERN;
}
lockPattern.setCallBack(new KustamPidichaLockPattern.CallBack() {
@Override
public void onFinish(String s) {
/**
* Create Pattern request
*/
if (patternMode == PatternMode.CREATE_PATTERN) {
/**
* If password length is less than 4 characters then
* Ask the user to enter new pattern
*/
if (s.length() < 4) {
patternLockStatus.setText("Pattern can not be created");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
patternLockStatus.setTextColor(Color.parseColor("#F44336"));
patternLockStatus.setText("Retry new pattern");
}
}, 2000);
firstPassCreated = false;
} else {
if (!firstPassCreated) {
tempPassword = s;
firstPassCreated = true;
patternLockStatus.setTextColor(Color.parseColor("#2196F3"));
patternLockStatus.setText("Pattern recorded");
} else if (tempPassword.equals(s)) {
/**
* Save the password and Set result ok to finish on activity result
*/
appPreferences.setPatternLockPass(s);
setResult(RESULT_OK);
finish();
} else {
patternLockStatus.setTextColor(Color.parseColor("#F44336"));
patternLockStatus.setText("Wrong pattern! Retry");
firstPassCreated = false;
}
}
}
/**
* Compare pattern request
*/
if (patternMode == PatternMode.COMPARE_PATTERN) {
AppPreferences appPreferences = new AppPreferences(PatternLocker.this);
if (s.length() < 4) {
patternLockStatus.setTextColor(Color.parseColor("#F44336"));
patternLockStatus.setText("Wrong Pattern!");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
patternLockStatus.setTextColor(Color.parseColor("#4CAF50"));
patternLockStatus.setText("Retry to unlock");
}
}, 2000);
} else if (appPreferences.getPatternLockPass().equals(s)) {
/**
* Compare the string password with the preference
*/
/**
* Set result ok to finish on activity result
*/
setResult(RESULT_OK);
finish();
} else {
patternLockStatus.setTextColor(Color.parseColor("#F44336"));
patternLockStatus.setText("Wrong Pattern!");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
patternLockStatus.setTextColor(Color.parseColor("#4CAF50"));
patternLockStatus.setText("Retry to unlock");
}
}, 2000);
}
}
}
});
}
@Override
public void onBackPressed() {
super.onBackPressed();
setResult(RESULT_CANCELED);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment