LockPatternView.java revision 613f55fbbb23249d7c65e3f1fe8c943c4459b41a
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 19c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.animation.Animator; 20c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.animation.AnimatorListenerAdapter; 21c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.animation.ValueAnimator; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 23240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.content.res.Resources; 24bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Millerimport android.content.res.TypedArray; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 26613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggiimport android.graphics.CanvasProperty; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Path; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 30240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.media.AudioManager; 31240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.os.Bundle; 326a109b4874b79d9bf8f5d990bfe831a59e5a83dcKarl Rosaenimport android.os.Debug; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 36240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.os.UserHandle; 37240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.provider.Settings; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 39240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.util.IntArray; 40240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.util.Log; 41613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggiimport android.view.DisplayListCanvas; 42aef555bcf26e770e37f2065913084588fb92c6fbJim Millerimport android.view.HapticFeedbackConstants; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 44613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggiimport android.view.RenderNodeAnimator; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 46240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.view.accessibility.AccessibilityEvent; 47530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 48240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.view.accessibility.AccessibilityNodeInfo; 49240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 50c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.view.animation.AnimationUtils; 51c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.view.animation.Interpolator; 52530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 53530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganovimport com.android.internal.R; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 56240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport java.util.HashMap; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Displays and detects the user's unlock attempt, which is a drag of a finger 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * across 9 regions of the screen. 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Is also capable of displaying a static pattern in "in progress", "wrong" or 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "correct" states. 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class LockPatternView extends View { 67bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller // Aspect to use when rendering this view 68bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_SQUARE = 0; // View will be the minimum of width/height 69bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will be minimum of (w,h) 70bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h) 71bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean PROFILE_DRAWING = false; 733018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek private final CellState[][] mCellStates; 74c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 75c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mDotSize; 76c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mDotSizeActivated; 77c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mPathWidth; 78c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDrawingProfilingStarted = false; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 81a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Paint mPaint = new Paint(); 82a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Paint mPathPaint = new Paint(); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How many milliseconds we spend animating each circle of a lock pattern 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if the animating mode is set. The entire animation should take this 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * constant * the length of the pattern to complete. 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MILLIS_PER_CIRCLE_ANIMATING = 700; 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 910caa377f4688f175ae22229a10294468610a116eJim Miller /** 920caa377f4688f175ae22229a10294468610a116eJim Miller * This can be used to avoid updating the display for very small motions or noisy panels. 930caa377f4688f175ae22229a10294468610a116eJim Miller * It didn't seem to have much impact on the devices tested, so currently set to 0. 940caa377f4688f175ae22229a10294468610a116eJim Miller */ 950caa377f4688f175ae22229a10294468610a116eJim Miller private static final float DRAG_THRESHHOLD = 0.0f; 96240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public static final int VIRTUAL_BASE_VIEW_ID = 1; 97240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public static final boolean DEBUG_A11Y = true; 98240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private static final String TAG = "LockPatternView"; 990caa377f4688f175ae22229a10294468610a116eJim Miller 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnPatternListener mOnPatternListener; 101a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9); 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Lookup table for the circles of the pattern we are currently drawing. 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will be the cells of the complete pattern unless we are animating, 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in which case we use this to hold the cells we are drawing for the in 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * progress animation. 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 109a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final boolean[][] mPatternDrawLookup = new boolean[3][3]; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the in progress point: 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - during interaction: where the user's finger is 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - during animation: the current tip of the animating line 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mInProgressX = -1; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mInProgressY = -1; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mAnimatingPeriodStart; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private DisplayMode mPatternDisplayMode = DisplayMode.Correct; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInputEnabled = true; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInStealthMode = false; 124aef555bcf26e770e37f2065913084588fb92c6fbJim Miller private boolean mEnableHapticFeedback = true; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mPatternInProgress = false; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mHitFactor = 0.6f; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSquareWidth; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSquareHeight; 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Path mCurrentPath = new Path(); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Rect mInvalidate = new Rect(); 1349ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller private final Rect mTmpInvalidateRect = new Rect(); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 136bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private int mAspect; 137c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mRegularColor; 138c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mErrorColor; 139c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mSuccessColor; 1402cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek 141a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Interpolator mFastOutSlowInInterpolator; 142a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Interpolator mLinearOutSlowInInterpolator; 143240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private PatternExploreByTouchHelper mExploreByTouchHelper; 144240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private AudioManager mAudioManager; 145bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Represents a cell in the 3 X 3 matrix of the unlock pattern view. 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 149a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley public static final class Cell { 150a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley final int row; 151a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley final int column; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // keep # objects limited to 9 154a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private static final Cell[][] sCells = createCells(); 155a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley 156a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private static Cell[][] createCells() { 157a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley Cell[][] res = new Cell[3][3]; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 160a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley res[i][j] = new Cell(i, j); 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 163a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley return res; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param row The row of the cell. 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param column The column of the cell. 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell(int row, int column) { 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange(row, column); 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.row = row; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.column = column; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getRow() { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return row; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getColumn() { 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return column; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 184a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley public static Cell of(int row, int column) { 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange(row, column); 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sCells[row][column]; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void checkRange(int row, int column) { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (row < 0 || row > 2) { 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("row must be in range 0-2"); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (column < 0 || column > 2) { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("column must be in range 0-2"); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 198a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @Override 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "(row=" + row + ",clmn=" + column + ")"; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2043018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public static class CellState { 205613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi int row; 206613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi int col; 207613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi boolean hwAnimating; 208613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Float> hwRadius; 209613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Float> hwCenterX; 210613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Float> hwCenterY; 211613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Paint> hwPaint; 212613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float radius; 213613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float translationY; 214613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float alpha = 1f; 215c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float lineEndX = Float.MIN_VALUE; 216c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float lineEndY = Float.MIN_VALUE; 217c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public ValueAnimator lineAnimator; 2183018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 2193018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How to display the current pattern. 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum DisplayMode { 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern drawn is correct (i.e draw it in a friendly color) 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Correct, 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Animate the pattern (for demo, and help). 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Animate, 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern is wrong (i.e draw a foreboding color) 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Wrong 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The call back interface for detecting patterns entered by the user. 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static interface OnPatternListener { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A new pattern has begun. 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternStart(); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern was cleared. 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternCleared(); 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 25741e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller * The user extended the pattern currently being drawn by one cell. 25841e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller * @param pattern The pattern with newly added cell. 25941e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller */ 26041e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller void onPatternCellAdded(List<Cell> pattern); 26141e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller 26241e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller /** 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A pattern was detected from the user. 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pattern The pattern. 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternDetected(List<Cell> pattern); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public LockPatternView(Context context) { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public LockPatternView(Context context, AttributeSet attrs) { 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 276bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView); 277bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 278bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller final String aspect = a.getString(R.styleable.LockPatternView_aspect); 279bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 280bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller if ("square".equals(aspect)) { 281bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_SQUARE; 282bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else if ("lock_width".equals(aspect)) { 283bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_LOCK_WIDTH; 284bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else if ("lock_height".equals(aspect)) { 285bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_LOCK_HEIGHT; 286bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else { 287bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_SQUARE; 288bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } 289bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setClickable(true); 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2922cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setAntiAlias(true); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setDither(true); 2951cf3594114b1846c97243ff536074c49bbe06061Fabrice Di Meglio 2964a357cd2e55293402d7172766f7f9419815fc1e8Alan Viverette mRegularColor = context.getColor(R.color.lock_pattern_view_regular_color); 2974a357cd2e55293402d7172766f7f9419815fc1e8Alan Viverette mErrorColor = context.getColor(R.color.lock_pattern_view_error_color); 2984a357cd2e55293402d7172766f7f9419815fc1e8Alan Viverette mSuccessColor = context.getColor(R.color.lock_pattern_view_success_color); 299c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, mRegularColor); 300c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, mErrorColor); 301c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, mSuccessColor); 302c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 303c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor); 3042cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPathPaint.setColor(pathColor); 3051cf3594114b1846c97243ff536074c49bbe06061Fabrice Di Meglio 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStyle(Paint.Style.STROKE); 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStrokeJoin(Paint.Join.ROUND); 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStrokeCap(Paint.Cap.ROUND); 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 310c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathWidth = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_line_width); 311c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setStrokeWidth(mPathWidth); 312c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 313c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size); 314c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mDotSizeActivated = getResources().getDimensionPixelSize( 315c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi R.dimen.lock_pattern_dot_size_activated); 31685d630020a29c24f3d51f00b5ce3f701c16f0a45Jim Miller 3172cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPaint.setAntiAlias(true); 3182cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPaint.setDither(true); 3193018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 3203018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mCellStates = new CellState[3][3]; 3213018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int i = 0; i < 3; i++) { 3223018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int j = 0; j < 3; j++) { 3233018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mCellStates[i][j] = new CellState(); 324613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mCellStates[i][j].radius = mDotSize/2; 325613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mCellStates[i][j].row = i; 326613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mCellStates[i][j].col = j; 3273018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 3283018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 329c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 330c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mFastOutSlowInInterpolator = 331c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); 332c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mLinearOutSlowInInterpolator = 333c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); 334240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mExploreByTouchHelper = new PatternExploreByTouchHelper(this); 335240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller setAccessibilityDelegate(mExploreByTouchHelper); 336240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 3373018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 3383018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 3393018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public CellState[][] getCellStates() { 3403018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek return mCellStates; 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the view is in stealth mode. 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInStealthMode() { 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInStealthMode; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the view has tactile feedback enabled. 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isTactileFeedbackEnabled() { 354aef555bcf26e770e37f2065913084588fb92c6fbJim Miller return mEnableHapticFeedback; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set whether the view is in stealth mode. If true, there will be no 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * visible feedback as the user enters the pattern. 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inStealthMode Whether in stealth mode. 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setInStealthMode(boolean inStealthMode) { 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = inStealthMode; 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set whether the view will use tactile feedback. If true, there will be 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * tactile feedback as the user enters the pattern. 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tactileFeedbackEnabled Whether tactile feedback is enabled 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) { 374aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mEnableHapticFeedback = tactileFeedbackEnabled; 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the call back for pattern detection. 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param onPatternListener The call back. 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnPatternListener( 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OnPatternListener onPatternListener) { 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPatternListener = onPatternListener; 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the pattern explicitely (rather than waiting for the user to input 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a pattern). 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param displayMode How to display the pattern. 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pattern The pattern. 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPattern(DisplayMode displayMode, List<Cell> pattern) { 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.clear(); 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.addAll(pattern); 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Cell cell : pattern) { 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true; 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDisplayMode(displayMode); 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the display mode of the current pattern. This can be useful, for 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, after detecting a pattern to tell this view whether change the 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in progress result to correct or wrong. 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param displayMode The display mode. 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setDisplayMode(DisplayMode displayMode) { 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = displayMode; 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (displayMode == DisplayMode.Animate) { 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPattern.size() == 0) { 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("you must have a pattern to " 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "animate if you want to set the display mode to animate"); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAnimatingPeriodStart = SystemClock.elapsedRealtime(); 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell first = mPattern.get(0); 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressX = getCenterXForColumn(first.getColumn()); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressY = getCenterYForRow(first.getRow()); 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 425613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void startCellStateAnimation(CellState cellState, float startAlpha, float endAlpha, 426613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startTranslationY, float endTranslationY, float startScale, float endScale, 427613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, 428613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi Interpolator interpolator, Runnable finishRunnable) { 429613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (isHardwareAccelerated()) { 430613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startCellStateAnimationHw(cellState, startAlpha, endAlpha, startTranslationY, 431613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi endTranslationY, startScale, endScale, delay, duration, interpolator, 432613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable); 433613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } else { 434613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startCellStateAnimationSw(cellState, startAlpha, endAlpha, startTranslationY, 435613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi endTranslationY, startScale, endScale, delay, duration, interpolator, 436613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable); 437613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 438613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 439613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 440613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startCellStateAnimationSw(final CellState cellState, 441613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi final float startAlpha, final float endAlpha, 442613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi final float startTranslationY, final float endTranslationY, 443613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi final float startScale, final float endScale, 444613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) { 445613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.alpha = startAlpha; 446613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.translationY = startTranslationY; 447613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius = mDotSize/2 * startScale; 448613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); 449613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setDuration(duration); 450613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setStartDelay(delay); 451613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setInterpolator(interpolator); 452613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 453613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 454613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 455613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float t = (float) animation.getAnimatedValue(); 456613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.alpha = (1 - t) * startAlpha + t * endAlpha; 457613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.translationY = (1 - t) * startTranslationY + t * endTranslationY; 458613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius = mDotSize/2 * ((1 - t) * startScale + t * endScale); 459613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi invalidate(); 460613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 461613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 462613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.addListener(new AnimatorListenerAdapter() { 463613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 464613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void onAnimationEnd(Animator animation) { 465613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (finishRunnable != null) { 466613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable.run(); 467613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 468613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 469613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 470613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.start(); 471613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 472613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 473613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startCellStateAnimationHw(final CellState cellState, 474613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startAlpha, float endAlpha, 475613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startTranslationY, float endTranslationY, 476613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startScale, float endScale, 477613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) { 478613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.alpha = endAlpha; 479613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.translationY = endTranslationY; 480613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius = mDotSize/2 * endScale; 481613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwAnimating = true; 482613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwCenterY = CanvasProperty.createFloat( 483613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi getCenterYForRow(cellState.row) + startTranslationY); 484613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwCenterX = CanvasProperty.createFloat(getCenterXForColumn(cellState.col)); 485613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwRadius = CanvasProperty.createFloat(mDotSize/2 * startScale); 486613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mPaint.setColor(getCurrentColor(false)); 487613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mPaint.setAlpha((int) (startAlpha * 255)); 488613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwPaint = CanvasProperty.createPaint(new Paint(mPaint)); 489613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 490613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRtFloatAnimation(cellState.hwCenterY, 491613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi getCenterYForRow(cellState.row) + endTranslationY, delay, duration, interpolator); 492613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRtFloatAnimation(cellState.hwRadius, mDotSize/2 * endScale, delay, duration, 493613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi interpolator); 494613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRtAlphaAnimation(cellState, endAlpha, delay, duration, interpolator, 495613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi new AnimatorListenerAdapter() { 496613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 497613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void onAnimationEnd(Animator animation) { 498613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwAnimating = false; 499613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (finishRunnable != null) { 500613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable.run(); 501613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 502613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 503613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 504613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 505613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi invalidate(); 506613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 507613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 508613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startRtAlphaAnimation(CellState cellState, float endAlpha, 509613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator, 510613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi Animator.AnimatorListener listener) { 511613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi RenderNodeAnimator animator = new RenderNodeAnimator(cellState.hwPaint, 512613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi RenderNodeAnimator.PAINT_ALPHA, (int) (endAlpha * 255)); 513613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setDuration(duration); 514613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setStartDelay(delay); 515613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setInterpolator(interpolator); 516613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setTarget(this); 517613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.addListener(listener); 518613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.start(); 519613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 520613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 521613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startRtFloatAnimation(CanvasProperty<Float> property, float endValue, 522613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator) { 523613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi RenderNodeAnimator animator = new RenderNodeAnimator(property, endValue); 524613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setDuration(duration); 525613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setStartDelay(delay); 526613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setInterpolator(interpolator); 527613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setTarget(this); 528613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.start(); 529613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 530613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 531530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyCellAdded() { 532240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // sendAccessEvent(R.string.lockscreen_access_pattern_cell_added); 533530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 534530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternCellAdded(mPattern); 535530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 536240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Disable used cells for accessibility as they get added 537240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "ivnalidating root because cell was added."); 538240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mExploreByTouchHelper.invalidateRoot(); 539530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 540530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 541530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternStarted() { 542e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_start); 543530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 544530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternStart(); 545530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 546530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 547530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 548530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternDetected() { 549e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_detected); 550530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 551530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternDetected(mPattern); 552530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 553530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 554530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 555530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternCleared() { 556e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_cleared); 557530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 558530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternCleared(); 559530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 560530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 561530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clear the pattern. 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clearPattern() { 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetPattern(); 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 570240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected boolean dispatchHoverEvent(MotionEvent event) { 571240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Give TouchHelper first right of refusal 572240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller boolean handled = mExploreByTouchHelper.dispatchHoverEvent(event); 573240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return super.dispatchHoverEvent(event) || handled; 574240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 575240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Reset all pattern state. 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetPattern() { 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.clear(); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = DisplayMode.Correct; 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clear the pattern lookup table. 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void clearPatternDrawLookup() { 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[i][j] = false; 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Disable input (for instance when displaying a message that will 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * timeout so user doesn't get view into messy state). 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void disableInput() { 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = false; 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable input. 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enableInput() { 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = true; 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onSizeChanged(int w, int h, int oldw, int oldh) { 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int width = w - mPaddingLeft - mPaddingRight; 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSquareWidth = width / 3.0f; 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 617240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onSizeChanged(" + w + "," + h + ")"); 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int height = h - mPaddingTop - mPaddingBottom; 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSquareHeight = height / 3.0f; 620240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mExploreByTouchHelper.invalidateRoot(); 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6230a0753808ea27955472c2283413fc230bc85595bJim Miller private int resolveMeasured(int measureSpec, int desired) 6240a0753808ea27955472c2283413fc230bc85595bJim Miller { 6250a0753808ea27955472c2283413fc230bc85595bJim Miller int result = 0; 6260a0753808ea27955472c2283413fc230bc85595bJim Miller int specSize = MeasureSpec.getSize(measureSpec); 6270a0753808ea27955472c2283413fc230bc85595bJim Miller switch (MeasureSpec.getMode(measureSpec)) { 6280a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.UNSPECIFIED: 6290a0753808ea27955472c2283413fc230bc85595bJim Miller result = desired; 6300a0753808ea27955472c2283413fc230bc85595bJim Miller break; 6310a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.AT_MOST: 6327bc60abc97f77cc2478f5d19c391ebdb1433a893Peter Ng result = Math.max(specSize, desired); 6330a0753808ea27955472c2283413fc230bc85595bJim Miller break; 6340a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.EXACTLY: 6350a0753808ea27955472c2283413fc230bc85595bJim Miller default: 6361fd16378812792913a6aa6923acbec20037e09ffPhilip Milne result = specSize; 6370a0753808ea27955472c2283413fc230bc85595bJim Miller } 6380a0753808ea27955472c2283413fc230bc85595bJim Miller return result; 6390a0753808ea27955472c2283413fc230bc85595bJim Miller } 6400a0753808ea27955472c2283413fc230bc85595bJim Miller 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 6430d244193bed0c995e2beaff5e217200457b28b9dJim Miller final int minimumWidth = getSuggestedMinimumWidth(); 6440d244193bed0c995e2beaff5e217200457b28b9dJim Miller final int minimumHeight = getSuggestedMinimumHeight(); 6450a0753808ea27955472c2283413fc230bc85595bJim Miller int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth); 6460a0753808ea27955472c2283413fc230bc85595bJim Miller int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight); 6470a0753808ea27955472c2283413fc230bc85595bJim Miller 648bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller switch (mAspect) { 649bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_SQUARE: 6500d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewWidth = viewHeight = Math.min(viewWidth, viewHeight); 651bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 652bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_LOCK_WIDTH: 6530d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewHeight = Math.min(viewWidth, viewHeight); 654bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 655bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_LOCK_HEIGHT: 6560d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewWidth = Math.min(viewWidth, viewHeight); 657bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 658bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } 6590a0753808ea27955472c2283413fc230bc85595bJim Miller // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" + viewHeight); 660bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller setMeasuredDimension(viewWidth, viewHeight); 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determines whether the point x, y will add a new point to the current 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pattern (in addition to finding the cell, also makes heuristic choices 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * such as filling in gaps based on current pattern). 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param x The x coordinate. 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y coordinate. 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell detectAndAddHit(float x, float y) { 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell cell = checkForNewHit(x, y); 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cell != null) { 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // check for gaps in existing pattern 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cell fillInGapCell = null; 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Cell> pattern = mPattern; 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!pattern.isEmpty()) { 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell lastCell = pattern.get(pattern.size() - 1); 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dRow = cell.row - lastCell.row; 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dColumn = cell.column - lastCell.column; 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fillInRow = lastCell.row; 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fillInColumn = lastCell.column; 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) { 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) { 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInGapCell = Cell.of(fillInRow, fillInColumn); 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fillInGapCell != null && 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addCellToPattern(fillInGapCell); 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addCellToPattern(cell); 701aef555bcf26e770e37f2065913084588fb92c6fbJim Miller if (mEnableHapticFeedback) { 702aef555bcf26e770e37f2065913084588fb92c6fbJim Miller performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, 703aef555bcf26e770e37f2065913084588fb92c6fbJim Miller HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING 704aef555bcf26e770e37f2065913084588fb92c6fbJim Miller | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cell; 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void addCellToPattern(Cell newCell) { 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true; 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.add(newCell); 714c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (!mInStealthMode) { 715c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startCellActivatedAnimation(newCell); 716c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 717530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyCellAdded(); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 720c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startCellActivatedAnimation(Cell cell) { 721c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final CellState cellState = mCellStates[cell.row][cell.column]; 722613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator, 723c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cellState, new Runnable() { 724613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 725613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void run() { 726613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192, 727613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mFastOutSlowInInterpolator, 728613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState, null); 729613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 730613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 731c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startLineEndAnimation(cellState, mInProgressX, mInProgressY, 732c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi getCenterXForColumn(cell.column), getCenterYForRow(cell.row)); 733c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 734c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 735c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startLineEndAnimation(final CellState state, 736c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final float startX, final float startY, final float targetX, final float targetY) { 737c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); 738c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 739c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 740c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 741c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float t = (float) animation.getAnimatedValue(); 742c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndX = (1 - t) * startX + t * targetX; 743c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndY = (1 - t) * startY + t * targetY; 744c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi invalidate(); 745c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 746c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 747c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addListener(new AnimatorListenerAdapter() { 748c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 749c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationEnd(Animator animation) { 750c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator = null; 751c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 752c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 753c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setInterpolator(mFastOutSlowInInterpolator); 754c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setDuration(100); 755c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.start(); 756c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator = valueAnimator; 757c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 758c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 759613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startRadiusAnimation(float start, float end, long duration, 760613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi Interpolator interpolator, final CellState state, final Runnable endRunnable) { 761c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end); 762c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 763c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 764c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 765613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi state.radius = (float) animation.getAnimatedValue(); 766c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi invalidate(); 767c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 768c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 769c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (endRunnable != null) { 770c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addListener(new AnimatorListenerAdapter() { 771c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 772c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationEnd(Animator animation) { 773c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi endRunnable.run(); 774c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 775c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 776c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 777c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setInterpolator(interpolator); 778c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setDuration(duration); 779c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.start(); 780c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 781c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // helper method to find which cell a point maps to 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell checkForNewHit(float x, float y) { 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int rowHit = getRowHit(y); 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowHit < 0) { 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int columnHit = getColumnHit(x); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (columnHit < 0) { 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPatternDrawLookup[rowHit][columnHit]) { 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Cell.of(rowHit, columnHit); 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper method to find the row that y falls into. 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y coordinate 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The row that y falls in, or -1 if it falls in no row. 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getRowHit(float y) { 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float squareHeight = mSquareHeight; 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float hitSize = squareHeight * mHitFactor; 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float offset = mPaddingTop + (squareHeight - hitSize) / 2f; 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float hitTop = offset + squareHeight * i; 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (y >= hitTop && y <= hitTop + hitSize) { 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper method to find the column x fallis into. 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param x The x coordinate. 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The column that x falls in, or -1 if it falls in no column. 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getColumnHit(float x) { 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float squareWidth = mSquareWidth; 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float hitSize = squareWidth * mHitFactor; 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float offset = mPaddingLeft + (squareWidth - hitSize) / 2f; 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float hitLeft = offset + squareWidth * i; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (x >= hitLeft && x <= hitLeft + hitSize) { 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 842530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov public boolean onHoverEvent(MotionEvent event) { 843530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) { 844530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov final int action = event.getAction(); 845530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov switch (action) { 846530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: 847530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_DOWN); 848530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 849530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: 850530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_MOVE); 851530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 852530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: 853530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_UP); 854530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 855530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 856530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov onTouchEvent(event); 857530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(action); 858530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 859530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov return super.onHoverEvent(event); 860530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 861530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 862530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov @Override 863aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller public boolean onTouchEvent(MotionEvent event) { 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mInputEnabled || !isEnabled()) { 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 868aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller switch(event.getAction()) { 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_DOWN: 870aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller handleActionDown(event); 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_UP: 873a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley handleActionUp(); 874aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return true; 875aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller case MotionEvent.ACTION_MOVE: 876aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller handleActionMove(event); 877aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return true; 878aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller case MotionEvent.ACTION_CANCEL: 879c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov if (mPatternInProgress) { 880c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov mPatternInProgress = false; 881c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov resetPattern(); 882c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov notifyPatternCleared(); 883c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov } 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (PROFILE_DRAWING) { 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDrawingProfilingStarted) { 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Debug.stopMethodTracing(); 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDrawingProfilingStarted = false; 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 891aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 892aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return false; 893aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 895aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller private void handleActionMove(MotionEvent event) { 896aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // Handle all recent motion events so we don't skip any cells even when the device 897aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // is busy... 898c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final float radius = mPathWidth; 899aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final int historySize = event.getHistorySize(); 9009ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mTmpInvalidateRect.setEmpty(); 9010caa377f4688f175ae22229a10294468610a116eJim Miller boolean invalidateNow = false; 902aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller for (int i = 0; i < historySize + 1; i++) { 903aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float x = i < historySize ? event.getHistoricalX(i) : event.getX(); 904aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float y = i < historySize ? event.getHistoricalY(i) : event.getY(); 905aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Cell hitCell = detectAndAddHit(x, y); 906aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final int patternSize = mPattern.size(); 907530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (hitCell != null && patternSize == 1) { 908aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = true; 909530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternStarted(); 910aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 911aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // note current x and y for rubber banding of in progress patterns 912aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float dx = Math.abs(x - mInProgressX); 913aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float dy = Math.abs(y - mInProgressY); 9140caa377f4688f175ae22229a10294468610a116eJim Miller if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) { 9150caa377f4688f175ae22229a10294468610a116eJim Miller invalidateNow = true; 9160caa377f4688f175ae22229a10294468610a116eJim Miller } 917aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 9180caa377f4688f175ae22229a10294468610a116eJim Miller if (mPatternInProgress && patternSize > 0) { 9190caa377f4688f175ae22229a10294468610a116eJim Miller final ArrayList<Cell> pattern = mPattern; 9200caa377f4688f175ae22229a10294468610a116eJim Miller final Cell lastCell = pattern.get(patternSize - 1); 9219ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float lastCellCenterX = getCenterXForColumn(lastCell.column); 9229ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float lastCellCenterY = getCenterYForRow(lastCell.row); 9230caa377f4688f175ae22229a10294468610a116eJim Miller 9249ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller // Adjust for drawn segment from last cell to (x,y). Radius accounts for line width. 9259ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float left = Math.min(lastCellCenterX, x) - radius; 9269ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float right = Math.max(lastCellCenterX, x) + radius; 9279ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float top = Math.min(lastCellCenterY, y) - radius; 9289ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float bottom = Math.max(lastCellCenterY, y) + radius; 9290caa377f4688f175ae22229a10294468610a116eJim Miller 9300caa377f4688f175ae22229a10294468610a116eJim Miller // Invalidate between the pattern's new cell and the pattern's previous cell 9319ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller if (hitCell != null) { 9320caa377f4688f175ae22229a10294468610a116eJim Miller final float width = mSquareWidth * 0.5f; 9330caa377f4688f175ae22229a10294468610a116eJim Miller final float height = mSquareHeight * 0.5f; 9349ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller final float hitCellCenterX = getCenterXForColumn(hitCell.column); 9359ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller final float hitCellCenterY = getCenterYForRow(hitCell.row); 9369ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller 9379ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller left = Math.min(hitCellCenterX - width, left); 9389ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller right = Math.max(hitCellCenterX + width, right); 9399ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller top = Math.min(hitCellCenterY - height, top); 9409ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller bottom = Math.max(hitCellCenterY + height, bottom); 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9420caa377f4688f175ae22229a10294468610a116eJim Miller 9430caa377f4688f175ae22229a10294468610a116eJim Miller // Invalidate between the pattern's last cell and the previous location 9449ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mTmpInvalidateRect.union(Math.round(left), Math.round(top), 9450caa377f4688f175ae22229a10294468610a116eJim Miller Math.round(right), Math.round(bottom)); 946aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 947aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 9480caa377f4688f175ae22229a10294468610a116eJim Miller mInProgressX = event.getX(); 9490caa377f4688f175ae22229a10294468610a116eJim Miller mInProgressY = event.getY(); 9500caa377f4688f175ae22229a10294468610a116eJim Miller 9510caa377f4688f175ae22229a10294468610a116eJim Miller // To save updates, we only invalidate if the user moved beyond a certain amount. 9520caa377f4688f175ae22229a10294468610a116eJim Miller if (invalidateNow) { 9539ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mInvalidate.union(mTmpInvalidateRect); 9549ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller invalidate(mInvalidate); 9559ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mInvalidate.set(mTmpInvalidateRect); 9560caa377f4688f175ae22229a10294468610a116eJim Miller } 957aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 958aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 959530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void sendAccessEvent(int resId) { 960e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv announceForAccessibility(mContext.getString(resId)); 961530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 962530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 963a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private void handleActionUp() { 964aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // report pattern detected 965530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (!mPattern.isEmpty()) { 966aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = false; 967c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cancelLineAnimations(); 968530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternDetected(); 969aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller invalidate(); 970aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 971aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (PROFILE_DRAWING) { 972aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (mDrawingProfilingStarted) { 973aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Debug.stopMethodTracing(); 974aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mDrawingProfilingStarted = false; 975aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 976aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 977aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 978aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 979c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void cancelLineAnimations() { 980c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi for (int i = 0; i < 3; i++) { 981c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi for (int j = 0; j < 3; j++) { 982c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState state = mCellStates[i][j]; 983c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (state.lineAnimator != null) { 984c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator.cancel(); 985c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndX = Float.MIN_VALUE; 986c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndY = Float.MIN_VALUE; 987c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 988c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 989c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 990c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 991aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller private void handleActionDown(MotionEvent event) { 992aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller resetPattern(); 993aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float x = event.getX(); 994aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float y = event.getY(); 995aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final Cell hitCell = detectAndAddHit(x, y); 996530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (hitCell != null) { 997aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = true; 998aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternDisplayMode = DisplayMode.Correct; 999530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternStarted(); 1000c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov } else if (mPatternInProgress) { 1001aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternInProgress = false; 1002530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternCleared(); 1003aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1004aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (hitCell != null) { 1005aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float startX = getCenterXForColumn(hitCell.column); 1006aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float startY = getCenterYForRow(hitCell.row); 1007aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 1008aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float widthOffset = mSquareWidth / 2f; 1009aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float heightOffset = mSquareHeight / 2f; 1010aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 1011aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller invalidate((int) (startX - widthOffset), (int) (startY - heightOffset), 1012aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller (int) (startX + widthOffset), (int) (startY + heightOffset)); 1013aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1014aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mInProgressX = x; 1015aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mInProgressY = y; 1016aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (PROFILE_DRAWING) { 1017aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (!mDrawingProfilingStarted) { 1018aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Debug.startMethodTracing("LockPatternDrawing"); 1019aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mDrawingProfilingStarted = true; 1020aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getCenterXForColumn(int column) { 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f; 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getCenterYForRow(int row) { 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaddingTop + row * mSquareHeight + mSquareHeight / 2f; 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onDraw(Canvas canvas) { 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Cell> pattern = mPattern; 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = pattern.size(); 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean[][] drawLookup = mPatternDrawLookup; 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPatternDisplayMode == DisplayMode.Animate) { 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out which circles to draw 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // + 1 so we pause on complete pattern 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING; 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spotInCycle = (int) (SystemClock.elapsedRealtime() - 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAnimatingPeriodStart) % oneCycle; 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING; 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numCircles; i++) { 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell cell = pattern.get(i); 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project drawLookup[cell.getRow()][cell.getColumn()] = true; 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out in progress portion of ghosting line 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean needToUpdateInProgressPoint = numCircles > 0 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && numCircles < count; 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needToUpdateInProgressPoint) { 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float percentageOfNextCircle = 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING)) / 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MILLIS_PER_CIRCLE_ANIMATING; 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell currentCell = pattern.get(numCircles - 1); 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float centerX = getCenterXForColumn(currentCell.column); 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float centerY = getCenterYForRow(currentCell.row); 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell nextCell = pattern.get(numCircles); 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float dx = percentageOfNextCircle * 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (getCenterXForColumn(nextCell.column) - centerX); 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float dy = percentageOfNextCircle * 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (getCenterYForRow(nextCell.row) - centerY); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressX = centerX + dx; 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressY = centerY + dy; 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Infinite loop here... 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Path currentPath = mCurrentPath; 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project currentPath.rewind(); 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // draw the circles 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 1085c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float centerY = getCenterYForRow(i); 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 1087c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState cellState = mCellStates[i][j]; 1088c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float centerX = getCenterXForColumn(j); 1089613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float translationY = cellState.translationY; 1090613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (isHardwareAccelerated() && cellState.hwAnimating) { 1091613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas; 1092613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY, 1093613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwRadius, cellState.hwPaint); 1094613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } else { 1095613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi drawCircle(canvas, (int) centerX, (int) centerY + translationY, 1096613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius, drawLookup[i][j], cellState.alpha); 1097613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 1098613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 110208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // TODO: the path should be created and cached every time we hit-detect a cell 110308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // only the last segment of the path should be computed here 1104e2d71e45209a4ac0787b360c4b0eb4d617863f3fAdrian Roos // draw the path of the pattern (unless we are in stealth mode) 1105e2d71e45209a4ac0787b360c4b0eb4d617863f3fAdrian Roos final boolean drawPath = !mInStealthMode; 110608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (drawPath) { 1108c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setColor(getCurrentColor(true /* partOfPattern */)); 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 111008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller boolean anyCircles = false; 1111c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float lastX = 0f; 1112c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float lastY = 0f; 111308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller for (int i = 0; i < count; i++) { 111408a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller Cell cell = pattern.get(i); 111508a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 111608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // only draw the part of the pattern stored in 111708a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // the lookup table (this is only different in the case 111808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // of animation). 111908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller if (!drawLookup[cell.row][cell.column]) { 112008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller break; 112108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 112208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller anyCircles = true; 112308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 112408a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller float centerX = getCenterXForColumn(cell.column); 112508a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller float centerY = getCenterYForRow(cell.row); 1126c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (i != 0) { 1127c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState state = mCellStates[cell.row][cell.column]; 1128c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.rewind(); 1129c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.moveTo(lastX, lastY); 1130c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (state.lineEndX != Float.MIN_VALUE && state.lineEndY != Float.MIN_VALUE) { 1131c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.lineTo(state.lineEndX, state.lineEndY); 1132c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } else { 1133c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.lineTo(centerX, centerY); 1134c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 1135c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawPath(currentPath, mPathPaint); 113608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 1137c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi lastX = centerX; 1138c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi lastY = centerY; 113908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 114008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 1141c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi // draw last in progress section 114208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate) 114308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller && anyCircles) { 1144c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.rewind(); 1145c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.moveTo(lastX, lastY); 114608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller currentPath.lineTo(mInProgressX, mInProgressY); 1147c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 1148c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setAlpha((int) (calculateLastSegmentAlpha( 1149c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mInProgressX, mInProgressY, lastX, lastY) * 255f)); 1150c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawPath(currentPath, mPathPaint); 115108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 115208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1155c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private float calculateLastSegmentAlpha(float x, float y, float lastX, float lastY) { 1156c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float diffX = x - lastX; 1157c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float diffY = y - lastY; 1158c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float dist = (float) Math.sqrt(diffX*diffX + diffY*diffY); 1159c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float frac = dist/mSquareWidth; 1160c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f)); 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1163c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int getCurrentColor(boolean partOfPattern) { 1164c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (!partOfPattern || mInStealthMode || mPatternInProgress) { 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // unselected circle 1166c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mRegularColor; 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPatternDisplayMode == DisplayMode.Wrong) { 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the pattern is wrong 1169c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mErrorColor; 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPatternDisplayMode == DisplayMode.Correct || 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode == DisplayMode.Animate) { 1172c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mSuccessColor; 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("unknown display mode " + mPatternDisplayMode); 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1176c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1178c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi /** 1179c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi * @param partOfPattern Whether this circle is part of the pattern. 1180c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi */ 1181613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void drawCircle(Canvas canvas, float centerX, float centerY, float radius, 1182c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi boolean partOfPattern, float alpha) { 1183c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPaint.setColor(getCurrentColor(partOfPattern)); 1184c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPaint.setAlpha((int) (alpha * 255)); 1185613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi canvas.drawCircle(centerX, centerY, radius, mPaint); 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected Parcelable onSaveInstanceState() { 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Parcelable superState = super.onSaveInstanceState(); 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(superState, 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LockPatternUtils.patternToString(mPattern), 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode.ordinal(), 1194aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mInputEnabled, mInStealthMode, mEnableHapticFeedback); 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onRestoreInstanceState(Parcelable state) { 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final SavedState ss = (SavedState) state; 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onRestoreInstanceState(ss.getSuperState()); 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setPattern( 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DisplayMode.Correct, 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LockPatternUtils.stringToPattern(ss.getSerializedPattern())); 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = ss.isInputEnabled(); 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = ss.isInStealthMode(); 1207aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mEnableHapticFeedback = ss.isTactileFeedbackEnabled(); 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The parecelable for saving and restoring a lock pattern view. 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class SavedState extends BaseSavedState { 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String mSerializedPattern; 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int mDisplayMode; 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mInputEnabled; 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mInStealthMode; 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mTactileFeedbackEnabled; 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link LockPatternView#onSaveInstanceState()} 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcelable superState, String serializedPattern, int displayMode, 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) { 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(superState); 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSerializedPattern = serializedPattern; 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayMode = displayMode; 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = inputEnabled; 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = inStealthMode; 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTactileFeedbackEnabled = tactileFeedbackEnabled; 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link #CREATOR} 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcel in) { 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(in); 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSerializedPattern = in.readString(); 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayMode = in.readInt(); 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = (Boolean) in.readValue(null); 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = (Boolean) in.readValue(null); 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTactileFeedbackEnabled = (Boolean) in.readValue(null); 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1245bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getSerializedPattern() { 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSerializedPattern; 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDisplayMode() { 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDisplayMode; 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInputEnabled() { 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInputEnabled; 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInStealthMode() { 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInStealthMode; 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isTactileFeedbackEnabled(){ 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mTactileFeedbackEnabled; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel dest, int flags) { 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.writeToParcel(dest, flags); 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeString(mSerializedPattern); 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeInt(mDisplayMode); 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mInputEnabled); 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mInStealthMode); 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mTactileFeedbackEnabled); 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1276a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @SuppressWarnings({ "unused", "hiding" }) // Found using reflection 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Parcelable.Creator<SavedState> CREATOR = 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Creator<SavedState>() { 1279240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1280240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public SavedState createFromParcel(Parcel in) { 1281240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return new SavedState(in); 1282240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1284240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1285240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public SavedState[] newArray(int size) { 1286240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return new SavedState[size]; 1287240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1288240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller }; 1289240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1290240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1291240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private final class PatternExploreByTouchHelper extends ExploreByTouchHelper { 1292240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private Rect mTempRect = new Rect(); 1293240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private HashMap<Integer, VirtualViewContainer> mItems = new HashMap<Integer, 1294240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller VirtualViewContainer>(); 1295240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1296240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller class VirtualViewContainer { 1297240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public VirtualViewContainer(CharSequence description) { 1298240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller this.description = description; 1299240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1300240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller CharSequence description; 1301240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller }; 1302240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1303240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public PatternExploreByTouchHelper(View forView) { 1304240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller super(forView); 1305240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1306240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1307240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1308240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected int getVirtualViewAt(float x, float y) { 1309240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // This must use the same hit logic for the screen to ensure consistency whether 1310240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // accessibility is on or off. 1311240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int id = getVirtualViewIdForHit(x, y); 1312240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return id; 1313240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1314240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1315240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1316240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected void getVisibleVirtualViews(IntArray virtualViewIds) { 1317240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "getVisibleVirtualViews(len=" + virtualViewIds.size() + ")"); 1318240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller for (int i = VIRTUAL_BASE_VIEW_ID; i < VIRTUAL_BASE_VIEW_ID + 9; i++) { 1319240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (!mItems.containsKey(i)) { 1320240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller VirtualViewContainer item = new VirtualViewContainer(getTextForVirtualView(i)); 1321240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mItems.put(i, item); 1322240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1323240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Add all views. As views are added to the pattern, we remove them 1324240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // from notification by making them non-clickable below. 1325240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller virtualViewIds.add(i); 1326240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1327240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1328240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1329240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1330240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 1331240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onPopulateEventForVirtualView(" + virtualViewId + ")"); 1332240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Announce this view 1333240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (mItems.containsKey(virtualViewId)) { 1334240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller CharSequence contentDescription = mItems.get(virtualViewId).description; 1335240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller event.getText().add(contentDescription); 1336240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1337240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1338240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1339240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1340240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 1341240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onPopulateNodeForVirtualView(view=" + virtualViewId + ")"); 1342240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1343240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Node and event text and content descriptions are usually 1344240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // identical, so we'll use the exact same string as before. 1345240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setText(getTextForVirtualView(virtualViewId)); 1346240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setContentDescription(getTextForVirtualView(virtualViewId)); 1347240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1348240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (isClickable(virtualViewId)) { 1349240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Mark this node of interest by making it clickable. 1350240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.addAction(AccessibilityAction.ACTION_CLICK); 1351240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setClickable(isClickable(virtualViewId)); 1352240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1353240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1354240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Compute bounds for this object 1355240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final Rect bounds = getBoundsForVirtualView(virtualViewId); 1356240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "bounds:" + bounds.toString()); 1357240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setBoundsInParent(bounds); 1358240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1359240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1360240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private boolean isClickable(int virtualViewId) { 1361240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Dots are clickable if they're not part of the current pattern. 1362240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (virtualViewId != ExploreByTouchHelper.INVALID_ID) { 1363240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int row = (virtualViewId - VIRTUAL_BASE_VIEW_ID) / 3; 1364240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int col = (virtualViewId - VIRTUAL_BASE_VIEW_ID) % 3; 1365240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return !mPatternDrawLookup[row][col]; 1366240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1367240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return false; 1368240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1369240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1370240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1371240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 1372240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller Bundle arguments) { 1373240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onPerformActionForVirtualView(id=" + virtualViewId 1374240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + ", action=" + action); 1375240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller switch (action) { 1376240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller case AccessibilityNodeInfo.ACTION_CLICK: 1377240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Click handling should be consistent with 1378240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // onTouchEvent(). This ensures that the view works the 1379240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // same whether accessibility is turned on or off. 1380240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return onItemClicked(virtualViewId); 1381240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller default: 1382240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "*** action not handled in " 1383240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + "onPerformActionForVirtualView(viewId=" 1384240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + virtualViewId + "action=" + action + ")"); 1385240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1386240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return false; 1387240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1388240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1389240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller boolean onItemClicked(int index) { 1390240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onItemClicked(" + index + ")"); 1391240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1392240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Since the item's checked state is exposed to accessibility 1393240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // services through its AccessibilityNodeInfo, we need to invalidate 1394240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // the item's virtual view. At some point in the future, the 1395240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // framework will obtain an updated version of the virtual view. 1396240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller invalidateVirtualView(index); 1397240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1398240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // We need to let the framework know what type of event 1399240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // happened. Accessibility services may use this event to provide 1400240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // appropriate feedback to the user. 1401240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller sendEventForVirtualView(index, AccessibilityEvent.TYPE_VIEW_CLICKED); 1402240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1403240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return true; 1404240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1405240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1406240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private Rect getBoundsForVirtualView(int virtualViewId) { 1407240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int ordinal = virtualViewId - VIRTUAL_BASE_VIEW_ID; 1408240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final Rect bounds = mTempRect; 1409240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int row = ordinal / 3; 1410240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int col = ordinal % 3; 1411240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final CellState cell = mCellStates[row][col]; 1412240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float centerX = getCenterXForColumn(col); 1413240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float centerY = getCenterYForRow(row); 1414240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float cellheight = mSquareHeight * mHitFactor * 0.5f; 1415240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float cellwidth = mSquareWidth * mHitFactor * 0.5f; 1416240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.left = (int) (centerX - cellwidth); 1417240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.right = (int) (centerX + cellwidth); 1418240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.top = (int) (centerY - cellheight); 1419240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.bottom = (int) (centerY + cellheight); 1420240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return bounds; 1421240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1422240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1423240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private boolean shouldSpeakPassword() { 1424240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final boolean speakPassword = Settings.Secure.getIntForUser( 1425240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0, 1426240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller UserHandle.USER_CURRENT_OR_SELF) != 0; 1427240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final boolean hasHeadphones = mAudioManager != null ? 1428240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) 1429240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller : false; 1430240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return speakPassword || hasHeadphones; 1431240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1432240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1433240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private CharSequence getTextForVirtualView(int virtualViewId) { 1434240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final Resources res = getResources(); 1435240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return shouldSpeakPassword() ? res.getString( 1436240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller R.string.lockscreen_access_pattern_cell_added_verbose, virtualViewId) 1437240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller : res.getString(R.string.lockscreen_access_pattern_cell_added); 1438240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1439240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1440240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller /** 1441240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * Helper method to find which cell a point maps to 1442240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * 1443240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * if there's no hit. 1444240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * @param x touch position x 1445240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * @param y touch position y 1446240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * @return VIRTUAL_BASE_VIEW_ID+id or 0 if no view was hit 1447240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller */ 1448240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private int getVirtualViewIdForHit(float x, float y) { 1449240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int rowHit = getRowHit(y); 1450240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (rowHit < 0) { 1451240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return ExploreByTouchHelper.INVALID_ID; 1452240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1453240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int columnHit = getColumnHit(x); 1454240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (columnHit < 0) { 1455240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return ExploreByTouchHelper.INVALID_ID; 1456240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1457240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller boolean dotAvailable = mPatternDrawLookup[rowHit][columnHit]; 1458240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int dotId = (rowHit * 3 + columnHit) + VIRTUAL_BASE_VIEW_ID; 1459240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int view = dotAvailable ? dotId : ExploreByTouchHelper.INVALID_ID; 1460240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "getVirtualViewIdForHit(" + x + "," + y + ") => " 1461240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + view + "avail =" + dotAvailable); 1462240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return view; 1463240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1466