Last active
July 13, 2016 16:11
-
-
Save akbarsha03/b5e51e31b8c701c6c66b to your computer and use it in GitHub Desktop.
Pattern Locker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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