Back to project page android-lockpattern.
The source code is released under:
Apache License
If you think the Android project android-lockpattern listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) 2007 The Android Open Source Project *//from w w w . j a v a 2 s.c o m * 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. */ package com.haibison.android.lockpattern.widget; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import android.util.Log; import com.haibison.android.lockpattern.BuildConfig; import com.haibison.android.lockpattern.collect.Lists; import com.haibison.android.lockpattern.util.Randoms; /** * Utilities for the lock pattern and its settings. */ public class LockPatternUtils { /** * Used for debugging... */ private static final String CLASSNAME = LockPatternUtils.class.getName(); /** * "UTF-8" */ public static final String UTF8 = "UTF-8"; /** * "SHA-1" */ public static final String SHA1 = "SHA-1"; /** * This is singleton class. */ private LockPatternUtils() { }// LockPatternUtils /** * Deserialize a pattern. * * @param string * The pattern serialized with {@link #patternToString} * @return The pattern. */ public static List<LockPatternView.Cell> stringToPattern(String string) { List<LockPatternView.Cell> result = Lists.newArrayList(); try { final byte[] bytes = string.getBytes(UTF8); for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; result.add(LockPatternView.Cell.of(b / 3, b % 3)); } } catch (UnsupportedEncodingException e) { // never catch this } return result; }// stringToPattern() /** * Serialize a pattern. * * @param pattern * The pattern. * @return The pattern in string form. */ public static String patternToString(List<LockPatternView.Cell> pattern) { if (pattern == null) { return ""; } final int patternSize = pattern.size(); byte[] res = new byte[patternSize]; for (int i = 0; i < patternSize; i++) { LockPatternView.Cell cell = pattern.get(i); res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); } try { return new String(res, UTF8); } catch (UnsupportedEncodingException e) { // never catch this return ""; } }// patternToString() /** * Serializes a pattern * * @param pattern * The pattern * @return The SHA-1 string of the pattern got from * {@link #patternToString(List)} */ public static String patternToSha1(List<LockPatternView.Cell> pattern) { try { MessageDigest md = MessageDigest.getInstance(SHA1); md.update(patternToString(pattern).getBytes(UTF8)); byte[] digest = md.digest(); BigInteger bi = new BigInteger(1, digest); return String.format((Locale) null, "%0" + (digest.length * 2) + "x", bi).toLowerCase(); } catch (NoSuchAlgorithmException e) { // never catch this return ""; } catch (UnsupportedEncodingException e) { // never catch this return ""; } }// patternToSha1() /** * Generates a random "CAPTCHA" pattern. By saying "CAPTCHA", this method * ensures that the generated pattern is easy for the user to re-draw. * <p> * <b>Notes:</b> This method is <b>not</b> optimized and <b>not</b> * benchmarked yet for large size of the pattern's matrix. Currently it * works fine with a matrix of {@code 3x3} cells. Be careful when the size * increases. * </p> * * @param size * the size of the pattern to be generated. * @return the generated pattern. * @throws IndexOutOfBoundsException * if {@code size <= 0} or {@code size > } * {@link LockPatternView#MATRIX_SIZE}. * @since v2.7 beta * @author Hai Bison */ public static ArrayList<LockPatternView.Cell> genCaptchaPattern(int size) throws IndexOutOfBoundsException { if (size <= 0 || size > LockPatternView.MATRIX_SIZE) throw new IndexOutOfBoundsException( "`size` must be in range [1, `LockPatternView.MATRIX_SIZE`]"); final List<Integer> usedIds = Lists.newArrayList(); int lastId = Randoms.randInt(LockPatternView.MATRIX_SIZE); usedIds.add(lastId); while (usedIds.size() < size) { /* * We start from an empty matrix, so there's always a break point to * exit this loop. */ if (BuildConfig.DEBUG) Log.d(CLASSNAME, " >> lastId = " + lastId); final int lastRow = lastId / LockPatternView.MATRIX_WIDTH; final int lastCol = lastId % LockPatternView.MATRIX_WIDTH; /* * This is the max available rows/ columns that we can reach from * the cell of `lastId` to the border of the matrix. */ final int maxDistance = Math.max( Math.max(lastRow, LockPatternView.MATRIX_WIDTH - lastRow), Math.max(lastCol, LockPatternView.MATRIX_WIDTH - lastCol)); lastId = -1; /* * Starting from `distance` = 1, find the closest-available * neighbour value of the cell [lastRow, lastCol]. */ for (int distance = 1; distance <= maxDistance; distance++) { /* * Now we have a square surrounding the current cell. We call it * ABCD, in which A is top-left, and C is bottom-right. */ final int rowA = lastRow - distance; final int colA = lastCol - distance; final int rowC = lastRow + distance; final int colC = lastCol + distance; int[] randomValues; /* * Process randomly AB, BC, CD, and DA. Break the loop as soon * as we find one value. */ final int[] lines = Randoms.randIntArray(4); for (int line : lines) { switch (line) { case 0: { if (rowA >= 0) { randomValues = Randoms.randIntArray(Math.max(0, colA), Math.min( LockPatternView.MATRIX_WIDTH, colC + 1)); for (int c : randomValues) { lastId = rowA * LockPatternView.MATRIX_WIDTH + c; if (usedIds.contains(lastId)) lastId = -1; else break; } } break; }// AB case 1: { if (colC < LockPatternView.MATRIX_WIDTH) { randomValues = Randoms.randIntArray(Math.max(0, rowA + 1), Math.min( LockPatternView.MATRIX_WIDTH, rowC + 1)); for (int r : randomValues) { lastId = r * LockPatternView.MATRIX_WIDTH + colC; if (usedIds.contains(lastId)) lastId = -1; else break; } } break; }// BC case 2: { if (rowC < LockPatternView.MATRIX_WIDTH) { randomValues = Randoms.randIntArray(Math.max(0, colA), Math.min( LockPatternView.MATRIX_WIDTH, colC)); for (int c : randomValues) { lastId = rowC * LockPatternView.MATRIX_WIDTH + c; if (usedIds.contains(lastId)) lastId = -1; else break; } } break; }// DC case 3: { if (colA >= 0) { randomValues = Randoms.randIntArray(Math.max(0, rowA + 1), Math.min( LockPatternView.MATRIX_WIDTH, rowC)); for (int r : randomValues) { lastId = r * LockPatternView.MATRIX_WIDTH + colA; if (usedIds.contains(lastId)) lastId = -1; else break; } } break; }// AD } if (lastId >= 0) break; }// for line if (lastId >= 0) break; }// for distance usedIds.add(lastId); }// while final ArrayList<LockPatternView.Cell> result = Lists.newArrayList(); for (int id : usedIds) result.add(LockPatternView.Cell.of(id)); return result; }// genCaptchaPattern() }