LockPatternView.java revision dcc1f1941711be22960e0f58ec75215237e0a11e
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; 2788a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanhimport android.graphics.drawable.Drawable; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Path; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 31240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.media.AudioManager; 32240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.os.Bundle; 336a109b4874b79d9bf8f5d990bfe831a59e5a83dcKarl Rosaenimport android.os.Debug; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 37240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.os.UserHandle; 38240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.provider.Settings; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 40240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.util.IntArray; 41240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.util.Log; 42f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaverimport android.util.SparseArray; 43613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggiimport android.view.DisplayListCanvas; 44aef555bcf26e770e37f2065913084588fb92c6fbJim Millerimport android.view.HapticFeedbackConstants; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 46613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggiimport android.view.RenderNodeAnimator; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 48240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.view.accessibility.AccessibilityEvent; 49530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 50240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.view.accessibility.AccessibilityNodeInfo; 51240a295f12a04e888b09f1d815fbd72cffbef974Jim Millerimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 52c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.view.animation.AnimationUtils; 53c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggiimport android.view.animation.Interpolator; 54530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 55530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganovimport com.android.internal.R; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Displays and detects the user's unlock attempt, which is a drag of a finger 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * across 9 regions of the screen. 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Is also capable of displaying a static pattern in "in progress", "wrong" or 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "correct" states. 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class LockPatternView extends View { 68bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller // Aspect to use when rendering this view 69bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_SQUARE = 0; // View will be the minimum of width/height 70bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_LOCK_WIDTH = 1; // Fixed width; height will be minimum of (w,h) 71bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h) 72bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean PROFILE_DRAWING = false; 743018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek private final CellState[][] mCellStates; 75c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 76c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mDotSize; 77c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mDotSizeActivated; 78c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private final int mPathWidth; 79c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDrawingProfilingStarted = false; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 82a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Paint mPaint = new Paint(); 83a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Paint mPathPaint = new Paint(); 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How many milliseconds we spend animating each circle of a lock pattern 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if the animating mode is set. The entire animation should take this 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * constant * the length of the pattern to complete. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MILLIS_PER_CIRCLE_ANIMATING = 700; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 920caa377f4688f175ae22229a10294468610a116eJim Miller /** 930caa377f4688f175ae22229a10294468610a116eJim Miller * This can be used to avoid updating the display for very small motions or noisy panels. 940caa377f4688f175ae22229a10294468610a116eJim Miller * It didn't seem to have much impact on the devices tested, so currently set to 0. 950caa377f4688f175ae22229a10294468610a116eJim Miller */ 960caa377f4688f175ae22229a10294468610a116eJim Miller private static final float DRAG_THRESHHOLD = 0.0f; 97240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public static final int VIRTUAL_BASE_VIEW_ID = 1; 98d2def946390505077766e34b6df4a529b25fdc23Adrian Roos public static final boolean DEBUG_A11Y = false; 99240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private static final String TAG = "LockPatternView"; 1000caa377f4688f175ae22229a10294468610a116eJim Miller 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnPatternListener mOnPatternListener; 102a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Lookup table for the circles of the pattern we are currently drawing. 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will be the cells of the complete pattern unless we are animating, 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in which case we use this to hold the cells we are drawing for the in 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * progress animation. 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 110a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final boolean[][] mPatternDrawLookup = new boolean[3][3]; 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the in progress point: 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - during interaction: where the user's finger is 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * - during animation: the current tip of the animating line 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mInProgressX = -1; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mInProgressY = -1; 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mAnimatingPeriodStart; 121dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan private long[] mLineFadeStart = new long[9]; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private DisplayMode mPatternDisplayMode = DisplayMode.Correct; 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInputEnabled = true; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInStealthMode = false; 126aef555bcf26e770e37f2065913084588fb92c6fbJim Miller private boolean mEnableHapticFeedback = true; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mPatternInProgress = false; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mHitFactor = 0.6f; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSquareWidth; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSquareHeight; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Path mCurrentPath = new Path(); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Rect mInvalidate = new Rect(); 1369ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller private final Rect mTmpInvalidateRect = new Rect(); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 138bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller private int mAspect; 139c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mRegularColor; 140c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mErrorColor; 141c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int mSuccessColor; 1422cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek 143a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Interpolator mFastOutSlowInInterpolator; 144a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private final Interpolator mLinearOutSlowInInterpolator; 145240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private PatternExploreByTouchHelper mExploreByTouchHelper; 146240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private AudioManager mAudioManager; 147bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 14888a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh private Drawable mSelectedDrawable; 14988a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh private Drawable mNotSelectedDrawable; 15088a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh private boolean mUseLockPatternDrawable; 15188a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Represents a cell in the 3 X 3 matrix of the unlock pattern view. 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 155a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley public static final class Cell { 156a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley final int row; 157a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley final int column; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // keep # objects limited to 9 160a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private static final Cell[][] sCells = createCells(); 161a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley 162a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private static Cell[][] createCells() { 163a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley Cell[][] res = new Cell[3][3]; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 166a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley res[i][j] = new Cell(i, j); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 169a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley return res; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param row The row of the cell. 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param column The column of the cell. 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell(int row, int column) { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange(row, column); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.row = row; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.column = column; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getRow() { 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return row; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getColumn() { 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return column; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 190a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley public static Cell of(int row, int column) { 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange(row, column); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sCells[row][column]; 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void checkRange(int row, int column) { 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (row < 0 || row > 2) { 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("row must be in range 0-2"); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (column < 0 || column > 2) { 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("column must be in range 0-2"); 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 204a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @Override 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "(row=" + row + ",clmn=" + column + ")"; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2103018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public static class CellState { 211613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi int row; 212613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi int col; 213613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi boolean hwAnimating; 214613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Float> hwRadius; 215613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Float> hwCenterX; 216613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Float> hwCenterY; 217613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi CanvasProperty<Paint> hwPaint; 218613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float radius; 219613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float translationY; 220613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float alpha = 1f; 221c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float lineEndX = Float.MIN_VALUE; 222c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public float lineEndY = Float.MIN_VALUE; 223c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public ValueAnimator lineAnimator; 2243018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 2253018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * How to display the current pattern. 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum DisplayMode { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern drawn is correct (i.e draw it in a friendly color) 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Correct, 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Animate the pattern (for demo, and help). 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Animate, 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern is wrong (i.e draw a foreboding color) 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Wrong 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The call back interface for detecting patterns entered by the user. 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static interface OnPatternListener { 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A new pattern has begun. 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternStart(); 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The pattern was cleared. 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternCleared(); 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 26341e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller * The user extended the pattern currently being drawn by one cell. 26441e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller * @param pattern The pattern with newly added cell. 26541e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller */ 26641e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller void onPatternCellAdded(List<Cell> pattern); 26741e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller 26841e8dc02cdde381cc2d7d55bfb56d5c7f72eb86eJim Miller /** 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A pattern was detected from the user. 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pattern The pattern. 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPatternDetected(List<Cell> pattern); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public LockPatternView(Context context) { 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public LockPatternView(Context context, AttributeSet attrs) { 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs); 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28258be7a675b7aa505255f0c91fee755f8290e8363Jason Monk TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView, 28358be7a675b7aa505255f0c91fee755f8290e8363Jason Monk R.attr.lockPatternStyle, R.style.Widget_LockPatternView); 284bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 285bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller final String aspect = a.getString(R.styleable.LockPatternView_aspect); 286bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 287bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller if ("square".equals(aspect)) { 288bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_SQUARE; 289bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else if ("lock_width".equals(aspect)) { 290bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_LOCK_WIDTH; 291bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else if ("lock_height".equals(aspect)) { 292bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_LOCK_HEIGHT; 293bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } else { 294bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller mAspect = ASPECT_SQUARE; 295bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } 296bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setClickable(true); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2992cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setAntiAlias(true); 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setDither(true); 3021cf3594114b1846c97243ff536074c49bbe06061Fabrice Di Meglio 30358be7a675b7aa505255f0c91fee755f8290e8363Jason Monk mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, 0); 30458be7a675b7aa505255f0c91fee755f8290e8363Jason Monk mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, 0); 30558be7a675b7aa505255f0c91fee755f8290e8363Jason Monk mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, 0); 306c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 307c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor); 3082cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPathPaint.setColor(pathColor); 3091cf3594114b1846c97243ff536074c49bbe06061Fabrice Di Meglio 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStyle(Paint.Style.STROKE); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStrokeJoin(Paint.Join.ROUND); 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPathPaint.setStrokeCap(Paint.Cap.ROUND); 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 314c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathWidth = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_line_width); 315c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setStrokeWidth(mPathWidth); 316c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 317c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size); 318c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mDotSizeActivated = getResources().getDimensionPixelSize( 319c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi R.dimen.lock_pattern_dot_size_activated); 32085d630020a29c24f3d51f00b5ce3f701c16f0a45Jim Miller 32188a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mUseLockPatternDrawable = getResources().getBoolean(R.bool.use_lock_pattern_drawable); 32288a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh if (mUseLockPatternDrawable) { 32388a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mSelectedDrawable = getResources().getDrawable(R.drawable.lockscreen_selected); 32488a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mNotSelectedDrawable = getResources().getDrawable(R.drawable.lockscreen_notselected); 32588a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } 32688a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh 3272cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPaint.setAntiAlias(true); 3282cb687e7b9d0cbb1af5ba753453a9a05350a100eSelim Cinek mPaint.setDither(true); 3293018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 3303018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mCellStates = new CellState[3][3]; 3313018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int i = 0; i < 3; i++) { 3323018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek for (int j = 0; j < 3; j++) { 3333018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek mCellStates[i][j] = new CellState(); 334613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mCellStates[i][j].radius = mDotSize/2; 335613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mCellStates[i][j].row = i; 336613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mCellStates[i][j].col = j; 3373018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 3383018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 339c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 340c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mFastOutSlowInInterpolator = 341c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); 342c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mLinearOutSlowInInterpolator = 343c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); 344240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mExploreByTouchHelper = new PatternExploreByTouchHelper(this); 345240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller setAccessibilityDelegate(mExploreByTouchHelper); 346240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 347ac010478a6e64407ca0f18fcab4b2aff2ba0274dJim Miller a.recycle(); 3483018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek } 3493018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek 3503018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek public CellState[][] getCellStates() { 3513018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek return mCellStates; 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the view is in stealth mode. 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInStealthMode() { 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInStealthMode; 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the view has tactile feedback enabled. 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isTactileFeedbackEnabled() { 365aef555bcf26e770e37f2065913084588fb92c6fbJim Miller return mEnableHapticFeedback; 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set whether the view is in stealth mode. If true, there will be no 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * visible feedback as the user enters the pattern. 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inStealthMode Whether in stealth mode. 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setInStealthMode(boolean inStealthMode) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = inStealthMode; 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set whether the view will use tactile feedback. If true, there will be 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * tactile feedback as the user enters the pattern. 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param tactileFeedbackEnabled Whether tactile feedback is enabled 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) { 385aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mEnableHapticFeedback = tactileFeedbackEnabled; 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the call back for pattern detection. 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param onPatternListener The call back. 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnPatternListener( 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OnPatternListener onPatternListener) { 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPatternListener = onPatternListener; 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the pattern explicitely (rather than waiting for the user to input 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a pattern). 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param displayMode How to display the pattern. 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param pattern The pattern. 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPattern(DisplayMode displayMode, List<Cell> pattern) { 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.clear(); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.addAll(pattern); 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Cell cell : pattern) { 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true; 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDisplayMode(displayMode); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the display mode of the current pattern. This can be useful, for 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance, after detecting a pattern to tell this view whether change the 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in progress result to correct or wrong. 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param displayMode The display mode. 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setDisplayMode(DisplayMode displayMode) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = displayMode; 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (displayMode == DisplayMode.Animate) { 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPattern.size() == 0) { 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("you must have a pattern to " 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "animate if you want to set the display mode to animate"); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAnimatingPeriodStart = SystemClock.elapsedRealtime(); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell first = mPattern.get(0); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressX = getCenterXForColumn(first.getColumn()); 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressY = getCenterYForRow(first.getRow()); 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 436613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void startCellStateAnimation(CellState cellState, float startAlpha, float endAlpha, 437613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startTranslationY, float endTranslationY, float startScale, float endScale, 438613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, 439613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi Interpolator interpolator, Runnable finishRunnable) { 440613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (isHardwareAccelerated()) { 441613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startCellStateAnimationHw(cellState, startAlpha, endAlpha, startTranslationY, 442613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi endTranslationY, startScale, endScale, delay, duration, interpolator, 443613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable); 444613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } else { 445613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startCellStateAnimationSw(cellState, startAlpha, endAlpha, startTranslationY, 446613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi endTranslationY, startScale, endScale, delay, duration, interpolator, 447613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable); 448613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 449613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 450613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 451613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startCellStateAnimationSw(final CellState cellState, 452613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi final float startAlpha, final float endAlpha, 453613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi final float startTranslationY, final float endTranslationY, 454613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi final float startScale, final float endScale, 455613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) { 456613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.alpha = startAlpha; 457613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.translationY = startTranslationY; 458613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius = mDotSize/2 * startScale; 459613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); 460613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setDuration(duration); 461613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setStartDelay(delay); 462613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setInterpolator(interpolator); 463613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 464613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 465613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 466613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float t = (float) animation.getAnimatedValue(); 467613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.alpha = (1 - t) * startAlpha + t * endAlpha; 468613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.translationY = (1 - t) * startTranslationY + t * endTranslationY; 469613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius = mDotSize/2 * ((1 - t) * startScale + t * endScale); 470613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi invalidate(); 471613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 472613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 473613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.addListener(new AnimatorListenerAdapter() { 474613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 475613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void onAnimationEnd(Animator animation) { 476613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (finishRunnable != null) { 477613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable.run(); 478613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 479613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 480613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 481613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.start(); 482613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 483613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 484613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startCellStateAnimationHw(final CellState cellState, 485613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startAlpha, float endAlpha, 486613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startTranslationY, float endTranslationY, 487613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float startScale, float endScale, 488613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) { 489613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.alpha = endAlpha; 490613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.translationY = endTranslationY; 491613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.radius = mDotSize/2 * endScale; 492613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwAnimating = true; 493613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwCenterY = CanvasProperty.createFloat( 494613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi getCenterYForRow(cellState.row) + startTranslationY); 495613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwCenterX = CanvasProperty.createFloat(getCenterXForColumn(cellState.col)); 496613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwRadius = CanvasProperty.createFloat(mDotSize/2 * startScale); 497613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mPaint.setColor(getCurrentColor(false)); 498613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mPaint.setAlpha((int) (startAlpha * 255)); 499613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwPaint = CanvasProperty.createPaint(new Paint(mPaint)); 500613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 501613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRtFloatAnimation(cellState.hwCenterY, 502613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi getCenterYForRow(cellState.row) + endTranslationY, delay, duration, interpolator); 503613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRtFloatAnimation(cellState.hwRadius, mDotSize/2 * endScale, delay, duration, 504613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi interpolator); 505613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRtAlphaAnimation(cellState, endAlpha, delay, duration, interpolator, 506613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi new AnimatorListenerAdapter() { 507613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 508613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void onAnimationEnd(Animator animation) { 509613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState.hwAnimating = false; 510613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi if (finishRunnable != null) { 511613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi finishRunnable.run(); 512613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 513613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 514613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 515613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 516613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi invalidate(); 517613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 518613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 519613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startRtAlphaAnimation(CellState cellState, float endAlpha, 520613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator, 521613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi Animator.AnimatorListener listener) { 522613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi RenderNodeAnimator animator = new RenderNodeAnimator(cellState.hwPaint, 523613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi RenderNodeAnimator.PAINT_ALPHA, (int) (endAlpha * 255)); 524613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setDuration(duration); 525613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setStartDelay(delay); 526613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setInterpolator(interpolator); 527613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setTarget(this); 528613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.addListener(listener); 529613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.start(); 530613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 531613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 532613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startRtFloatAnimation(CanvasProperty<Float> property, float endValue, 533613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi long delay, long duration, Interpolator interpolator) { 534613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi RenderNodeAnimator animator = new RenderNodeAnimator(property, endValue); 535613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setDuration(duration); 536613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setStartDelay(delay); 537613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setInterpolator(interpolator); 538613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.setTarget(this); 539613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi animator.start(); 540613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 541613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 542530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyCellAdded() { 543240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // sendAccessEvent(R.string.lockscreen_access_pattern_cell_added); 544530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 545530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternCellAdded(mPattern); 546530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 547240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Disable used cells for accessibility as they get added 548240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "ivnalidating root because cell was added."); 549240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mExploreByTouchHelper.invalidateRoot(); 550530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 551530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 552530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternStarted() { 553e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_start); 554530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 555530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternStart(); 556530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 557530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 558530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 559530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternDetected() { 560e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_detected); 561530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 562530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternDetected(mPattern); 563530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 564530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 565530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 566530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void notifyPatternCleared() { 567e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv sendAccessEvent(R.string.lockscreen_access_pattern_cleared); 568530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (mOnPatternListener != null) { 569530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov mOnPatternListener.onPatternCleared(); 570530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 571530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 572530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clear the pattern. 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clearPattern() { 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetPattern(); 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 580240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 581240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected boolean dispatchHoverEvent(MotionEvent event) { 582d2def946390505077766e34b6df4a529b25fdc23Adrian Roos // Dispatch to onHoverEvent first so mPatternInProgress is up to date when the 583d2def946390505077766e34b6df4a529b25fdc23Adrian Roos // helper gets the event. 584d2def946390505077766e34b6df4a529b25fdc23Adrian Roos boolean handled = super.dispatchHoverEvent(event); 585d2def946390505077766e34b6df4a529b25fdc23Adrian Roos handled |= mExploreByTouchHelper.dispatchHoverEvent(event); 586d2def946390505077766e34b6df4a529b25fdc23Adrian Roos return handled; 587240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 588240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Reset all pattern state. 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetPattern() { 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.clear(); 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = DisplayMode.Correct; 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 600dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan * Clear the pattern lookup table. Also reset the line fade start times for 601dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan * the next attempt. 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void clearPatternDrawLookup() { 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[i][j] = false; 607dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan mLineFadeStart[i+j] = 0; 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Disable input (for instance when displaying a message that will 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * timeout so user doesn't get view into messy state). 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void disableInput() { 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = false; 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable input. 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enableInput() { 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = true; 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onSizeChanged(int w, int h, int oldw, int oldh) { 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int width = w - mPaddingLeft - mPaddingRight; 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSquareWidth = width / 3.0f; 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 632240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onSizeChanged(" + w + "," + h + ")"); 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int height = h - mPaddingTop - mPaddingBottom; 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSquareHeight = height / 3.0f; 635240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller mExploreByTouchHelper.invalidateRoot(); 63688a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh 63788a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh if (mUseLockPatternDrawable) { 63888a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mNotSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height); 63988a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height); 64088a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6430a0753808ea27955472c2283413fc230bc85595bJim Miller private int resolveMeasured(int measureSpec, int desired) 6440a0753808ea27955472c2283413fc230bc85595bJim Miller { 6450a0753808ea27955472c2283413fc230bc85595bJim Miller int result = 0; 6460a0753808ea27955472c2283413fc230bc85595bJim Miller int specSize = MeasureSpec.getSize(measureSpec); 6470a0753808ea27955472c2283413fc230bc85595bJim Miller switch (MeasureSpec.getMode(measureSpec)) { 6480a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.UNSPECIFIED: 6490a0753808ea27955472c2283413fc230bc85595bJim Miller result = desired; 6500a0753808ea27955472c2283413fc230bc85595bJim Miller break; 6510a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.AT_MOST: 6527bc60abc97f77cc2478f5d19c391ebdb1433a893Peter Ng result = Math.max(specSize, desired); 6530a0753808ea27955472c2283413fc230bc85595bJim Miller break; 6540a0753808ea27955472c2283413fc230bc85595bJim Miller case MeasureSpec.EXACTLY: 6550a0753808ea27955472c2283413fc230bc85595bJim Miller default: 6561fd16378812792913a6aa6923acbec20037e09ffPhilip Milne result = specSize; 6570a0753808ea27955472c2283413fc230bc85595bJim Miller } 6580a0753808ea27955472c2283413fc230bc85595bJim Miller return result; 6590a0753808ea27955472c2283413fc230bc85595bJim Miller } 6600a0753808ea27955472c2283413fc230bc85595bJim Miller 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 6630d244193bed0c995e2beaff5e217200457b28b9dJim Miller final int minimumWidth = getSuggestedMinimumWidth(); 6640d244193bed0c995e2beaff5e217200457b28b9dJim Miller final int minimumHeight = getSuggestedMinimumHeight(); 6650a0753808ea27955472c2283413fc230bc85595bJim Miller int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth); 6660a0753808ea27955472c2283413fc230bc85595bJim Miller int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight); 6670a0753808ea27955472c2283413fc230bc85595bJim Miller 668bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller switch (mAspect) { 669bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_SQUARE: 6700d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewWidth = viewHeight = Math.min(viewWidth, viewHeight); 671bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 672bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_LOCK_WIDTH: 6730d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewHeight = Math.min(viewWidth, viewHeight); 674bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 675bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller case ASPECT_LOCK_HEIGHT: 6760d244193bed0c995e2beaff5e217200457b28b9dJim Miller viewWidth = Math.min(viewWidth, viewHeight); 677bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller break; 678bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller } 6790a0753808ea27955472c2283413fc230bc85595bJim Miller // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" + viewHeight); 680bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller setMeasuredDimension(viewWidth, viewHeight); 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determines whether the point x, y will add a new point to the current 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pattern (in addition to finding the cell, also makes heuristic choices 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * such as filling in gaps based on current pattern). 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param x The x coordinate. 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y coordinate. 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell detectAndAddHit(float x, float y) { 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell cell = checkForNewHit(x, y); 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cell != null) { 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // check for gaps in existing pattern 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cell fillInGapCell = null; 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Cell> pattern = mPattern; 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!pattern.isEmpty()) { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell lastCell = pattern.get(pattern.size() - 1); 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dRow = cell.row - lastCell.row; 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dColumn = cell.column - lastCell.column; 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fillInRow = lastCell.row; 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fillInColumn = lastCell.column; 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) { 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1); 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) { 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1); 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fillInGapCell = Cell.of(fillInRow, fillInColumn); 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fillInGapCell != null && 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) { 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addCellToPattern(fillInGapCell); 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addCellToPattern(cell); 721aef555bcf26e770e37f2065913084588fb92c6fbJim Miller if (mEnableHapticFeedback) { 722aef555bcf26e770e37f2065913084588fb92c6fbJim Miller performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, 723aef555bcf26e770e37f2065913084588fb92c6fbJim Miller HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING 724aef555bcf26e770e37f2065913084588fb92c6fbJim Miller | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return cell; 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void addCellToPattern(Cell newCell) { 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPattern.add(newCell); 734c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (!mInStealthMode) { 735c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startCellActivatedAnimation(newCell); 736c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 737530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyCellAdded(); 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 740c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startCellActivatedAnimation(Cell cell) { 741c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final CellState cellState = mCellStates[cell.row][cell.column]; 742613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator, 743c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cellState, new Runnable() { 744613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi @Override 745613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi public void run() { 746613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192, 747613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi mFastOutSlowInInterpolator, 748613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi cellState, null); 749613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 750613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi }); 751c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi startLineEndAnimation(cellState, mInProgressX, mInProgressY, 752c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi getCenterXForColumn(cell.column), getCenterYForRow(cell.row)); 753c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 754c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 755c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void startLineEndAnimation(final CellState state, 756c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final float startX, final float startY, final float targetX, final float targetY) { 757c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); 758c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 759c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 760c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 761c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float t = (float) animation.getAnimatedValue(); 762c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndX = (1 - t) * startX + t * targetX; 763c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndY = (1 - t) * startY + t * targetY; 764c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi invalidate(); 765c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 766c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 767c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addListener(new AnimatorListenerAdapter() { 768c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 769c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationEnd(Animator animation) { 770c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator = null; 771c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 772c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 773c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setInterpolator(mFastOutSlowInInterpolator); 774c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setDuration(100); 775c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.start(); 776c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator = valueAnimator; 777c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 778c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 779613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void startRadiusAnimation(float start, float end, long duration, 780613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi Interpolator interpolator, final CellState state, final Runnable endRunnable) { 781c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end); 782c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 783c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 784c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationUpdate(ValueAnimator animation) { 785613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi state.radius = (float) animation.getAnimatedValue(); 786c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi invalidate(); 787c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 788c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 789c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (endRunnable != null) { 790c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.addListener(new AnimatorListenerAdapter() { 791c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi @Override 792c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi public void onAnimationEnd(Animator animation) { 793c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi endRunnable.run(); 794c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 795c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi }); 796c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 797c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setInterpolator(interpolator); 798c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.setDuration(duration); 799c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi valueAnimator.start(); 800c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 801c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // helper method to find which cell a point maps to 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Cell checkForNewHit(float x, float y) { 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int rowHit = getRowHit(y); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowHit < 0) { 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int columnHit = getColumnHit(x); 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (columnHit < 0) { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPatternDrawLookup[rowHit][columnHit]) { 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Cell.of(rowHit, columnHit); 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper method to find the row that y falls into. 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param y The y coordinate 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The row that y falls in, or -1 if it falls in no row. 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getRowHit(float y) { 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float squareHeight = mSquareHeight; 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float hitSize = squareHeight * mHitFactor; 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float offset = mPaddingTop + (squareHeight - 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 hitTop = offset + squareHeight * i; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (y >= hitTop && y <= hitTop + 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 /** 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Helper method to find the column x fallis into. 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param x The x coordinate. 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The column that x falls in, or -1 if it falls in no column. 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getColumnHit(float x) { 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float squareWidth = mSquareWidth; 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float hitSize = squareWidth * mHitFactor; 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float offset = mPaddingLeft + (squareWidth - hitSize) / 2f; 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float hitLeft = offset + squareWidth * i; 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (x >= hitLeft && x <= hitLeft + hitSize) { 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 862530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov public boolean onHoverEvent(MotionEvent event) { 863530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) { 864530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov final int action = event.getAction(); 865530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov switch (action) { 866530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: 867530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_DOWN); 868530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 869530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: 870530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_MOVE); 871530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 872530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: 873530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(MotionEvent.ACTION_UP); 874530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov break; 875530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 876530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov onTouchEvent(event); 877530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov event.setAction(action); 878530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 879530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov return super.onHoverEvent(event); 880530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 881530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 882530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov @Override 883aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller public boolean onTouchEvent(MotionEvent event) { 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mInputEnabled || !isEnabled()) { 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 888aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller switch(event.getAction()) { 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_DOWN: 890aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller handleActionDown(event); 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_UP: 893a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley handleActionUp(); 894aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return true; 895aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller case MotionEvent.ACTION_MOVE: 896aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller handleActionMove(event); 897aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return true; 898aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller case MotionEvent.ACTION_CANCEL: 899c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov if (mPatternInProgress) { 900d2def946390505077766e34b6df4a529b25fdc23Adrian Roos setPatternInProgress(false); 901c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov resetPattern(); 902c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov notifyPatternCleared(); 903c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov } 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (PROFILE_DRAWING) { 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDrawingProfilingStarted) { 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Debug.stopMethodTracing(); 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDrawingProfilingStarted = false; 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 911aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 912aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller return false; 913aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 915d2def946390505077766e34b6df4a529b25fdc23Adrian Roos private void setPatternInProgress(boolean progress) { 916d2def946390505077766e34b6df4a529b25fdc23Adrian Roos mPatternInProgress = progress; 917d2def946390505077766e34b6df4a529b25fdc23Adrian Roos mExploreByTouchHelper.invalidateRoot(); 918d2def946390505077766e34b6df4a529b25fdc23Adrian Roos } 919d2def946390505077766e34b6df4a529b25fdc23Adrian Roos 920aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller private void handleActionMove(MotionEvent event) { 921aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // Handle all recent motion events so we don't skip any cells even when the device 922aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // is busy... 923c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi final float radius = mPathWidth; 924aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final int historySize = event.getHistorySize(); 9259ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mTmpInvalidateRect.setEmpty(); 9260caa377f4688f175ae22229a10294468610a116eJim Miller boolean invalidateNow = false; 927aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller for (int i = 0; i < historySize + 1; i++) { 928aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float x = i < historySize ? event.getHistoricalX(i) : event.getX(); 929aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float y = i < historySize ? event.getHistoricalY(i) : event.getY(); 930aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Cell hitCell = detectAndAddHit(x, y); 931aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final int patternSize = mPattern.size(); 932530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (hitCell != null && patternSize == 1) { 933d2def946390505077766e34b6df4a529b25fdc23Adrian Roos setPatternInProgress(true); 934530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternStarted(); 935aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 936aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // note current x and y for rubber banding of in progress patterns 937aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float dx = Math.abs(x - mInProgressX); 938aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float dy = Math.abs(y - mInProgressY); 9390caa377f4688f175ae22229a10294468610a116eJim Miller if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) { 9400caa377f4688f175ae22229a10294468610a116eJim Miller invalidateNow = true; 9410caa377f4688f175ae22229a10294468610a116eJim Miller } 942aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 9430caa377f4688f175ae22229a10294468610a116eJim Miller if (mPatternInProgress && patternSize > 0) { 9440caa377f4688f175ae22229a10294468610a116eJim Miller final ArrayList<Cell> pattern = mPattern; 9450caa377f4688f175ae22229a10294468610a116eJim Miller final Cell lastCell = pattern.get(patternSize - 1); 9469ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float lastCellCenterX = getCenterXForColumn(lastCell.column); 9479ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float lastCellCenterY = getCenterYForRow(lastCell.row); 9480caa377f4688f175ae22229a10294468610a116eJim Miller 9499ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller // Adjust for drawn segment from last cell to (x,y). Radius accounts for line width. 9509ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float left = Math.min(lastCellCenterX, x) - radius; 9519ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float right = Math.max(lastCellCenterX, x) + radius; 9529ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float top = Math.min(lastCellCenterY, y) - radius; 9539ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller float bottom = Math.max(lastCellCenterY, y) + radius; 9540caa377f4688f175ae22229a10294468610a116eJim Miller 9550caa377f4688f175ae22229a10294468610a116eJim Miller // Invalidate between the pattern's new cell and the pattern's previous cell 9569ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller if (hitCell != null) { 9570caa377f4688f175ae22229a10294468610a116eJim Miller final float width = mSquareWidth * 0.5f; 9580caa377f4688f175ae22229a10294468610a116eJim Miller final float height = mSquareHeight * 0.5f; 9599ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller final float hitCellCenterX = getCenterXForColumn(hitCell.column); 9609ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller final float hitCellCenterY = getCenterYForRow(hitCell.row); 9619ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller 9629ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller left = Math.min(hitCellCenterX - width, left); 9639ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller right = Math.max(hitCellCenterX + width, right); 9649ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller top = Math.min(hitCellCenterY - height, top); 9659ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller bottom = Math.max(hitCellCenterY + height, bottom); 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9670caa377f4688f175ae22229a10294468610a116eJim Miller 9680caa377f4688f175ae22229a10294468610a116eJim Miller // Invalidate between the pattern's last cell and the previous location 9699ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mTmpInvalidateRect.union(Math.round(left), Math.round(top), 9700caa377f4688f175ae22229a10294468610a116eJim Miller Math.round(right), Math.round(bottom)); 971aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 972aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 9730caa377f4688f175ae22229a10294468610a116eJim Miller mInProgressX = event.getX(); 9740caa377f4688f175ae22229a10294468610a116eJim Miller mInProgressY = event.getY(); 9750caa377f4688f175ae22229a10294468610a116eJim Miller 9760caa377f4688f175ae22229a10294468610a116eJim Miller // To save updates, we only invalidate if the user moved beyond a certain amount. 9770caa377f4688f175ae22229a10294468610a116eJim Miller if (invalidateNow) { 9789ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mInvalidate.union(mTmpInvalidateRect); 9799ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller invalidate(mInvalidate); 9809ddfeb83aa071990110c0dac7f9280d35ebf2239Jim Miller mInvalidate.set(mTmpInvalidateRect); 9810caa377f4688f175ae22229a10294468610a116eJim Miller } 982aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 983aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 984530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov private void sendAccessEvent(int resId) { 985e303c5c3eb2f65ef3c6fc2693cc3cbcee92d63b7alanv announceForAccessibility(mContext.getString(resId)); 986530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov } 987530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov 988a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley private void handleActionUp() { 989aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller // report pattern detected 990530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (!mPattern.isEmpty()) { 991d2def946390505077766e34b6df4a529b25fdc23Adrian Roos setPatternInProgress(false); 992c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi cancelLineAnimations(); 993530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternDetected(); 994aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller invalidate(); 995aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 996aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (PROFILE_DRAWING) { 997aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (mDrawingProfilingStarted) { 998aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Debug.stopMethodTracing(); 999aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mDrawingProfilingStarted = false; 1000aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1001aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1002aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1003aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 1004c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private void cancelLineAnimations() { 1005c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi for (int i = 0; i < 3; i++) { 1006c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi for (int j = 0; j < 3; j++) { 1007c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState state = mCellStates[i][j]; 1008c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (state.lineAnimator != null) { 1009c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineAnimator.cancel(); 1010c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndX = Float.MIN_VALUE; 1011c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi state.lineEndY = Float.MIN_VALUE; 1012c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 1013c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 1014c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 1015c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 1016aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller private void handleActionDown(MotionEvent event) { 1017aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller resetPattern(); 1018aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float x = event.getX(); 1019aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float y = event.getY(); 1020aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final Cell hitCell = detectAndAddHit(x, y); 1021530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov if (hitCell != null) { 1022d2def946390505077766e34b6df4a529b25fdc23Adrian Roos setPatternInProgress(true); 1023aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mPatternDisplayMode = DisplayMode.Correct; 1024530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternStarted(); 1025c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov } else if (mPatternInProgress) { 1026d2def946390505077766e34b6df4a529b25fdc23Adrian Roos setPatternInProgress(false); 1027530d9f10a6af8ff83a184582ca81608b29510b42Svetoslav Ganov notifyPatternCleared(); 1028aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1029aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (hitCell != null) { 1030aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float startX = getCenterXForColumn(hitCell.column); 1031aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float startY = getCenterYForRow(hitCell.row); 1032aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 1033aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float widthOffset = mSquareWidth / 2f; 1034aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller final float heightOffset = mSquareHeight / 2f; 1035aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller 1036aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller invalidate((int) (startX - widthOffset), (int) (startY - heightOffset), 1037aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller (int) (startX + widthOffset), (int) (startY + heightOffset)); 1038aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 1039aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mInProgressX = x; 1040aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mInProgressY = y; 1041aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (PROFILE_DRAWING) { 1042aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller if (!mDrawingProfilingStarted) { 1043aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller Debug.startMethodTracing("LockPatternDrawing"); 1044aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller mDrawingProfilingStarted = true; 1045aced12fd2276ed7664af6bf70ff03ce2acaf6545Jim Miller } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getCenterXForColumn(int column) { 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f; 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getCenterYForRow(int row) { 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaddingTop + row * mSquareHeight + mSquareHeight / 2f; 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onDraw(Canvas canvas) { 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<Cell> pattern = mPattern; 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int count = pattern.size(); 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean[][] drawLookup = mPatternDrawLookup; 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPatternDisplayMode == DisplayMode.Animate) { 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out which circles to draw 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // + 1 so we pause on complete pattern 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING; 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int spotInCycle = (int) (SystemClock.elapsedRealtime() - 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAnimatingPeriodStart) % oneCycle; 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING; 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearPatternDrawLookup(); 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numCircles; i++) { 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell cell = pattern.get(i); 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project drawLookup[cell.getRow()][cell.getColumn()] = true; 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // figure out in progress portion of ghosting line 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean needToUpdateInProgressPoint = numCircles > 0 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && numCircles < count; 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needToUpdateInProgressPoint) { 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float percentageOfNextCircle = 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING)) / 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MILLIS_PER_CIRCLE_ANIMATING; 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell currentCell = pattern.get(numCircles - 1); 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float centerX = getCenterXForColumn(currentCell.column); 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float centerY = getCenterYForRow(currentCell.row); 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Cell nextCell = pattern.get(numCircles); 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float dx = percentageOfNextCircle * 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (getCenterXForColumn(nextCell.column) - centerX); 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float dy = percentageOfNextCircle * 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (getCenterYForRow(nextCell.row) - centerY); 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressX = centerX + dx; 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInProgressY = centerY + dy; 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Infinite loop here... 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Path currentPath = mCurrentPath; 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project currentPath.rewind(); 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // draw the circles 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < 3; i++) { 1110c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float centerY = getCenterYForRow(i); 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < 3; j++) { 1112c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState cellState = mCellStates[i][j]; 1113c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float centerX = getCenterXForColumn(j); 1114613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi float translationY = cellState.translationY; 1115613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi 111688a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh if (mUseLockPatternDrawable) { 111788a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh drawCellDrawable(canvas, i, j, cellState.radius, drawLookup[i][j]); 111888a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } else { 111988a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh if (isHardwareAccelerated() && cellState.hwAnimating) { 112088a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas; 112188a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY, 112288a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh cellState.hwRadius, cellState.hwPaint); 112388a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } else { 112488a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh drawCircle(canvas, (int) centerX, (int) centerY + translationY, 112588a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh cellState.radius, drawLookup[i][j], cellState.alpha); 112688a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } 1127613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi } 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 113108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // TODO: the path should be created and cached every time we hit-detect a cell 113208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // only the last segment of the path should be computed here 1133e2d71e45209a4ac0787b360c4b0eb4d617863f3fAdrian Roos // draw the path of the pattern (unless we are in stealth mode) 1134e2d71e45209a4ac0787b360c4b0eb4d617863f3fAdrian Roos final boolean drawPath = !mInStealthMode; 113508a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (drawPath) { 1137c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setColor(getCurrentColor(true /* partOfPattern */)); 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 113908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller boolean anyCircles = false; 1140c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float lastX = 0f; 1141c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float lastY = 0f; 1142dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan long elapsedRealtime = SystemClock.elapsedRealtime(); 1143dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan for (int i = 0; i < count; i++) { 114408a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller Cell cell = pattern.get(i); 114508a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 114608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // only draw the part of the pattern stored in 114708a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // the lookup table (this is only different in the case 114808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller // of animation). 114908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller if (!drawLookup[cell.row][cell.column]) { 115008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller break; 115108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 115208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller anyCircles = true; 115308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 1154dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan if (mLineFadeStart[i] == 0) { 1155dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan mLineFadeStart[i] = SystemClock.elapsedRealtime(); 1156dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan } 1157dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan 115808a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller float centerX = getCenterXForColumn(cell.column); 115908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller float centerY = getCenterYForRow(cell.row); 1160c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (i != 0) { 1161dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan // Set this line segment to slowly fade over the next second. 1162dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan int lineFadeVal = (int) Math.min((elapsedRealtime - 1163dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan mLineFadeStart[i])/2f, 255f); 1164dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan 1165c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi CellState state = mCellStates[cell.row][cell.column]; 1166c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.rewind(); 1167c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.moveTo(lastX, lastY); 1168c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (state.lineEndX != Float.MIN_VALUE && state.lineEndY != Float.MIN_VALUE) { 1169c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.lineTo(state.lineEndX, state.lineEndY); 1170dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan mPathPaint.setAlpha((int) 255 - lineFadeVal ); 1171c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } else { 1172c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.lineTo(centerX, centerY); 1173dcc1f1941711be22960e0f58ec75215237e0a11eVishwath Mohan mPathPaint.setAlpha((int) 255 - lineFadeVal ); 1174c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 1175c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawPath(currentPath, mPathPaint); 117608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 1177c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi lastX = centerX; 1178c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi lastY = centerY; 117908a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 118008a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller 1181c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi // draw last in progress section 118208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate) 118308a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller && anyCircles) { 1184c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.rewind(); 1185c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi currentPath.moveTo(lastX, lastY); 118608a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller currentPath.lineTo(mInProgressX, mInProgressY); 1187c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi 1188c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPathPaint.setAlpha((int) (calculateLastSegmentAlpha( 1189c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mInProgressX, mInProgressY, lastX, lastY) * 255f)); 1190c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi canvas.drawPath(currentPath, mPathPaint); 119108a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 119208a975ef86200a73db51bfbcca6bea8ad2a63cbdJim Miller } 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1195c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private float calculateLastSegmentAlpha(float x, float y, float lastX, float lastY) { 1196c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float diffX = x - lastX; 1197c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float diffY = y - lastY; 1198c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float dist = (float) Math.sqrt(diffX*diffX + diffY*diffY); 1199c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi float frac = dist/mSquareWidth; 1200c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return Math.min(1f, Math.max(0f, (frac - 0.3f) * 4f)); 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1203c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi private int getCurrentColor(boolean partOfPattern) { 1204c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi if (!partOfPattern || mInStealthMode || mPatternInProgress) { 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // unselected circle 1206c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mRegularColor; 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPatternDisplayMode == DisplayMode.Wrong) { 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the pattern is wrong 1209c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mErrorColor; 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mPatternDisplayMode == DisplayMode.Correct || 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode == DisplayMode.Animate) { 1212c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi return mSuccessColor; 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalStateException("unknown display mode " + mPatternDisplayMode); 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1216c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi } 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1218c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi /** 1219c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi * @param partOfPattern Whether this circle is part of the pattern. 1220c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi */ 1221613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi private void drawCircle(Canvas canvas, float centerX, float centerY, float radius, 1222c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi boolean partOfPattern, float alpha) { 1223c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPaint.setColor(getCurrentColor(partOfPattern)); 1224c15819748a78963f0dbfbb06300419daf3d2f5f6Jorim Jaggi mPaint.setAlpha((int) (alpha * 255)); 1225613f55fbbb23249d7c65e3f1fe8c943c4459b41aJorim Jaggi canvas.drawCircle(centerX, centerY, radius, mPaint); 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 122888a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh /** 122988a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh * @param partOfPattern Whether this circle is part of the pattern. 123088a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh */ 123188a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh private void drawCellDrawable(Canvas canvas, int i, int j, float radius, 123288a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh boolean partOfPattern) { 123388a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh Rect dst = new Rect( 123488a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh (int) (mPaddingLeft + j * mSquareWidth), 123588a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh (int) (mPaddingTop + i * mSquareHeight), 123688a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh (int) (mPaddingLeft + (j + 1) * mSquareWidth), 123788a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh (int) (mPaddingTop + (i + 1) * mSquareHeight)); 123888a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh float scale = radius / (mDotSize / 2); 123988a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh 124088a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh // Only draw on this square with the appropriate scale. 124188a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh canvas.save(); 124288a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh canvas.clipRect(dst); 124388a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh canvas.scale(scale, scale, dst.centerX(), dst.centerY()); 124488a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh if (!partOfPattern || scale > 1) { 124588a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mNotSelectedDrawable.draw(canvas); 124688a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } else { 124788a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh mSelectedDrawable.draw(canvas); 124888a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } 124988a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh canvas.restore(); 125088a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh } 125188a2a61f09ddf0beb60f7ee3d148f4dec4f466a8Alain Vongsouvanh 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected Parcelable onSaveInstanceState() { 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Parcelable superState = super.onSaveInstanceState(); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SavedState(superState, 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LockPatternUtils.patternToString(mPattern), 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode.ordinal(), 1258aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mInputEnabled, mInStealthMode, mEnableHapticFeedback); 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onRestoreInstanceState(Parcelable state) { 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final SavedState ss = (SavedState) state; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onRestoreInstanceState(ss.getSuperState()); 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setPattern( 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DisplayMode.Correct, 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LockPatternUtils.stringToPattern(ss.getSerializedPattern())); 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = ss.isInputEnabled(); 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = ss.isInStealthMode(); 1271aef555bcf26e770e37f2065913084588fb92c6fbJim Miller mEnableHapticFeedback = ss.isTactileFeedbackEnabled(); 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The parecelable for saving and restoring a lock pattern view. 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class SavedState extends BaseSavedState { 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String mSerializedPattern; 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int mDisplayMode; 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mInputEnabled; 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mInStealthMode; 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mTactileFeedbackEnabled; 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link LockPatternView#onSaveInstanceState()} 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcelable superState, String serializedPattern, int displayMode, 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) { 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(superState); 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSerializedPattern = serializedPattern; 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayMode = displayMode; 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = inputEnabled; 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = inStealthMode; 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTactileFeedbackEnabled = tactileFeedbackEnabled; 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor called from {@link #CREATOR} 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SavedState(Parcel in) { 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(in); 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSerializedPattern = in.readString(); 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayMode = in.readInt(); 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInputEnabled = (Boolean) in.readValue(null); 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInStealthMode = (Boolean) in.readValue(null); 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTactileFeedbackEnabled = (Boolean) in.readValue(null); 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309bf1259b8a6a44d7a4eab5131cd33dac0fbcb50b6Jim Miller 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getSerializedPattern() { 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSerializedPattern; 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDisplayMode() { 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDisplayMode; 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInputEnabled() { 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInputEnabled; 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isInStealthMode() { 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mInStealthMode; 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isTactileFeedbackEnabled(){ 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mTactileFeedbackEnabled; 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel dest, int flags) { 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.writeToParcel(dest, flags); 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeString(mSerializedPattern); 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeInt(mDisplayMode); 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mInputEnabled); 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mInStealthMode); 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeValue(mTactileFeedbackEnabled); 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1340a97227add8ef08de811979ef9dfbb84cff3de014Paul Crowley @SuppressWarnings({ "unused", "hiding" }) // Found using reflection 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Parcelable.Creator<SavedState> CREATOR = 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Creator<SavedState>() { 1343240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1344240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public SavedState createFromParcel(Parcel in) { 1345240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return new SavedState(in); 1346240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1348240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1349240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public SavedState[] newArray(int size) { 1350240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return new SavedState[size]; 1351240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1352240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller }; 1353240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1354240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1355240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private final class PatternExploreByTouchHelper extends ExploreByTouchHelper { 1356240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private Rect mTempRect = new Rect(); 1357f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver private final SparseArray<VirtualViewContainer> mItems = new SparseArray<>(); 1358240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1359240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller class VirtualViewContainer { 1360240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public VirtualViewContainer(CharSequence description) { 1361240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller this.description = description; 1362240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1363240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller CharSequence description; 1364240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller }; 1365240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1366240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller public PatternExploreByTouchHelper(View forView) { 1367240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller super(forView); 1368f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver for (int i = VIRTUAL_BASE_VIEW_ID; i < VIRTUAL_BASE_VIEW_ID + 9; i++) { 1369f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver mItems.put(i, new VirtualViewContainer(getTextForVirtualView(i))); 1370f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver } 1371240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1372240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1373240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1374240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected int getVirtualViewAt(float x, float y) { 1375240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // This must use the same hit logic for the screen to ensure consistency whether 1376240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // accessibility is on or off. 1377240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int id = getVirtualViewIdForHit(x, y); 1378240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return id; 1379240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1380240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1381240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1382240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected void getVisibleVirtualViews(IntArray virtualViewIds) { 1383240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "getVisibleVirtualViews(len=" + virtualViewIds.size() + ")"); 1384d2def946390505077766e34b6df4a529b25fdc23Adrian Roos if (!mPatternInProgress) { 1385d2def946390505077766e34b6df4a529b25fdc23Adrian Roos return; 1386d2def946390505077766e34b6df4a529b25fdc23Adrian Roos } 1387240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller for (int i = VIRTUAL_BASE_VIEW_ID; i < VIRTUAL_BASE_VIEW_ID + 9; i++) { 1388240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Add all views. As views are added to the pattern, we remove them 1389240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // from notification by making them non-clickable below. 1390240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller virtualViewIds.add(i); 1391240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1392240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1393240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1394240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1395240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 1396240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onPopulateEventForVirtualView(" + virtualViewId + ")"); 1397240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Announce this view 1398f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver VirtualViewContainer container = mItems.get(virtualViewId); 1399f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver if (container != null) { 1400f5d677d53a9030015ab4180b1acd2ae9d732fe88Phil Weaver event.getText().add(container.description); 1401240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1402240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1403240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1404240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1405d2def946390505077766e34b6df4a529b25fdc23Adrian Roos public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 1406d2def946390505077766e34b6df4a529b25fdc23Adrian Roos super.onPopulateAccessibilityEvent(host, event); 1407d2def946390505077766e34b6df4a529b25fdc23Adrian Roos if (!mPatternInProgress) { 1408d2def946390505077766e34b6df4a529b25fdc23Adrian Roos CharSequence contentDescription = getContext().getText( 1409d2def946390505077766e34b6df4a529b25fdc23Adrian Roos com.android.internal.R.string.lockscreen_access_pattern_area); 1410d2def946390505077766e34b6df4a529b25fdc23Adrian Roos event.setContentDescription(contentDescription); 1411d2def946390505077766e34b6df4a529b25fdc23Adrian Roos } 1412d2def946390505077766e34b6df4a529b25fdc23Adrian Roos } 1413d2def946390505077766e34b6df4a529b25fdc23Adrian Roos 1414d2def946390505077766e34b6df4a529b25fdc23Adrian Roos @Override 1415240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 1416240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onPopulateNodeForVirtualView(view=" + virtualViewId + ")"); 1417240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1418240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Node and event text and content descriptions are usually 1419240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // identical, so we'll use the exact same string as before. 1420240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setText(getTextForVirtualView(virtualViewId)); 1421240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setContentDescription(getTextForVirtualView(virtualViewId)); 1422240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1423d2def946390505077766e34b6df4a529b25fdc23Adrian Roos if (mPatternInProgress) { 1424d2def946390505077766e34b6df4a529b25fdc23Adrian Roos node.setFocusable(true); 1425d2def946390505077766e34b6df4a529b25fdc23Adrian Roos 1426d2def946390505077766e34b6df4a529b25fdc23Adrian Roos if (isClickable(virtualViewId)) { 1427d2def946390505077766e34b6df4a529b25fdc23Adrian Roos // Mark this node of interest by making it clickable. 1428d2def946390505077766e34b6df4a529b25fdc23Adrian Roos node.addAction(AccessibilityAction.ACTION_CLICK); 1429d2def946390505077766e34b6df4a529b25fdc23Adrian Roos node.setClickable(isClickable(virtualViewId)); 1430d2def946390505077766e34b6df4a529b25fdc23Adrian Roos } 1431240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1432240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1433240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Compute bounds for this object 1434240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final Rect bounds = getBoundsForVirtualView(virtualViewId); 1435240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "bounds:" + bounds.toString()); 1436240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller node.setBoundsInParent(bounds); 1437240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1438240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1439240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private boolean isClickable(int virtualViewId) { 1440240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Dots are clickable if they're not part of the current pattern. 1441240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (virtualViewId != ExploreByTouchHelper.INVALID_ID) { 1442240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int row = (virtualViewId - VIRTUAL_BASE_VIEW_ID) / 3; 1443240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int col = (virtualViewId - VIRTUAL_BASE_VIEW_ID) % 3; 1444240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return !mPatternDrawLookup[row][col]; 1445240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1446240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return false; 1447240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1448240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1449240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller @Override 1450240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 1451240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller Bundle arguments) { 1452240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onPerformActionForVirtualView(id=" + virtualViewId 1453240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + ", action=" + action); 1454240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller switch (action) { 1455240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller case AccessibilityNodeInfo.ACTION_CLICK: 1456240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Click handling should be consistent with 1457240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // onTouchEvent(). This ensures that the view works the 1458240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // same whether accessibility is turned on or off. 1459240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return onItemClicked(virtualViewId); 1460240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller default: 1461240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "*** action not handled in " 1462240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + "onPerformActionForVirtualView(viewId=" 1463240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + virtualViewId + "action=" + action + ")"); 1464240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1465240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return false; 1466240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1467240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1468240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller boolean onItemClicked(int index) { 1469240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "onItemClicked(" + index + ")"); 1470240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1471240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // Since the item's checked state is exposed to accessibility 1472240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // services through its AccessibilityNodeInfo, we need to invalidate 1473240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // the item's virtual view. At some point in the future, the 1474240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // framework will obtain an updated version of the virtual view. 1475240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller invalidateVirtualView(index); 1476240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1477240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // We need to let the framework know what type of event 1478240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // happened. Accessibility services may use this event to provide 1479240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller // appropriate feedback to the user. 1480240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller sendEventForVirtualView(index, AccessibilityEvent.TYPE_VIEW_CLICKED); 1481240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1482240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return true; 1483240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1484240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1485240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private Rect getBoundsForVirtualView(int virtualViewId) { 1486240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int ordinal = virtualViewId - VIRTUAL_BASE_VIEW_ID; 1487240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final Rect bounds = mTempRect; 1488240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int row = ordinal / 3; 1489240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int col = ordinal % 3; 1490240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final CellState cell = mCellStates[row][col]; 1491240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float centerX = getCenterXForColumn(col); 1492240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float centerY = getCenterYForRow(row); 1493240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float cellheight = mSquareHeight * mHitFactor * 0.5f; 1494240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller float cellwidth = mSquareWidth * mHitFactor * 0.5f; 1495240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.left = (int) (centerX - cellwidth); 1496240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.right = (int) (centerX + cellwidth); 1497240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.top = (int) (centerY - cellheight); 1498240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller bounds.bottom = (int) (centerY + cellheight); 1499240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return bounds; 1500240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1501240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1502240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private CharSequence getTextForVirtualView(int virtualViewId) { 1503240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final Resources res = getResources(); 1504385912ee2d78e0e557704cfd5f8c7dbe2b7fd280Phil Weaver return res.getString(R.string.lockscreen_access_pattern_cell_added_verbose, 1505385912ee2d78e0e557704cfd5f8c7dbe2b7fd280Phil Weaver virtualViewId); 1506240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1507240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller 1508240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller /** 1509240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * Helper method to find which cell a point maps to 1510240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * 1511240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * if there's no hit. 1512240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * @param x touch position x 1513240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * @param y touch position y 1514240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller * @return VIRTUAL_BASE_VIEW_ID+id or 0 if no view was hit 1515240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller */ 1516240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller private int getVirtualViewIdForHit(float x, float y) { 1517240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int rowHit = getRowHit(y); 1518240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (rowHit < 0) { 1519240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return ExploreByTouchHelper.INVALID_ID; 1520240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1521240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller final int columnHit = getColumnHit(x); 1522240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (columnHit < 0) { 1523240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return ExploreByTouchHelper.INVALID_ID; 1524240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 1525240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller boolean dotAvailable = mPatternDrawLookup[rowHit][columnHit]; 1526240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int dotId = (rowHit * 3 + columnHit) + VIRTUAL_BASE_VIEW_ID; 1527240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller int view = dotAvailable ? dotId : ExploreByTouchHelper.INVALID_ID; 1528240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller if (DEBUG_A11Y) Log.v(TAG, "getVirtualViewIdForHit(" + x + "," + y + ") => " 1529240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller + view + "avail =" + dotAvailable); 1530240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller return view; 1531240a295f12a04e888b09f1d815fbd72cffbef974Jim Miller } 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1534