LockPatternView.java revision a97227add8ef08de811979ef9dfbb84cff3de014
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.animation.Animator; 21c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.animation.AnimatorListenerAdapter; 22c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.animation.ValueAnimator; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 24bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Millerimport android.content.res.TypedArray; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Path; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 296a109b4874b79d9bf8f5d990bfe831a59e5a83dcKarl Rosaenimport android.os.Debug; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 34aef555bcf26e770e37f2065913084588fb92c6fbJim Millerimport android.view.HapticFeedbackConstants; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 37530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 38c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.view.animation.AnimationUtils; 39c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.view.animation.Interpolator; 40530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 41530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganovimport com.android.internal.R; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Displays and detects the user's unlock attempt, which is a drag of a finger 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * across 9 regions of the screen. 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Is also capable of displaying a static pattern in "in progress", "wrong" or 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "correct" states. 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class LockPatternView extends View { 54bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller // Aspect to use when rendering this view 55bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_SQUARE = 0; // View will be the minimum of width/height 56bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will be minimum of (w,h) 57bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h) 58bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean PROFILE_DRAWING = false; 603018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek private final CellState[][] mCellStates; 61c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 62c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mDotSize; 63c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mDotSizeActivated; 64c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mPathWidth; 65c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDrawingProfilingStarted = false; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 68a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Paint mPaint = new Paint(); 69a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Paint mPathPaint = new Paint(); 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How many milliseconds we spend animating each circle of a lock pattern 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if the animating mode is set. The entire animation should take this 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * constant * the length of the pattern to complete. 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MILLIS_PER_CIRCLE_ANIMATING = 700; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 780caa377f4688f175ae22229a10294468610a116eJim Miller /** 790caa377f4688f175ae22229a10294468610a116eJim Miller * This can be used to avoid updating the display for very small motions or noisy panels. 800caa377f4688f175ae22229a10294468610a116eJim Miller * It didn't seem to have much impact on the devices tested, so currently set to 0. 810caa377f4688f175ae22229a10294468610a116eJim Miller */ 820caa377f4688f175ae22229a10294468610a116eJim Miller private static final float DRAG_THRESHHOLD = 0.0f; 830caa377f4688f175ae22229a10294468610a116eJim Miller 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnPatternListener mOnPatternListener; 85a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Lookup table for the circles of the pattern we are currently drawing. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will be the cells of the complete pattern unless we are animating, 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in which case we use this to hold the cells we are drawing for the in 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * progress animation. 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 93a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final boolean[][] mPatternDrawLookup = new boolean[3][3]; 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the in progress point: 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - during interaction: where the user's finger is 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - during animation: the current tip of the animating line 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mInProgressX = -1; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mInProgressY = -1; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mAnimatingPeriodStart; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private DisplayMode mPatternDisplayMode = DisplayMode.Correct; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInputEnabled = true; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInStealthMode = false; 108aef555bcf26e770e37f2065913084588fb92c6fbJim Miller private boolean mEnableHapticFeedback = true; 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mPatternInProgress = false; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mHitFactor = 0.6f; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSquareWidth; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSquareHeight; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Path mCurrentPath = new Path(); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Rect mInvalidate = new Rect(); 1189ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller private final Rect mTmpInvalidateRect = new Rect(); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 120bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private int mAspect; 121c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mRegularColor; 122c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mErrorColor; 123c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mSuccessColor; 1242cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek 125a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Interpolator mFastOutSlowInInterpolator; 126a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Interpolator mLinearOutSlowInInterpolator; 127bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Represents a cell in the 3 X 3 matrix of the unlock pattern view. 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 131a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley public static final class Cell { 132a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley final int row; 133a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley final int column; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // keep # objects limited to 9 136a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private static final Cell[][] sCells = createCells(); 137a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley 138a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private static Cell[][] createCells() { 139a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley Cell[][] res = new Cell[3][3]; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 142a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley res[i][j] = new Cell(i, j); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 145a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley return res; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param row The row of the cell. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param column The column of the cell. 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell(int row, int column) { 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange(row, column); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.row = row; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.column = column; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getRow() { 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return row; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getColumn() { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return column; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 166a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley public static Cell of(int row, int column) { 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange(row, column); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sCells[row][column]; 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void checkRange(int row, int column) { 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (row < 0 || row > 2) { 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("row must be in range 0-2"); 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (column < 0 || column > 2) { 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("column must be in range 0-2"); 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 180a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @Override 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "(row=" + row + ",clmn=" + column + ")"; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1863018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public static class CellState { 1873018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public float scale = 1.0f; 1883018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public float translateY = 0.0f; 1893018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public float alpha = 1.0f; 190c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float size; 191c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float lineEndX = Float.MIN_VALUE; 192c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float lineEndY = Float.MIN_VALUE; 193c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public ValueAnimator lineAnimator; 1943018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 1953018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How to display the current pattern. 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum DisplayMode { 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern drawn is correct (i.e draw it in a friendly color) 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Correct, 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Animate the pattern (for demo, and help). 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Animate, 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern is wrong (i.e draw a foreboding color) 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Wrong 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The call back interface for detecting patterns entered by the user. 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static interface OnPatternListener { 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A new pattern has begun. 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternStart(); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern was cleared. 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternCleared(); 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 23341e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller * The user extended the pattern currently being drawn by one cell. 23441e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller * @param pattern The pattern with newly added cell. 23541e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller */ 23641e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller void onPatternCellAdded(List<Cell> pattern); 23741e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller 23841e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller /** 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A pattern was detected from the user. 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pattern The pattern. 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternDetected(List<Cell> pattern); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public LockPatternView(Context context) { 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public LockPatternView(Context context, AttributeSet attrs) { 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs); 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 252bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView); 253bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 254bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller final String aspect = a.getString(R.styleable.LockPatternView_aspect); 255bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 256bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller if ("square".equals(aspect)) { 257bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_SQUARE; 258bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else if ("lock_width".equals(aspect)) { 259bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_LOCK_WIDTH; 260bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else if ("lock_height".equals(aspect)) { 261bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_LOCK_HEIGHT; 262bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else { 263bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_SQUARE; 264bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } 265bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setClickable(true); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2682cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setAntiAlias(true); 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setDither(true); 2711cf3594114b1846c97243ff536074c49bbe06061Fabrice Di Meglio 272c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mRegularColor = getResources().getColor(R.color.lock_pattern_view_regular_color); 273c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mErrorColor = getResources().getColor(R.color.lock_pattern_view_error_color); 274c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mSuccessColor = getResources().getColor(R.color.lock_pattern_view_success_color); 275c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, mRegularColor); 276c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, mErrorColor); 277c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, mSuccessColor); 278c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 279c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor); 2802cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPathPaint.setColor(pathColor); 2811cf3594114b1846c97243ff536074c49bbe06061Fabrice Di Meglio 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStyle(Paint.Style.STROKE); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStrokeJoin(Paint.Join.ROUND); 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStrokeCap(Paint.Cap.ROUND); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 286c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathWidth = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_line_width); 287c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setStrokeWidth(mPathWidth); 288c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 289c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size); 290c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mDotSizeActivated = getResources().getDimensionPixelSize( 291c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi R.dimen.lock_pattern_dot_size_activated); 29285d630020a29c24f3d51f00b5ce3f701c16f0a45Jim Miller 2932cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPaint.setAntiAlias(true); 2942cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPaint.setDither(true); 2953018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 2963018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mCellStates = new CellState[3][3]; 2973018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int i = 0; i < 3; i++) { 2983018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int j = 0; j < 3; j++) { 2993018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mCellStates[i][j] = new CellState(); 300c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mCellStates[i][j].size = mDotSize; 3013018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 3023018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 303c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 304c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mFastOutSlowInInterpolator = 305c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); 306c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mLinearOutSlowInInterpolator = 307c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); 3083018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 3093018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 3103018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public CellState[][] getCellStates() { 3113018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek return mCellStates; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the view is in stealth mode. 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInStealthMode() { 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInStealthMode; 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the view has tactile feedback enabled. 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isTactileFeedbackEnabled() { 325aef555bcf26e770e37f2065913084588fb92c6fbJim Miller return mEnableHapticFeedback; 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set whether the view is in stealth mode. If true, there will be no 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * visible feedback as the user enters the pattern. 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inStealthMode Whether in stealth mode. 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setInStealthMode(boolean inStealthMode) { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = inStealthMode; 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set whether the view will use tactile feedback. If true, there will be 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * tactile feedback as the user enters the pattern. 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tactileFeedbackEnabled Whether tactile feedback is enabled 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) { 345aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mEnableHapticFeedback = tactileFeedbackEnabled; 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the call back for pattern detection. 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param onPatternListener The call back. 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnPatternListener( 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OnPatternListener onPatternListener) { 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPatternListener = onPatternListener; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the pattern explicitely (rather than waiting for the user to input 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a pattern). 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param displayMode How to display the pattern. 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pattern The pattern. 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPattern(DisplayMode displayMode, List<Cell> pattern) { 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.clear(); 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.addAll(pattern); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Cell cell : pattern) { 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true; 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDisplayMode(displayMode); 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the display mode of the current pattern. This can be useful, for 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, after detecting a pattern to tell this view whether change the 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in progress result to correct or wrong. 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param displayMode The display mode. 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setDisplayMode(DisplayMode displayMode) { 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = displayMode; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (displayMode == DisplayMode.Animate) { 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPattern.size() == 0) { 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("you must have a pattern to " 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "animate if you want to set the display mode to animate"); 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAnimatingPeriodStart = SystemClock.elapsedRealtime(); 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell first = mPattern.get(0); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressX = getCenterXForColumn(first.getColumn()); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressY = getCenterYForRow(first.getRow()); 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 396530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyCellAdded() { 397e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_cell_added); 398530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 399530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternCellAdded(mPattern); 400530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 401530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 402530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 403530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternStarted() { 404e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_start); 405530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 406530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternStart(); 407530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 408530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 409530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 410530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternDetected() { 411e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_detected); 412530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 413530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternDetected(mPattern); 414530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 415530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 416530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 417530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternCleared() { 418e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_cleared); 419530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 420530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternCleared(); 421530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 422530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 423530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clear the pattern. 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clearPattern() { 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetPattern(); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Reset all pattern state. 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetPattern() { 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.clear(); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = DisplayMode.Correct; 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clear the pattern lookup table. 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void clearPatternDrawLookup() { 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[i][j] = false; 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Disable input (for instance when displaying a message that will 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * timeout so user doesn't get view into messy state). 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void disableInput() { 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = false; 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable input. 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enableInput() { 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = true; 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onSizeChanged(int w, int h, int oldw, int oldh) { 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int width = w - mPaddingLeft - mPaddingRight; 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSquareWidth = width / 3.0f; 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int height = h - mPaddingTop - mPaddingBottom; 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSquareHeight = height / 3.0f; 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4760a0753808ea27955472c2283413fc230bc85595bJim Miller private int resolveMeasured(int measureSpec, int desired) 4770a0753808ea27955472c2283413fc230bc85595bJim Miller { 4780a0753808ea27955472c2283413fc230bc85595bJim Miller int result = 0; 4790a0753808ea27955472c2283413fc230bc85595bJim Miller int specSize = MeasureSpec.getSize(measureSpec); 4800a0753808ea27955472c2283413fc230bc85595bJim Miller switch (MeasureSpec.getMode(measureSpec)) { 4810a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.UNSPECIFIED: 4820a0753808ea27955472c2283413fc230bc85595bJim Miller result = desired; 4830a0753808ea27955472c2283413fc230bc85595bJim Miller break; 4840a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.AT_MOST: 4857bc60abc97f77cc2478f5d19c391ebdb1433a893Peter Ng result = Math.max(specSize, desired); 4860a0753808ea27955472c2283413fc230bc85595bJim Miller break; 4870a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.EXACTLY: 4880a0753808ea27955472c2283413fc230bc85595bJim Miller default: 4891fd16378812792913a6aa6923acbec20037e09ffPhilip Milne result = specSize; 4900a0753808ea27955472c2283413fc230bc85595bJim Miller } 4910a0753808ea27955472c2283413fc230bc85595bJim Miller return result; 4920a0753808ea27955472c2283413fc230bc85595bJim Miller } 4930a0753808ea27955472c2283413fc230bc85595bJim Miller 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 4960d244193bed0c995e2beaff5e217200457b28b9dJim Miller final int minimumWidth = getSuggestedMinimumWidth(); 4970d244193bed0c995e2beaff5e217200457b28b9dJim Miller final int minimumHeight = getSuggestedMinimumHeight(); 4980a0753808ea27955472c2283413fc230bc85595bJim Miller int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth); 4990a0753808ea27955472c2283413fc230bc85595bJim Miller int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight); 5000a0753808ea27955472c2283413fc230bc85595bJim Miller 501bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller switch (mAspect) { 502bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_SQUARE: 5030d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewWidth = viewHeight = Math.min(viewWidth, viewHeight); 504bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 505bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_LOCK_WIDTH: 5060d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewHeight = Math.min(viewWidth, viewHeight); 507bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 508bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_LOCK_HEIGHT: 5090d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewWidth = Math.min(viewWidth, viewHeight); 510bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 511bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } 5120a0753808ea27955472c2283413fc230bc85595bJim Miller // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" + viewHeight); 513bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller setMeasuredDimension(viewWidth, viewHeight); 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determines whether the point x, y will add a new point to the current 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pattern (in addition to finding the cell, also makes heuristic choices 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * such as filling in gaps based on current pattern). 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param x The x coordinate. 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y coordinate. 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell detectAndAddHit(float x, float y) { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell cell = checkForNewHit(x, y); 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cell != null) { 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // check for gaps in existing pattern 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cell fillInGapCell = null; 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Cell> pattern = mPattern; 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!pattern.isEmpty()) { 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell lastCell = pattern.get(pattern.size() - 1); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dRow = cell.row - lastCell.row; 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dColumn = cell.column - lastCell.column; 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fillInRow = lastCell.row; 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fillInColumn = lastCell.column; 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) { 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1); 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) { 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1); 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInGapCell = Cell.of(fillInRow, fillInColumn); 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fillInGapCell != null && 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) { 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addCellToPattern(fillInGapCell); 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addCellToPattern(cell); 554aef555bcf26e770e37f2065913084588fb92c6fbJim Miller if (mEnableHapticFeedback) { 555aef555bcf26e770e37f2065913084588fb92c6fbJim Miller performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, 556aef555bcf26e770e37f2065913084588fb92c6fbJim Miller HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING 557aef555bcf26e770e37f2065913084588fb92c6fbJim Miller | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cell; 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void addCellToPattern(Cell newCell) { 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true; 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.add(newCell); 567c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (!mInStealthMode) { 568c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startCellActivatedAnimation(newCell); 569c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 570530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyCellAdded(); 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 573c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startCellActivatedAnimation(Cell cell) { 574c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final CellState cellState = mCellStates[cell.row][cell.column]; 575c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startSizeAnimation(mDotSize, mDotSizeActivated, 96, mLinearOutSlowInInterpolator, 576c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cellState, new Runnable() { 577c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 578c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void run() { 579c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startSizeAnimation(mDotSizeActivated, mDotSize, 192, mFastOutSlowInInterpolator, 580c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cellState, null); 581c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 582c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 583c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startLineEndAnimation(cellState, mInProgressX, mInProgressY, 584c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi getCenterXForColumn(cell.column), getCenterYForRow(cell.row)); 585c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 586c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 587c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startLineEndAnimation(final CellState state, 588c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final float startX, final float startY, final float targetX, final float targetY) { 589c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); 590c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 591c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 592c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 593c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float t = (float) animation.getAnimatedValue(); 594c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndX = (1 - t) * startX + t * targetX; 595c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndY = (1 - t) * startY + t * targetY; 596c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi invalidate(); 597c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 598c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 599c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addListener(new AnimatorListenerAdapter() { 600c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 601c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationEnd(Animator animation) { 602c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator = null; 603c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 604c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 605c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setInterpolator(mFastOutSlowInInterpolator); 606c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setDuration(100); 607c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.start(); 608c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator = valueAnimator; 609c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 610c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 611c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startSizeAnimation(float start, float end, long duration, Interpolator interpolator, 612c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final CellState state, final Runnable endRunnable) { 613c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end); 614c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 615c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 616c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 617c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.size = (float) animation.getAnimatedValue(); 618c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi invalidate(); 619c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 620c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 621c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (endRunnable != null) { 622c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addListener(new AnimatorListenerAdapter() { 623c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 624c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationEnd(Animator animation) { 625c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi endRunnable.run(); 626c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 627c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 628c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 629c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setInterpolator(interpolator); 630c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setDuration(duration); 631c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.start(); 632c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 633c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // helper method to find which cell a point maps to 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell checkForNewHit(float x, float y) { 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int rowHit = getRowHit(y); 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowHit < 0) { 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int columnHit = getColumnHit(x); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (columnHit < 0) { 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPatternDrawLookup[rowHit][columnHit]) { 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Cell.of(rowHit, columnHit); 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper method to find the row that y falls into. 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y coordinate 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The row that y falls in, or -1 if it falls in no row. 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getRowHit(float y) { 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float squareHeight = mSquareHeight; 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float hitSize = squareHeight * mHitFactor; 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float offset = mPaddingTop + (squareHeight - hitSize) / 2f; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float hitTop = offset + squareHeight * i; 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (y >= hitTop && y <= hitTop + hitSize) { 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper method to find the column x fallis into. 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param x The x coordinate. 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The column that x falls in, or -1 if it falls in no column. 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getColumnHit(float x) { 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float squareWidth = mSquareWidth; 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float hitSize = squareWidth * mHitFactor; 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float offset = mPaddingLeft + (squareWidth - hitSize) / 2f; 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float hitLeft = offset + squareWidth * i; 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (x >= hitLeft && x <= hitLeft + hitSize) { 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 694530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov public boolean onHoverEvent(MotionEvent event) { 695530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) { 696530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov final int action = event.getAction(); 697530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov switch (action) { 698530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: 699530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_DOWN); 700530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 701530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: 702530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_MOVE); 703530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 704530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: 705530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_UP); 706530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 707530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 708530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov onTouchEvent(event); 709530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(action); 710530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 711530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov return super.onHoverEvent(event); 712530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 713530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 714530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov @Override 715aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller public boolean onTouchEvent(MotionEvent event) { 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mInputEnabled || !isEnabled()) { 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 720aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller switch(event.getAction()) { 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_DOWN: 722aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller handleActionDown(event); 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_UP: 725a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley handleActionUp(); 726aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return true; 727aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller case MotionEvent.ACTION_MOVE: 728aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller handleActionMove(event); 729aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return true; 730aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller case MotionEvent.ACTION_CANCEL: 731c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov if (mPatternInProgress) { 732c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov mPatternInProgress = false; 733c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov resetPattern(); 734c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov notifyPatternCleared(); 735c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov } 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (PROFILE_DRAWING) { 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDrawingProfilingStarted) { 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Debug.stopMethodTracing(); 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDrawingProfilingStarted = false; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 743aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 744aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return false; 745aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 747aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller private void handleActionMove(MotionEvent event) { 748aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // Handle all recent motion events so we don't skip any cells even when the device 749aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // is busy... 750c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final float radius = mPathWidth; 751aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final int historySize = event.getHistorySize(); 7529ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mTmpInvalidateRect.setEmpty(); 7530caa377f4688f175ae22229a10294468610a116eJim Miller boolean invalidateNow = false; 754aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller for (int i = 0; i < historySize + 1; i++) { 755aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float x = i < historySize ? event.getHistoricalX(i) : event.getX(); 756aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float y = i < historySize ? event.getHistoricalY(i) : event.getY(); 757aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Cell hitCell = detectAndAddHit(x, y); 758aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final int patternSize = mPattern.size(); 759530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (hitCell != null && patternSize == 1) { 760aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = true; 761530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternStarted(); 762aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 763aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // note current x and y for rubber banding of in progress patterns 764aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float dx = Math.abs(x - mInProgressX); 765aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float dy = Math.abs(y - mInProgressY); 7660caa377f4688f175ae22229a10294468610a116eJim Miller if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) { 7670caa377f4688f175ae22229a10294468610a116eJim Miller invalidateNow = true; 7680caa377f4688f175ae22229a10294468610a116eJim Miller } 769aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 7700caa377f4688f175ae22229a10294468610a116eJim Miller if (mPatternInProgress && patternSize > 0) { 7710caa377f4688f175ae22229a10294468610a116eJim Miller final ArrayList<Cell> pattern = mPattern; 7720caa377f4688f175ae22229a10294468610a116eJim Miller final Cell lastCell = pattern.get(patternSize - 1); 7739ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float lastCellCenterX = getCenterXForColumn(lastCell.column); 7749ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float lastCellCenterY = getCenterYForRow(lastCell.row); 7750caa377f4688f175ae22229a10294468610a116eJim Miller 7769ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller // Adjust for drawn segment from last cell to (x,y). Radius accounts for line width. 7779ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float left = Math.min(lastCellCenterX, x) - radius; 7789ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float right = Math.max(lastCellCenterX, x) + radius; 7799ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float top = Math.min(lastCellCenterY, y) - radius; 7809ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float bottom = Math.max(lastCellCenterY, y) + radius; 7810caa377f4688f175ae22229a10294468610a116eJim Miller 7820caa377f4688f175ae22229a10294468610a116eJim Miller // Invalidate between the pattern's new cell and the pattern's previous cell 7839ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller if (hitCell != null) { 7840caa377f4688f175ae22229a10294468610a116eJim Miller final float width = mSquareWidth * 0.5f; 7850caa377f4688f175ae22229a10294468610a116eJim Miller final float height = mSquareHeight * 0.5f; 7869ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller final float hitCellCenterX = getCenterXForColumn(hitCell.column); 7879ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller final float hitCellCenterY = getCenterYForRow(hitCell.row); 7889ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller 7899ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller left = Math.min(hitCellCenterX - width, left); 7909ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller right = Math.max(hitCellCenterX + width, right); 7919ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller top = Math.min(hitCellCenterY - height, top); 7929ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller bottom = Math.max(hitCellCenterY + height, bottom); 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7940caa377f4688f175ae22229a10294468610a116eJim Miller 7950caa377f4688f175ae22229a10294468610a116eJim Miller // Invalidate between the pattern's last cell and the previous location 7969ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mTmpInvalidateRect.union(Math.round(left), Math.round(top), 7970caa377f4688f175ae22229a10294468610a116eJim Miller Math.round(right), Math.round(bottom)); 798aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 799aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 8000caa377f4688f175ae22229a10294468610a116eJim Miller mInProgressX = event.getX(); 8010caa377f4688f175ae22229a10294468610a116eJim Miller mInProgressY = event.getY(); 8020caa377f4688f175ae22229a10294468610a116eJim Miller 8030caa377f4688f175ae22229a10294468610a116eJim Miller // To save updates, we only invalidate if the user moved beyond a certain amount. 8040caa377f4688f175ae22229a10294468610a116eJim Miller if (invalidateNow) { 8059ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mInvalidate.union(mTmpInvalidateRect); 8069ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller invalidate(mInvalidate); 8079ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mInvalidate.set(mTmpInvalidateRect); 8080caa377f4688f175ae22229a10294468610a116eJim Miller } 809aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 810aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 811530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void sendAccessEvent(int resId) { 812e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv announceForAccessibility(mContext.getString(resId)); 813530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 814530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 815a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private void handleActionUp() { 816aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // report pattern detected 817530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (!mPattern.isEmpty()) { 818aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = false; 819c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cancelLineAnimations(); 820530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternDetected(); 821aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller invalidate(); 822aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 823aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (PROFILE_DRAWING) { 824aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (mDrawingProfilingStarted) { 825aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Debug.stopMethodTracing(); 826aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mDrawingProfilingStarted = false; 827aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 828aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 829aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 830aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 831c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void cancelLineAnimations() { 832c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi for (int i = 0; i < 3; i++) { 833c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi for (int j = 0; j < 3; j++) { 834c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState state = mCellStates[i][j]; 835c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (state.lineAnimator != null) { 836c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator.cancel(); 837c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndX = Float.MIN_VALUE; 838c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndY = Float.MIN_VALUE; 839c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 840c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 841c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 842c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 843aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller private void handleActionDown(MotionEvent event) { 844aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller resetPattern(); 845aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float x = event.getX(); 846aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float y = event.getY(); 847aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final Cell hitCell = detectAndAddHit(x, y); 848530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (hitCell != null) { 849aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = true; 850aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternDisplayMode = DisplayMode.Correct; 851530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternStarted(); 852c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov } else if (mPatternInProgress) { 853aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = false; 854530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternCleared(); 855aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 856aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (hitCell != null) { 857aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float startX = getCenterXForColumn(hitCell.column); 858aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float startY = getCenterYForRow(hitCell.row); 859aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 860aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float widthOffset = mSquareWidth / 2f; 861aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float heightOffset = mSquareHeight / 2f; 862aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 863aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller invalidate((int) (startX - widthOffset), (int) (startY - heightOffset), 864aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller (int) (startX + widthOffset), (int) (startY + heightOffset)); 865aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 866aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mInProgressX = x; 867aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mInProgressY = y; 868aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (PROFILE_DRAWING) { 869aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (!mDrawingProfilingStarted) { 870aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Debug.startMethodTracing("LockPatternDrawing"); 871aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mDrawingProfilingStarted = true; 872aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getCenterXForColumn(int column) { 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f; 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getCenterYForRow(int row) { 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaddingTop + row * mSquareHeight + mSquareHeight / 2f; 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onDraw(Canvas canvas) { 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Cell> pattern = mPattern; 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = pattern.size(); 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean[][] drawLookup = mPatternDrawLookup; 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPatternDisplayMode == DisplayMode.Animate) { 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out which circles to draw 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // + 1 so we pause on complete pattern 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING; 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spotInCycle = (int) (SystemClock.elapsedRealtime() - 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAnimatingPeriodStart) % oneCycle; 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING; 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numCircles; i++) { 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell cell = pattern.get(i); 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project drawLookup[cell.getRow()][cell.getColumn()] = true; 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out in progress portion of ghosting line 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean needToUpdateInProgressPoint = numCircles > 0 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && numCircles < count; 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needToUpdateInProgressPoint) { 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float percentageOfNextCircle = 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING)) / 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MILLIS_PER_CIRCLE_ANIMATING; 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell currentCell = pattern.get(numCircles - 1); 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float centerX = getCenterXForColumn(currentCell.column); 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float centerY = getCenterYForRow(currentCell.row); 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell nextCell = pattern.get(numCircles); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float dx = percentageOfNextCircle * 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (getCenterXForColumn(nextCell.column) - centerX); 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float dy = percentageOfNextCircle * 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (getCenterYForRow(nextCell.row) - centerY); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressX = centerX + dx; 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressY = centerY + dy; 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Infinite loop here... 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Path currentPath = mCurrentPath; 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project currentPath.rewind(); 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // draw the circles 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 937c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float centerY = getCenterYForRow(i); 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 939c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState cellState = mCellStates[i][j]; 940c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float centerX = getCenterXForColumn(j); 941c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float size = cellState.size * cellState.scale; 942c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float translationY = cellState.translateY; 943c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi drawCircle(canvas, (int) centerX, (int) centerY + translationY, 944c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi size, drawLookup[i][j], cellState.alpha); 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 94808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // TODO: the path should be created and cached every time we hit-detect a cell 94908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // only the last segment of the path should be computed here 950e2d71e45209a4ac0787b360c4b0eb4d617863f3fAdrian Roos // draw the path of the pattern (unless we are in stealth mode) 951e2d71e45209a4ac0787b360c4b0eb4d617863f3fAdrian Roos final boolean drawPath = !mInStealthMode; 95208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (drawPath) { 954c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setColor(getCurrentColor(true /* partOfPattern */)); 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 95608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller boolean anyCircles = false; 957c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float lastX = 0f; 958c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float lastY = 0f; 95908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller for (int i = 0; i < count; i++) { 96008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller Cell cell = pattern.get(i); 96108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 96208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // only draw the part of the pattern stored in 96308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // the lookup table (this is only different in the case 96408a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // of animation). 96508a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller if (!drawLookup[cell.row][cell.column]) { 96608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller break; 96708a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 96808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller anyCircles = true; 96908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 97008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller float centerX = getCenterXForColumn(cell.column); 97108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller float centerY = getCenterYForRow(cell.row); 972c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (i != 0) { 973c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState state = mCellStates[cell.row][cell.column]; 974c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.rewind(); 975c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.moveTo(lastX, lastY); 976c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (state.lineEndX != Float.MIN_VALUE && state.lineEndY != Float.MIN_VALUE) { 977c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.lineTo(state.lineEndX, state.lineEndY); 978c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } else { 979c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.lineTo(centerX, centerY); 980c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 981c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawPath(currentPath, mPathPaint); 98208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 983c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi lastX = centerX; 984c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi lastY = centerY; 98508a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 98608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 987c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi // draw last in progress section 98808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate) 98908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller && anyCircles) { 990c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.rewind(); 991c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.moveTo(lastX, lastY); 99208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller currentPath.lineTo(mInProgressX, mInProgressY); 993c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 994c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setAlpha((int) (calculateLastSegmentAlpha( 995c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mInProgressX, mInProgressY, lastX, lastY) * 255f)); 996c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawPath(currentPath, mPathPaint); 99708a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 99808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1001c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private float calculateLastSegmentAlpha(float x, float y, float lastX, float lastY) { 1002c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float diffX = x - lastX; 1003c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float diffY = y - lastY; 1004c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float dist = (float) Math.sqrt(diffX*diffX + diffY*diffY); 1005c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float frac = dist/mSquareWidth; 1006c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f)); 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int getCurrentColor(boolean partOfPattern) { 1010c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (!partOfPattern || mInStealthMode || mPatternInProgress) { 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // unselected circle 1012c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mRegularColor; 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPatternDisplayMode == DisplayMode.Wrong) { 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the pattern is wrong 1015c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mErrorColor; 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPatternDisplayMode == DisplayMode.Correct || 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode == DisplayMode.Animate) { 1018c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mSuccessColor; 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("unknown display mode " + mPatternDisplayMode); 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1022c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1024c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi /** 1025c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi * @param partOfPattern Whether this circle is part of the pattern. 1026c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi */ 1027c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void drawCircle(Canvas canvas, float centerX, float centerY, float size, 1028c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi boolean partOfPattern, float alpha) { 1029c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPaint.setColor(getCurrentColor(partOfPattern)); 1030c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPaint.setAlpha((int) (alpha * 255)); 1031c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawCircle(centerX, centerY, size/2, mPaint); 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected Parcelable onSaveInstanceState() { 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Parcelable superState = super.onSaveInstanceState(); 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(superState, 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LockPatternUtils.patternToString(mPattern), 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode.ordinal(), 1040aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mInputEnabled, mInStealthMode, mEnableHapticFeedback); 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onRestoreInstanceState(Parcelable state) { 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final SavedState ss = (SavedState) state; 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onRestoreInstanceState(ss.getSuperState()); 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setPattern( 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DisplayMode.Correct, 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LockPatternUtils.stringToPattern(ss.getSerializedPattern())); 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = ss.isInputEnabled(); 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = ss.isInStealthMode(); 1053aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mEnableHapticFeedback = ss.isTactileFeedbackEnabled(); 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The parecelable for saving and restoring a lock pattern view. 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class SavedState extends BaseSavedState { 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String mSerializedPattern; 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int mDisplayMode; 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mInputEnabled; 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mInStealthMode; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mTactileFeedbackEnabled; 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link LockPatternView#onSaveInstanceState()} 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcelable superState, String serializedPattern, int displayMode, 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) { 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(superState); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSerializedPattern = serializedPattern; 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayMode = displayMode; 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = inputEnabled; 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = inStealthMode; 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTactileFeedbackEnabled = tactileFeedbackEnabled; 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link #CREATOR} 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcel in) { 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(in); 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSerializedPattern = in.readString(); 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayMode = in.readInt(); 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = (Boolean) in.readValue(null); 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = (Boolean) in.readValue(null); 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTactileFeedbackEnabled = (Boolean) in.readValue(null); 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1091bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getSerializedPattern() { 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSerializedPattern; 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDisplayMode() { 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDisplayMode; 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInputEnabled() { 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInputEnabled; 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInStealthMode() { 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInStealthMode; 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isTactileFeedbackEnabled(){ 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mTactileFeedbackEnabled; 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel dest, int flags) { 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.writeToParcel(dest, flags); 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeString(mSerializedPattern); 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeInt(mDisplayMode); 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mInputEnabled); 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mInStealthMode); 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mTactileFeedbackEnabled); 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1122a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @SuppressWarnings({ "unused", "hiding" }) // Found using reflection 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Parcelable.Creator<SavedState> CREATOR = 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Creator<SavedState>() { 1125a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @Override 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SavedState createFromParcel(Parcel in) { 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(in); 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1130a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @Override 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SavedState[] newArray(int size) { 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState[size]; 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1137