From 0caa377f4688f175ae22229a10294468610a116e Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Thu, 7 Mar 2013 18:44:32 -0800 Subject: Fix long-standing bug with LockPatternView drawing artifacts Moving very slowly in LockPatternView would often draw discontinuous lines and have missing wedges in the pattern rings. This fixes the problem by correctly accounting for the invalidate region. The invalidate region is constrained to the last registered pattern cell and the current point. When a new pattern cell is added, the bounding region expands to refresh it once. Fixes bug 8315830 Change-Id: I72342535ae292fcadb02d96b89665ba8431886b2 --- .../android/internal/widget/LockPatternView.java | 152 +++++++-------------- 1 file changed, 47 insertions(+), 105 deletions(-) diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 7a76ab01b8c0..1b088b3c81ac 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -38,6 +38,7 @@ import android.view.View; import android.view.accessibility.AccessibilityManager; import com.android.internal.R; +import com.android.internal.widget.LockPatternView.Cell; import java.util.ArrayList; import java.util.List; @@ -72,6 +73,12 @@ public class LockPatternView extends View { */ private static final int MILLIS_PER_CIRCLE_ANIMATING = 700; + /** + * This can be used to avoid updating the display for very small motions or noisy panels. + * It didn't seem to have much impact on the devices tested, so currently set to 0. + */ + private static final float DRAG_THRESHHOLD = 0.0f; + private OnPatternListener mOnPatternListener; private ArrayList mPattern = new ArrayList(9); @@ -674,10 +681,11 @@ public class LockPatternView extends View { // Handle all recent motion events so we don't skip any cells even when the device // is busy... final int historySize = event.getHistorySize(); + Rect invalidateRect = mInvalidate; + boolean invalidateNow = false; for (int i = 0; i < historySize + 1; i++) { final float x = i < historySize ? event.getHistoricalX(i) : event.getX(); final float y = i < historySize ? event.getHistoricalY(i) : event.getY(); - final int patternSizePreHitDetect = mPattern.size(); Cell hitCell = detectAndAddHit(x, y); final int patternSize = mPattern.size(); if (hitCell != null && patternSize == 1) { @@ -687,114 +695,48 @@ public class LockPatternView extends View { // note current x and y for rubber banding of in progress patterns final float dx = Math.abs(x - mInProgressX); final float dy = Math.abs(y - mInProgressY); - if (dx + dy > mSquareWidth * 0.01f) { - float oldX = mInProgressX; - float oldY = mInProgressY; - - mInProgressX = x; - mInProgressY = y; - - if (mPatternInProgress && patternSize > 0) { - final ArrayList pattern = mPattern; - final float radius = mSquareWidth * mDiameterFactor * 0.5f; - - final Cell lastCell = pattern.get(patternSize - 1); - - float startX = getCenterXForColumn(lastCell.column); - float startY = getCenterYForRow(lastCell.row); - - float left; - float top; - float right; - float bottom; - - final Rect invalidateRect = mInvalidate; - - if (startX < x) { - left = startX; - right = x; - } else { - left = x; - right = startX; - } - - if (startY < y) { - top = startY; - bottom = y; - } else { - top = y; - bottom = startY; - } - - // Invalidate between the pattern's last cell and the current location - invalidateRect.set((int) (left - radius), (int) (top - radius), - (int) (right + radius), (int) (bottom + radius)); - - if (startX < oldX) { - left = startX; - right = oldX; - } else { - left = oldX; - right = startX; - } - - if (startY < oldY) { - top = startY; - bottom = oldY; - } else { - top = oldY; - bottom = startY; - } - - // Invalidate between the pattern's last cell and the previous location - invalidateRect.union((int) (left - radius), (int) (top - radius), - (int) (right + radius), (int) (bottom + radius)); - - // Invalidate between the pattern's new cell and the pattern's previous cell - if (hitCell != null) { - startX = getCenterXForColumn(hitCell.column); - startY = getCenterYForRow(hitCell.row); - - if (patternSize >= 2) { - // (re-using hitcell for old cell) - hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect)); - oldX = getCenterXForColumn(hitCell.column); - oldY = getCenterYForRow(hitCell.row); - - if (startX < oldX) { - left = startX; - right = oldX; - } else { - left = oldX; - right = startX; - } - - if (startY < oldY) { - top = startY; - bottom = oldY; - } else { - top = oldY; - bottom = startY; - } - } else { - left = right = startX; - top = bottom = startY; - } - - final float widthOffset = mSquareWidth / 2f; - final float heightOffset = mSquareHeight / 2f; - - invalidateRect.set((int) (left - widthOffset), - (int) (top - heightOffset), (int) (right + widthOffset), - (int) (bottom + heightOffset)); - } + if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) { + invalidateNow = true; + } - invalidate(invalidateRect); - } else { - invalidate(); + if (mPatternInProgress && patternSize > 0) { + final ArrayList pattern = mPattern; + final Cell lastCell = pattern.get(patternSize - 1); + float startX = getCenterXForColumn(lastCell.column); + float startY = getCenterYForRow(lastCell.row); + + // Adjust for current position. Radius accounts for line width. + final float radius = (mSquareWidth * mDiameterFactor * 0.5f); + float left = Math.min(startX, x) - radius; + float right = Math.max(startX, x) + radius; + float top = Math.min(startY, y) - radius; + float bottom = Math.max(startY, y) + radius; + + // Invalidate between the pattern's new cell and the pattern's previous cell + if (hitCell != null && patternSize >= 2) { + final float width = mSquareWidth * 0.5f; + final float height = mSquareHeight * 0.5f; + final float x2 = getCenterXForColumn(hitCell.column); + final float y2 = getCenterYForRow(hitCell.row); + left = Math.min(x2, left - width); + right = Math.max(x2, right + width); + top = Math.min(y2, top - height); + bottom = Math.max(y2, bottom + height); } + + // Invalidate between the pattern's last cell and the previous location + invalidateRect.union(Math.round(left), Math.round(top), + Math.round(right), Math.round(bottom)); } } + mInProgressX = event.getX(); + mInProgressY = event.getY(); + + // To save updates, we only invalidate if the user moved beyond a certain amount. + if (invalidateNow) { + invalidate(invalidateRect); + invalidateRect.setEmpty(); + } } private void sendAccessEvent(int resId) { -- cgit v1.2.3-59-g8ed1b