summaryrefslogtreecommitdiffstats
path: root/core/java/com/android/internal/widget
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
commitd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/com/android/internal/widget
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
downloadframeworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/com/android/internal/widget')
-rw-r--r--core/java/com/android/internal/widget/DialogTitle.java71
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java116
-rw-r--r--core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java66
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java359
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java1024
-rw-r--r--core/java/com/android/internal/widget/NumberPicker.java406
-rw-r--r--core/java/com/android/internal/widget/NumberPickerButton.java86
-rw-r--r--core/java/com/android/internal/widget/TextProgressBar.java178
-rw-r--r--core/java/com/android/internal/widget/VerticalTextSpinner.java467
9 files changed, 0 insertions, 2773 deletions
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
deleted file mode 100644
index 2eef0b6..0000000
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.text.Layout;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.widget.TextView;
-
-/**
- * Used by dialogs to change the font size and number of lines to try to fit
- * the text to the available space.
- */
-public class DialogTitle extends TextView {
-
- public DialogTitle(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public DialogTitle(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public DialogTitle(Context context) {
- super(context);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- final Layout layout = getLayout();
- if (layout != null) {
- final int lineCount = layout.getLineCount();
- if (lineCount > 0) {
- final int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
- if (ellipsisCount > 0) {
- setSingleLine(false);
-
- TypedArray a = mContext.obtainStyledAttributes(
- android.R.style.TextAppearance_Medium,
- android.R.styleable.TextAppearance);
- final int textSize = a.getDimensionPixelSize(
- android.R.styleable.TextAppearance_textSize, 20);
-
- setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
- setMaxLines(2);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
- }
- }
-
-} \ No newline at end of file
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
deleted file mode 100644
index 44cf0ed..0000000
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2007-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.internal.widget;
-
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.method.KeyListener;
-import android.util.Log;
-import android.view.inputmethod.BaseInputConnection;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.widget.TextView;
-
-public class EditableInputConnection extends BaseInputConnection {
- private static final boolean DEBUG = false;
- private static final String TAG = "EditableInputConnection";
-
- private final TextView mTextView;
-
- public EditableInputConnection(TextView textview) {
- super(textview, false);
- mTextView = textview;
- }
-
- public Editable getEditable() {
- TextView tv = mTextView;
- if (tv != null) {
- return tv.getEditableText();
- }
- return null;
- }
-
- public boolean beginBatchEdit() {
- mTextView.beginBatchEdit();
- return true;
- }
-
- public boolean endBatchEdit() {
- mTextView.endBatchEdit();
- return true;
- }
-
- public boolean clearMetaKeyStates(int states) {
- final Editable content = getEditable();
- if (content == null) return false;
- KeyListener kl = mTextView.getKeyListener();
- if (kl != null) kl.clearMetaKeyState(mTextView, content, states);
- return true;
- }
-
- public boolean commitCompletion(CompletionInfo text) {
- if (DEBUG) Log.v(TAG, "commitCompletion " + text);
- mTextView.beginBatchEdit();
- mTextView.onCommitCompletion(text);
- mTextView.endBatchEdit();
- return true;
- }
-
- public boolean performContextMenuAction(int id) {
- if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
- mTextView.beginBatchEdit();
- mTextView.onTextContextMenuItem(id);
- mTextView.endBatchEdit();
- return true;
- }
-
- public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
- if (mTextView != null) {
- ExtractedText et = new ExtractedText();
- if (mTextView.extractText(request, et)) {
- if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
- mTextView.setExtracting(request);
- }
- return et;
- }
- }
- return null;
- }
-
- public boolean performPrivateCommand(String action, Bundle data) {
- mTextView.onPrivateIMECommand(action, data);
- return true;
- }
-
- @Override
- public boolean commitText(CharSequence text, int newCursorPosition) {
- if (mTextView == null) {
- return super.commitText(text, newCursorPosition);
- }
-
- CharSequence errorBefore = mTextView.getError();
- boolean success = super.commitText(text, newCursorPosition);
- CharSequence errorAfter = mTextView.getError();
-
- if (errorAfter != null && errorBefore == errorAfter) {
- mTextView.setError(null, null);
- }
-
- return success;
- }
-}
diff --git a/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java b/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java
deleted file mode 100644
index b2001cb..0000000
--- a/core/java/com/android/internal/widget/LinearLayoutWithDefaultTouchRecepient.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-
-
-/**
- * Like a normal linear layout, but supports dispatching all otherwise unhandled
- * touch events to a particular descendant. This is for the unlock screen, so
- * that a wider range of touch events than just the lock pattern widget can kick
- * off a lock pattern if the finger is eventually dragged into the bounds of the
- * lock pattern view.
- */
-public class LinearLayoutWithDefaultTouchRecepient extends LinearLayout {
-
- private final Rect mTempRect = new Rect();
- private View mDefaultTouchRecepient;
-
- public LinearLayoutWithDefaultTouchRecepient(Context context) {
- super(context);
- }
-
- public LinearLayoutWithDefaultTouchRecepient(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void setDefaultTouchRecepient(View defaultTouchRecepient) {
- mDefaultTouchRecepient = defaultTouchRecepient;
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (mDefaultTouchRecepient == null) {
- return super.dispatchTouchEvent(ev);
- }
-
- if (super.dispatchTouchEvent(ev)) {
- return true;
- }
- mTempRect.set(0, 0, 0, 0);
- offsetRectIntoDescendantCoords(mDefaultTouchRecepient, mTempRect);
- ev.setLocation(ev.getX() + mTempRect.left, ev.getY() + mTempRect.top);
- return mDefaultTouchRecepient.dispatchTouchEvent(ev);
- }
-
-}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
deleted file mode 100644
index c8b3ad4..0000000
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.ContentResolver;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.security.MessageDigest;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.google.android.collect.Lists;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Utilities for the lock patten and its settings.
- */
-public class LockPatternUtils {
-
- private static final String TAG = "LockPatternUtils";
-
- private static final String LOCK_PATTERN_FILE = "/system/gesture.key";
-
- /**
- * The maximum number of incorrect attempts before the user is prevented
- * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
- */
- public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
-
- /**
- * The number of incorrect attempts before which we fall back on an alternative
- * method of verifying the user, and resetting their lock pattern.
- */
- public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
-
- /**
- * How long the user is prevented from trying again after entering the
- * wrong pattern too many times.
- */
- public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
-
- /**
- * The interval of the countdown for showing progress of the lockout.
- */
- public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
-
- /**
- * The minimum number of dots in a valid pattern.
- */
- public static final int MIN_LOCK_PATTERN_SIZE = 4;
-
- /**
- * The minimum number of dots the user must include in a wrong pattern
- * attempt for it to be counted against the counts that affect
- * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
- */
- public static final int MIN_PATTERN_REGISTER_FAIL = 3;
-
- private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
- private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
-
- private final ContentResolver mContentResolver;
-
- private static String sLockPatternFilename;
-
- /**
- * @param contentResolver Used to look up and save settings.
- */
- public LockPatternUtils(ContentResolver contentResolver) {
- mContentResolver = contentResolver;
- // Initialize the location of gesture lock file
- if (sLockPatternFilename == null) {
- sLockPatternFilename = android.os.Environment.getDataDirectory()
- .getAbsolutePath() + LOCK_PATTERN_FILE;
- }
- }
-
- /**
- * Check to see if a pattern matches the saved pattern. If no pattern exists,
- * always returns true.
- * @param pattern The pattern to check.
- * @return Whether the pattern matchees the stored one.
- */
- public boolean checkPattern(List<LockPatternView.Cell> pattern) {
- try {
- // Read all the bytes from the file
- RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "r");
- final byte[] stored = new byte[(int) raf.length()];
- int got = raf.read(stored, 0, stored.length);
- raf.close();
- if (got <= 0) {
- return true;
- }
- // Compare the hash from the file with the entered pattern's hash
- return Arrays.equals(stored, LockPatternUtils.patternToHash(pattern));
- } catch (FileNotFoundException fnfe) {
- return true;
- } catch (IOException ioe) {
- return true;
- }
- }
-
- /**
- * Check to see if the user has stored a lock pattern.
- * @return Whether a saved pattern exists.
- */
- public boolean savedPatternExists() {
- try {
- // Check if we can read a byte from the file
- RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "r");
- byte first = raf.readByte();
- raf.close();
- return true;
- } catch (FileNotFoundException fnfe) {
- return false;
- } catch (IOException ioe) {
- return false;
- }
- }
-
- /**
- * Save a lock pattern.
- * @param pattern The new pattern to save.
- */
- public void saveLockPattern(List<LockPatternView.Cell> pattern) {
- // Compute the hash
- final byte[] hash = LockPatternUtils.patternToHash(pattern);
- try {
- // Write the hash to file
- RandomAccessFile raf = new RandomAccessFile(sLockPatternFilename, "rw");
- // Truncate the file if pattern is null, to clear the lock
- if (pattern == null) {
- raf.setLength(0);
- } else {
- raf.write(hash, 0, hash.length);
- }
- raf.close();
- } catch (FileNotFoundException fnfe) {
- // Cant do much, unless we want to fail over to using the settings provider
- Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
- } catch (IOException ioe) {
- // Cant do much
- Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
- }
- }
-
- /**
- * Deserialize a pattern.
- * @param string The pattern serialized with {@link #patternToString}
- * @return The pattern.
- */
- public static List<LockPatternView.Cell> stringToPattern(String string) {
- List<LockPatternView.Cell> result = Lists.newArrayList();
-
- final byte[] bytes = string.getBytes();
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- result.add(LockPatternView.Cell.of(b / 3, b % 3));
- }
- return result;
- }
-
- /**
- * Serialize a pattern.
- * @param pattern The pattern.
- * @return The pattern in string form.
- */
- public static String patternToString(List<LockPatternView.Cell> pattern) {
- if (pattern == null) {
- return "";
- }
- final int patternSize = pattern.size();
-
- byte[] res = new byte[patternSize];
- for (int i = 0; i < patternSize; i++) {
- LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
- }
- return new String(res);
- }
-
- /*
- * Generate an SHA-1 hash for the pattern. Not the most secure, but it is
- * at least a second level of protection. First level is that the file
- * is in a location only readable by the system process.
- * @param pattern the gesture pattern.
- * @return the hash of the pattern in a byte array.
- */
- static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
- if (pattern == null) {
- return null;
- }
-
- final int patternSize = pattern.size();
- byte[] res = new byte[patternSize];
- for (int i = 0; i < patternSize; i++) {
- LockPatternView.Cell cell = pattern.get(i);
- res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
- }
- try {
- MessageDigest md = MessageDigest.getInstance("SHA-1");
- byte[] hash = md.digest(res);
- return hash;
- } catch (NoSuchAlgorithmException nsa) {
- return res;
- }
- }
-
- /**
- * @return Whether the lock pattern is enabled.
- */
- public boolean isLockPatternEnabled() {
- return getBoolean(Settings.System.LOCK_PATTERN_ENABLED);
- }
-
- /**
- * Set whether the lock pattern is enabled.
- */
- public void setLockPatternEnabled(boolean enabled) {
- setBoolean(Settings.System.LOCK_PATTERN_ENABLED, enabled);
- }
-
- /**
- * @return Whether the visible pattern is enabled.
- */
- public boolean isVisiblePatternEnabled() {
- return getBoolean(Settings.System.LOCK_PATTERN_VISIBLE);
- }
-
- /**
- * Set whether the visible pattern is enabled.
- */
- public void setVisiblePatternEnabled(boolean enabled) {
- setBoolean(Settings.System.LOCK_PATTERN_VISIBLE, enabled);
- }
-
- /**
- * @return Whether tactile feedback for the pattern is enabled.
- */
- public boolean isTactileFeedbackEnabled() {
- return getBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
- }
-
- /**
- * Set whether tactile feedback for the pattern is enabled.
- */
- public void setTactileFeedbackEnabled(boolean enabled) {
- setBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, enabled);
- }
-
- /**
- * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
- * pattern until the deadline has passed.
- * @return the chosen deadline.
- */
- public long setLockoutAttemptDeadline() {
- final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
- setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
- return deadline;
- }
-
- /**
- * @return The elapsed time in millis in the future when the user is allowed to
- * attempt to enter his/her lock pattern, or 0 if the user is welcome to
- * enter a pattern.
- */
- public long getLockoutAttemptDeadline() {
- final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
- final long now = SystemClock.elapsedRealtime();
- if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
- return 0L;
- }
- return deadline;
- }
-
- /**
- * @return Whether the user is permanently locked out until they verify their
- * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
- * attempts.
- */
- public boolean isPermanentlyLocked() {
- return getBoolean(LOCKOUT_PERMANENT_KEY);
- }
-
- /**
- * Set the state of whether the device is permanently locked, meaning the user
- * must authenticate via other means. If false, that means the user has gone
- * out of permanent lock, so the existing (forgotten) lock pattern needs to
- * be cleared.
- * @param locked Whether the user is permanently locked out until they verify their
- * credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
- * attempts.
- */
- public void setPermanentlyLocked(boolean locked) {
- setBoolean(LOCKOUT_PERMANENT_KEY, locked);
-
- if (!locked) {
- setLockPatternEnabled(false);
- saveLockPattern(null);
- }
- }
-
- /**
- * @return A formatted string of the next alarm (for showing on the lock screen),
- * or null if there is no next alarm.
- */
- public String getNextAlarm() {
- String nextAlarm = Settings.System.getString(mContentResolver,
- Settings.System.NEXT_ALARM_FORMATTED);
- if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) {
- return null;
- }
- return nextAlarm;
- }
-
- private boolean getBoolean(String systemSettingKey) {
- return 1 ==
- android.provider.Settings.System.getInt(
- mContentResolver,
- systemSettingKey, 0);
- }
-
- private void setBoolean(String systemSettingKey, boolean enabled) {
- android.provider.Settings.System.putInt(
- mContentResolver,
- systemSettingKey,
- enabled ? 1 : 0);
- }
-
- private long getLong(String systemSettingKey, long def) {
- return android.provider.Settings.System.getLong(mContentResolver, systemSettingKey, def);
- }
-
- private void setLong(String systemSettingKey, long value) {
- android.provider.Settings.System.putLong(mContentResolver, systemSettingKey, value);
- }
-
-
-}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
deleted file mode 100644
index 7f99ac8..0000000
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.os.Debug;
-import android.os.Vibrator;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Displays and detects the user's unlock attempt, which is a drag of a finger
- * across 9 regions of the screen.
- *
- * Is also capable of displaying a static pattern in "in progress", "wrong" or
- * "correct" states.
- */
-public class LockPatternView extends View {
- // Vibrator pattern for creating a tactile bump
- private static final long[] VIBE_PATTERN = {0, 1, 40, 41};
-
- private static final boolean PROFILE_DRAWING = false;
- private boolean mDrawingProfilingStarted = false;
-
- private Paint mPaint = new Paint();
- private Paint mPathPaint = new Paint();
-
- // TODO: make this common with PhoneWindow
- static final int STATUS_BAR_HEIGHT = 25;
-
- /**
- * How many milliseconds we spend animating each circle of a lock pattern
- * if the animating mode is set. The entire animation should take this
- * constant * the length of the pattern to complete.
- */
- private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
-
- private OnPatternListener mOnPatternListener;
- private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
-
- /**
- * Lookup table for the circles of the pattern we are currently drawing.
- * This will be the cells of the complete pattern unless we are animating,
- * in which case we use this to hold the cells we are drawing for the in
- * progress animation.
- */
- private boolean[][] mPatternDrawLookup = new boolean[3][3];
-
- /**
- * the in progress point:
- * - during interaction: where the user's finger is
- * - during animation: the current tip of the animating line
- */
- private float mInProgressX = -1;
- private float mInProgressY = -1;
-
- private long mAnimatingPeriodStart;
-
- private DisplayMode mPatternDisplayMode = DisplayMode.Correct;
- private boolean mInputEnabled = true;
- private boolean mInStealthMode = false;
- private boolean mTactileFeedbackEnabled = true;
- private boolean mPatternInProgress = false;
-
- private float mDiameterFactor = 0.5f;
- private float mHitFactor = 0.6f;
-
- private float mSquareWidth;
- private float mSquareHeight;
-
- private Bitmap mBitmapBtnDefault;
- private Bitmap mBitmapBtnTouched;
- private Bitmap mBitmapCircleDefault;
- private Bitmap mBitmapCircleGreen;
- private Bitmap mBitmapCircleRed;
-
- private Bitmap mBitmapArrowGreenUp;
- private Bitmap mBitmapArrowRedUp;
-
- private final Path mCurrentPath = new Path();
- private final Rect mInvalidate = new Rect();
-
- private int mBitmapWidth;
- private int mBitmapHeight;
-
-
- private Vibrator vibe; // Vibrator for creating tactile feedback
-
- /**
- * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
- */
- public static class Cell {
- int row;
- int column;
-
- // keep # objects limited to 9
- static Cell[][] sCells = new Cell[3][3];
- static {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- sCells[i][j] = new Cell(i, j);
- }
- }
- }
-
- /**
- * @param row The row of the cell.
- * @param column The column of the cell.
- */
- private Cell(int row, int column) {
- checkRange(row, column);
- this.row = row;
- this.column = column;
- }
-
- public int getRow() {
- return row;
- }
-
- public int getColumn() {
- return column;
- }
-
- /**
- * @param row The row of the cell.
- * @param column The column of the cell.
- */
- public static synchronized Cell of(int row, int column) {
- checkRange(row, column);
- return sCells[row][column];
- }
-
- private static void checkRange(int row, int column) {
- if (row < 0 || row > 2) {
- throw new IllegalArgumentException("row must be in range 0-2");
- }
- if (column < 0 || column > 2) {
- throw new IllegalArgumentException("column must be in range 0-2");
- }
- }
-
- public String toString() {
- return "(row=" + row + ",clmn=" + column + ")";
- }
- }
-
- /**
- * How to display the current pattern.
- */
- public enum DisplayMode {
-
- /**
- * The pattern drawn is correct (i.e draw it in a friendly color)
- */
- Correct,
-
- /**
- * Animate the pattern (for demo, and help).
- */
- Animate,
-
- /**
- * The pattern is wrong (i.e draw a foreboding color)
- */
- Wrong
- }
-
- /**
- * The call back interface for detecting patterns entered by the user.
- */
- public static interface OnPatternListener {
-
- /**
- * A new pattern has begun.
- */
- void onPatternStart();
-
- /**
- * The pattern was cleared.
- */
- void onPatternCleared();
-
- /**
- * A pattern was detected from the user.
- * @param pattern The pattern.
- */
- void onPatternDetected(List<Cell> pattern);
- }
-
- public LockPatternView(Context context) {
- this(context, null);
- }
-
- public LockPatternView(Context context, AttributeSet attrs) {
- super(context, attrs);
- vibe = new Vibrator();
-
- setClickable(true);
-
- mPathPaint.setAntiAlias(true);
- mPathPaint.setDither(true);
- mPathPaint.setColor(Color.WHITE); // TODO this should be from the style
- mPathPaint.setAlpha(128);
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setStrokeJoin(Paint.Join.ROUND);
- mPathPaint.setStrokeCap(Paint.Cap.ROUND);
-
- // lot's of bitmaps!
- mBitmapBtnDefault = getBitmapFor(R.drawable.btn_code_lock_default);
- mBitmapBtnTouched = getBitmapFor(R.drawable.btn_code_lock_touched);
- mBitmapCircleDefault = getBitmapFor(R.drawable.indicator_code_lock_point_area_default);
- mBitmapCircleGreen = getBitmapFor(R.drawable.indicator_code_lock_point_area_green);
- mBitmapCircleRed = getBitmapFor(R.drawable.indicator_code_lock_point_area_red);
-
- mBitmapArrowGreenUp = getBitmapFor(R.drawable.indicator_code_lock_drag_direction_green_up);
- mBitmapArrowRedUp = getBitmapFor(R.drawable.indicator_code_lock_drag_direction_red_up);
-
- // we assume all bitmaps have the same size
- mBitmapWidth = mBitmapBtnDefault.getWidth();
- mBitmapHeight = mBitmapBtnDefault.getHeight();
- }
-
- private Bitmap getBitmapFor(int resId) {
- return BitmapFactory.decodeResource(getContext().getResources(), resId);
- }
-
- /**
- * @return Whether the view is in stealth mode.
- */
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- /**
- * @return Whether the view has tactile feedback enabled.
- */
- public boolean isTactileFeedbackEnabled() {
- return mTactileFeedbackEnabled;
- }
-
- /**
- * Set whether the view is in stealth mode. If true, there will be no
- * visible feedback as the user enters the pattern.
- *
- * @param inStealthMode Whether in stealth mode.
- */
- public void setInStealthMode(boolean inStealthMode) {
- mInStealthMode = inStealthMode;
- }
-
- /**
- * Set whether the view will use tactile feedback. If true, there will be
- * tactile feedback as the user enters the pattern.
- *
- * @param tactileFeedbackEnabled Whether tactile feedback is enabled
- */
- public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) {
- mTactileFeedbackEnabled = tactileFeedbackEnabled;
- }
-
- /**
- * Set the call back for pattern detection.
- * @param onPatternListener The call back.
- */
- public void setOnPatternListener(
- OnPatternListener onPatternListener) {
- mOnPatternListener = onPatternListener;
- }
-
- /**
- * Set the pattern explicitely (rather than waiting for the user to input
- * a pattern).
- * @param displayMode How to display the pattern.
- * @param pattern The pattern.
- */
- public void setPattern(DisplayMode displayMode, List<Cell> pattern) {
- mPattern.clear();
- mPattern.addAll(pattern);
- clearPatternDrawLookup();
- for (Cell cell : pattern) {
- mPatternDrawLookup[cell.getRow()][cell.getColumn()] = true;
- }
-
- setDisplayMode(displayMode);
- }
-
- /**
- * Set the display mode of the current pattern. This can be useful, for
- * instance, after detecting a pattern to tell this view whether change the
- * in progress result to correct or wrong.
- * @param displayMode The display mode.
- */
- public void setDisplayMode(DisplayMode displayMode) {
- mPatternDisplayMode = displayMode;
- if (displayMode == DisplayMode.Animate) {
- if (mPattern.size() == 0) {
- throw new IllegalStateException("you must have a pattern to "
- + "animate if you want to set the display mode to animate");
- }
- mAnimatingPeriodStart = SystemClock.elapsedRealtime();
- final Cell first = mPattern.get(0);
- mInProgressX = getCenterXForColumn(first.getColumn());
- mInProgressY = getCenterYForRow(first.getRow());
- clearPatternDrawLookup();
- }
- invalidate();
- }
-
- /**
- * Clear the pattern.
- */
- public void clearPattern() {
- resetPattern();
- }
-
- /**
- * Reset all pattern state.
- */
- private void resetPattern() {
- mPattern.clear();
- clearPatternDrawLookup();
- mPatternDisplayMode = DisplayMode.Correct;
- invalidate();
- }
-
- /**
- * Clear the pattern lookup table.
- */
- private void clearPatternDrawLookup() {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- mPatternDrawLookup[i][j] = false;
- }
- }
- }
-
- /**
- * Disable input (for instance when displaying a message that will
- * timeout so user doesn't get view into messy state).
- */
- public void disableInput() {
- mInputEnabled = false;
- }
-
- /**
- * Enable input.
- */
- public void enableInput() {
- mInputEnabled = true;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- final int width = w - mPaddingLeft - mPaddingRight;
- mSquareWidth = width / 3.0f;
-
- final int height = h - mPaddingTop - mPaddingBottom;
- mSquareHeight = height / 3.0f;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final WindowManager wm = (WindowManager) getContext()
- .getSystemService(Context.WINDOW_SERVICE);
- final int width = wm.getDefaultDisplay().getWidth();
- final int height = wm.getDefaultDisplay().getHeight();
- int squareSide = Math.min(width, height);
-
- // if in landscape...
- if (width > height) {
- squareSide -= STATUS_BAR_HEIGHT;
- }
-
- setMeasuredDimension(squareSide, squareSide);
- }
-
- /**
- * Determines whether the point x, y will add a new point to the current
- * pattern (in addition to finding the cell, also makes heuristic choices
- * such as filling in gaps based on current pattern).
- * @param x The x coordinate.
- * @param y The y coordinate.
- */
- private Cell detectAndAddHit(float x, float y) {
- final Cell cell = checkForNewHit(x, y);
- if (cell != null) {
-
- // check for gaps in existing pattern
- Cell fillInGapCell = null;
- final ArrayList<Cell> pattern = mPattern;
- if (!pattern.isEmpty()) {
- final Cell lastCell = pattern.get(pattern.size() - 1);
- int dRow = cell.row - lastCell.row;
- int dColumn = cell.column - lastCell.column;
-
- int fillInRow = lastCell.row;
- int fillInColumn = lastCell.column;
-
- if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) {
- fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1);
- }
-
- if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) {
- fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1);
- }
-
- fillInGapCell = Cell.of(fillInRow, fillInColumn);
- }
-
- if (fillInGapCell != null &&
- !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
- addCellToPattern(fillInGapCell);
- }
- addCellToPattern(cell);
- if (mTactileFeedbackEnabled){
- vibe.vibrate(VIBE_PATTERN, -1); // Generate tactile feedback
- }
- return cell;
- }
- return null;
- }
-
- private void addCellToPattern(Cell newCell) {
- mPatternDrawLookup[newCell.getRow()][newCell.getColumn()] = true;
- mPattern.add(newCell);
- }
-
- // helper method to find which cell a point maps to
- private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
- }
-
- /**
- * Helper method to find the row that y falls into.
- * @param y The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Helper method to find the column x fallis into.
- * @param x The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent motionEvent) {
- if (!mInputEnabled || !isEnabled()) {
- return false;
- }
-
- final float x = motionEvent.getX();
- final float y = motionEvent.getY();
- Cell hitCell;
- switch(motionEvent.getAction()) {
- case MotionEvent.ACTION_DOWN:
- resetPattern();
- hitCell = detectAndAddHit(x, y);
- if (hitCell != null && mOnPatternListener != null) {
- mPatternInProgress = true;
- mPatternDisplayMode = DisplayMode.Correct;
- mOnPatternListener.onPatternStart();
- } else if (mOnPatternListener != null) {
- mPatternInProgress = false;
- mOnPatternListener.onPatternCleared();
- }
- if (hitCell != null) {
- final float startX = getCenterXForColumn(hitCell.column);
- final float startY = getCenterYForRow(hitCell.row);
-
- final float widthOffset = mSquareWidth / 2f;
- final float heightOffset = mSquareHeight / 2f;
-
- invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),
- (int) (startX + widthOffset), (int) (startY + heightOffset));
- }
- mInProgressX = x;
- mInProgressY = y;
- if (PROFILE_DRAWING) {
- if (!mDrawingProfilingStarted) {
- Debug.startMethodTracing("LockPatternDrawing");
- mDrawingProfilingStarted = true;
- }
- }
- return true;
- case MotionEvent.ACTION_UP:
- // report pattern detected
- if (!mPattern.isEmpty() && mOnPatternListener != null) {
- mPatternInProgress = false;
- mOnPatternListener.onPatternDetected(mPattern);
- invalidate();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- return true;
- case MotionEvent.ACTION_MOVE:
- final int patternSizePreHitDetect = mPattern.size();
- hitCell = detectAndAddHit(x, y);
- final int patternSize = mPattern.size();
- if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) {
- mPatternInProgress = true;
- mOnPatternListener.onPatternStart();
- }
- // 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) {
- final ArrayList<Cell> pattern = mPattern;
- final float radius = mSquareWidth * mDiameterFactor * 0.5f;
-
- Cell cell = pattern.get(patternSize - 1);
-
- float startX = getCenterXForColumn(cell.column);
- float startY = getCenterYForRow(cell.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));
- }
-
- invalidate(invalidateRect);
- } else {
- invalidate();
- }
- }
- return true;
- case MotionEvent.ACTION_CANCEL:
- resetPattern();
- if (mOnPatternListener != null) {
- mPatternInProgress = false;
- mOnPatternListener.onPatternCleared();
- }
- if (PROFILE_DRAWING) {
- if (mDrawingProfilingStarted) {
- Debug.stopMethodTracing();
- mDrawingProfilingStarted = false;
- }
- }
- return true;
- }
- return false;
- }
-
- private float getCenterXForColumn(int column) {
- return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
- }
-
- private float getCenterYForRow(int row) {
- return mPaddingTop + row * mSquareHeight + mSquareHeight / 2f;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- final ArrayList<Cell> pattern = mPattern;
- final int count = pattern.size();
- final boolean[][] drawLookup = mPatternDrawLookup;
-
- if (mPatternDisplayMode == DisplayMode.Animate) {
-
- // figure out which circles to draw
-
- // + 1 so we pause on complete pattern
- final int oneCycle = (count + 1) * MILLIS_PER_CIRCLE_ANIMATING;
- final int spotInCycle = (int) (SystemClock.elapsedRealtime() -
- mAnimatingPeriodStart) % oneCycle;
- final int numCircles = spotInCycle / MILLIS_PER_CIRCLE_ANIMATING;
-
- clearPatternDrawLookup();
- for (int i = 0; i < numCircles; i++) {
- final Cell cell = pattern.get(i);
- drawLookup[cell.getRow()][cell.getColumn()] = true;
- }
-
- // figure out in progress portion of ghosting line
-
- final boolean needToUpdateInProgressPoint = numCircles > 0
- && numCircles < count;
-
- if (needToUpdateInProgressPoint) {
- final float percentageOfNextCircle =
- ((float) (spotInCycle % MILLIS_PER_CIRCLE_ANIMATING)) /
- MILLIS_PER_CIRCLE_ANIMATING;
-
- final Cell currentCell = pattern.get(numCircles - 1);
- final float centerX = getCenterXForColumn(currentCell.column);
- final float centerY = getCenterYForRow(currentCell.row);
-
- final Cell nextCell = pattern.get(numCircles);
- final float dx = percentageOfNextCircle *
- (getCenterXForColumn(nextCell.column) - centerX);
- final float dy = percentageOfNextCircle *
- (getCenterYForRow(nextCell.row) - centerY);
- mInProgressX = centerX + dx;
- mInProgressY = centerY + dy;
- }
- // TODO: Infinite loop here...
- invalidate();
- }
-
- final float squareWidth = mSquareWidth;
- final float squareHeight = mSquareHeight;
-
- float radius = (squareWidth * mDiameterFactor * 0.5f);
- mPathPaint.setStrokeWidth(radius);
-
- final Path currentPath = mCurrentPath;
- currentPath.rewind();
-
- // TODO: the path should be created and cached every time we hit-detect a cell
- // only the last segment of the path should be computed here
- // draw the path of the pattern (unless the user is in progress, and
- // we are in stealth mode)
- final boolean drawPath = (!mInStealthMode || mPatternDisplayMode == DisplayMode.Wrong);
- if (drawPath) {
- boolean anyCircles = false;
- for (int i = 0; i < count; i++) {
- Cell cell = pattern.get(i);
-
- // only draw the part of the pattern stored in
- // the lookup table (this is only different in the case
- // of animation).
- if (!drawLookup[cell.row][cell.column]) {
- break;
- }
- anyCircles = true;
-
- float centerX = getCenterXForColumn(cell.column);
- float centerY = getCenterYForRow(cell.row);
- if (i == 0) {
- currentPath.moveTo(centerX, centerY);
- } else {
- currentPath.lineTo(centerX, centerY);
- }
- }
-
- // add last in progress section
- if ((mPatternInProgress || mPatternDisplayMode == DisplayMode.Animate)
- && anyCircles) {
- currentPath.lineTo(mInProgressX, mInProgressY);
- }
- canvas.drawPath(currentPath, mPathPaint);
- }
-
- // draw the circles
- final int paddingTop = mPaddingTop;
- final int paddingLeft = mPaddingLeft;
-
- for (int i = 0; i < 3; i++) {
- float topY = paddingTop + i * squareHeight;
- //float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);
- for (int j = 0; j < 3; j++) {
- float leftX = paddingLeft + j * squareWidth;
- drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
- }
- }
-
- // draw the arrows associated with the path (unless the user is in progress, and
- // we are in stealth mode)
- boolean oldFlag = (mPaint.getFlags() & Paint.FILTER_BITMAP_FLAG) != 0;
- mPaint.setFilterBitmap(true); // draw with higher quality since we render with transforms
- if (drawPath) {
- for (int i = 0; i < count - 1; i++) {
- Cell cell = pattern.get(i);
- Cell next = pattern.get(i + 1);
-
- // only draw the part of the pattern stored in
- // the lookup table (this is only different in the case
- // of animation).
- if (!drawLookup[next.row][next.column]) {
- break;
- }
-
- float leftX = paddingLeft + cell.column * squareWidth;
- float topY = paddingTop + cell.row * squareHeight;
-
- drawArrow(canvas, leftX, topY, cell, next);
- }
- }
- mPaint.setFilterBitmap(oldFlag); // restore default flag
- }
-
- private void drawArrow(Canvas canvas, float leftX, float topY, Cell start, Cell end) {
- boolean green = mPatternDisplayMode != DisplayMode.Wrong;
-
- final int endRow = end.row;
- final int startRow = start.row;
- final int endColumn = end.column;
- final int startColumn = start.column;
-
- // offsets for centering the bitmap in the cell
- final int offsetX = ((int) mSquareWidth - mBitmapWidth) / 2;
- final int offsetY = ((int) mSquareHeight - mBitmapHeight) / 2;
-
- // compute transform to place arrow bitmaps at correct angle inside circle.
- // This assumes that the arrow image is drawn at 12:00 with it's top edge
- // coincident with the circle bitmap's top edge.
- Bitmap arrow = green ? mBitmapArrowGreenUp : mBitmapArrowRedUp;
- Matrix matrix = new Matrix();
- final int cellWidth = mBitmapCircleDefault.getWidth();
- final int cellHeight = mBitmapCircleDefault.getHeight();
-
- // the up arrow bitmap is at 12:00, so find the rotation from x axis and add 90 degrees.
- final float theta = (float) Math.atan2(
- (double) (endRow - startRow), (double) (endColumn - startColumn));
- final float angle = (float) Math.toDegrees(theta) + 90.0f;
-
- // compose matrix
- matrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
- matrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f); // rotate about cell center
- matrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
- canvas.drawBitmap(arrow, matrix, mPaint);
- }
-
- /**
- * @param canvas
- * @param leftX
- * @param topY
- * @param partOfPattern Whether this circle is part of the pattern.
- */
- private void drawCircle(Canvas canvas, int leftX, int topY, boolean partOfPattern) {
- Bitmap outerCircle;
- Bitmap innerCircle;
-
- if (!partOfPattern || (mInStealthMode && mPatternDisplayMode != DisplayMode.Wrong)) {
- // unselected circle
- outerCircle = mBitmapCircleDefault;
- innerCircle = mBitmapBtnDefault;
- } else if (mPatternInProgress) {
- // user is in middle of drawing a pattern
- outerCircle = mBitmapCircleGreen;
- innerCircle = mBitmapBtnTouched;
- } else if (mPatternDisplayMode == DisplayMode.Wrong) {
- // the pattern is wrong
- outerCircle = mBitmapCircleRed;
- innerCircle = mBitmapBtnDefault;
- } else if (mPatternDisplayMode == DisplayMode.Correct ||
- mPatternDisplayMode == DisplayMode.Animate) {
- // the pattern is correct
- outerCircle = mBitmapCircleGreen;
- innerCircle = mBitmapBtnDefault;
- } else {
- throw new IllegalStateException("unknown display mode " + mPatternDisplayMode);
- }
-
- final int width = mBitmapWidth;
- final int height = mBitmapHeight;
-
- final float squareWidth = mSquareWidth;
- final float squareHeight = mSquareHeight;
-
- int offsetX = (int) ((squareWidth - width) / 2f);
- int offsetY = (int) ((squareHeight - height) / 2f);
-
- canvas.drawBitmap(outerCircle, leftX + offsetX, topY + offsetY, mPaint);
- canvas.drawBitmap(innerCircle, leftX + offsetX, topY + offsetY, mPaint);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
- mPatternDisplayMode.ordinal(),
- mInputEnabled, mInStealthMode, mTactileFeedbackEnabled);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setPattern(
- DisplayMode.Correct,
- LockPatternUtils.stringToPattern(ss.getSerializedPattern()));
- mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()];
- mInputEnabled = ss.isInputEnabled();
- mInStealthMode = ss.isInStealthMode();
- mTactileFeedbackEnabled = ss.isTactileFeedbackEnabled();
- }
-
- /**
- * The parecelable for saving and restoring a lock pattern view.
- */
- private static class SavedState extends BaseSavedState {
-
- private final String mSerializedPattern;
- private final int mDisplayMode;
- private final boolean mInputEnabled;
- private final boolean mInStealthMode;
- private final boolean mTactileFeedbackEnabled;
-
- /**
- * Constructor called from {@link LockPatternView#onSaveInstanceState()}
- */
- private SavedState(Parcelable superState, String serializedPattern, int displayMode,
- boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) {
- super(superState);
- mSerializedPattern = serializedPattern;
- mDisplayMode = displayMode;
- mInputEnabled = inputEnabled;
- mInStealthMode = inStealthMode;
- mTactileFeedbackEnabled = tactileFeedbackEnabled;
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- private SavedState(Parcel in) {
- super(in);
- mSerializedPattern = in.readString();
- mDisplayMode = in.readInt();
- mInputEnabled = (Boolean) in.readValue(null);
- mInStealthMode = (Boolean) in.readValue(null);
- mTactileFeedbackEnabled = (Boolean) in.readValue(null);
- }
-
- public String getSerializedPattern() {
- return mSerializedPattern;
- }
-
- public int getDisplayMode() {
- return mDisplayMode;
- }
-
- public boolean isInputEnabled() {
- return mInputEnabled;
- }
-
- public boolean isInStealthMode() {
- return mInStealthMode;
- }
-
- public boolean isTactileFeedbackEnabled(){
- return mTactileFeedbackEnabled;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeString(mSerializedPattern);
- dest.writeInt(mDisplayMode);
- dest.writeValue(mInputEnabled);
- dest.writeValue(mInStealthMode);
- dest.writeValue(mTactileFeedbackEnabled);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-}
diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java
deleted file mode 100644
index 1647c20..0000000
--- a/core/java/com/android/internal/widget/NumberPicker.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.os.Handler;
-import android.text.InputFilter;
-import android.text.InputType;
-import android.text.Spanned;
-import android.text.method.NumberKeyListener;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnLongClickListener;
-import android.widget.TextView;
-import android.widget.LinearLayout;
-
-import com.android.internal.R;
-
-public class NumberPicker extends LinearLayout implements OnClickListener,
- OnFocusChangeListener, OnLongClickListener {
-
- public interface OnChangedListener {
- void onChanged(NumberPicker picker, int oldVal, int newVal);
- }
-
- public interface Formatter {
- String toString(int value);
- }
-
- /*
- * Use a custom NumberPicker formatting callback to use two-digit
- * minutes strings like "01". Keeping a static formatter etc. is the
- * most efficient way to do this; it avoids creating temporary objects
- * on every call to format().
- */
- public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER =
- new NumberPicker.Formatter() {
- final StringBuilder mBuilder = new StringBuilder();
- final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
- final Object[] mArgs = new Object[1];
- public String toString(int value) {
- mArgs[0] = value;
- mBuilder.delete(0, mBuilder.length());
- mFmt.format("%02d", mArgs);
- return mFmt.toString();
- }
- };
-
- private final Handler mHandler;
- private final Runnable mRunnable = new Runnable() {
- public void run() {
- if (mIncrement) {
- changeCurrent(mCurrent + 1);
- mHandler.postDelayed(this, mSpeed);
- } else if (mDecrement) {
- changeCurrent(mCurrent - 1);
- mHandler.postDelayed(this, mSpeed);
- }
- }
- };
-
- private final TextView mText;
- private final InputFilter mNumberInputFilter;
-
- private String[] mDisplayedValues;
- private int mStart;
- private int mEnd;
- private int mCurrent;
- private int mPrevious;
- private OnChangedListener mListener;
- private Formatter mFormatter;
- private long mSpeed = 300;
-
- private boolean mIncrement;
- private boolean mDecrement;
-
- public NumberPicker(Context context) {
- this(context, null);
- }
-
- public NumberPicker(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- @SuppressWarnings({"UnusedDeclaration"})
- public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs);
- setOrientation(VERTICAL);
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.number_picker, this, true);
- mHandler = new Handler();
- InputFilter inputFilter = new NumberPickerInputFilter();
- mNumberInputFilter = new NumberRangeKeyListener();
- mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
- mIncrementButton.setOnClickListener(this);
- mIncrementButton.setOnLongClickListener(this);
- mIncrementButton.setNumberPicker(this);
- mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement);
- mDecrementButton.setOnClickListener(this);
- mDecrementButton.setOnLongClickListener(this);
- mDecrementButton.setNumberPicker(this);
-
- mText = (TextView) findViewById(R.id.timepicker_input);
- mText.setOnFocusChangeListener(this);
- mText.setFilters(new InputFilter[] {inputFilter});
- mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
-
- if (!isEnabled()) {
- setEnabled(false);
- }
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- mIncrementButton.setEnabled(enabled);
- mDecrementButton.setEnabled(enabled);
- mText.setEnabled(enabled);
- }
-
- public void setOnChangeListener(OnChangedListener listener) {
- mListener = listener;
- }
-
- public void setFormatter(Formatter formatter) {
- mFormatter = formatter;
- }
-
- /**
- * Set the range of numbers allowed for the number picker. The current
- * value will be automatically set to the start.
- *
- * @param start the start of the range (inclusive)
- * @param end the end of the range (inclusive)
- */
- public void setRange(int start, int end) {
- mStart = start;
- mEnd = end;
- mCurrent = start;
- updateView();
- }
-
- /**
- * Set the range of numbers allowed for the number picker. The current
- * value will be automatically set to the start. Also provide a mapping
- * for values used to display to the user.
- *
- * @param start the start of the range (inclusive)
- * @param end the end of the range (inclusive)
- * @param displayedValues the values displayed to the user.
- */
- public void setRange(int start, int end, String[] displayedValues) {
- mDisplayedValues = displayedValues;
- mStart = start;
- mEnd = end;
- mCurrent = start;
- updateView();
- }
-
- public void setCurrent(int current) {
- mCurrent = current;
- updateView();
- }
-
- /**
- * The speed (in milliseconds) at which the numbers will scroll
- * when the the +/- buttons are longpressed. Default is 300ms.
- */
- public void setSpeed(long speed) {
- mSpeed = speed;
- }
-
- public void onClick(View v) {
-
- /* The text view may still have focus so clear it's focus which will
- * trigger the on focus changed and any typed values to be pulled.
- */
- mText.clearFocus();
-
- // now perform the increment/decrement
- if (R.id.increment == v.getId()) {
- changeCurrent(mCurrent + 1);
- } else if (R.id.decrement == v.getId()) {
- changeCurrent(mCurrent - 1);
- }
- }
-
- private String formatNumber(int value) {
- return (mFormatter != null)
- ? mFormatter.toString(value)
- : String.valueOf(value);
- }
-
- private void changeCurrent(int current) {
-
- // Wrap around the values if we go past the start or end
- if (current > mEnd) {
- current = mStart;
- } else if (current < mStart) {
- current = mEnd;
- }
- mPrevious = mCurrent;
- mCurrent = current;
- notifyChange();
- updateView();
- }
-
- private void notifyChange() {
- if (mListener != null) {
- mListener.onChanged(this, mPrevious, mCurrent);
- }
- }
-
- private void updateView() {
-
- /* If we don't have displayed values then use the
- * current number else find the correct value in the
- * displayed values for the current number.
- */
- if (mDisplayedValues == null) {
- mText.setText(formatNumber(mCurrent));
- } else {
- mText.setText(mDisplayedValues[mCurrent - mStart]);
- }
- }
-
- private void validateCurrentView(CharSequence str) {
- int val = getSelectedPos(str.toString());
- if ((val >= mStart) && (val <= mEnd)) {
- mPrevious = mCurrent;
- mCurrent = val;
- notifyChange();
- }
- updateView();
- }
-
- public void onFocusChange(View v, boolean hasFocus) {
-
- /* When focus is lost check that the text field
- * has valid values.
- */
- if (!hasFocus) {
- String str = String.valueOf(((TextView) v).getText());
- if ("".equals(str)) {
-
- // Restore to the old value as we don't allow empty values
- updateView();
- } else {
-
- // Check the new value and ensure it's in range
- validateCurrentView(str);
- }
- }
- }
-
- /**
- * We start the long click here but rely on the {@link NumberPickerButton}
- * to inform us when the long click has ended.
- */
- public boolean onLongClick(View v) {
-
- /* The text view may still have focus so clear it's focus which will
- * trigger the on focus changed and any typed values to be pulled.
- */
- mText.clearFocus();
-
- if (R.id.increment == v.getId()) {
- mIncrement = true;
- mHandler.post(mRunnable);
- } else if (R.id.decrement == v.getId()) {
- mDecrement = true;
- mHandler.post(mRunnable);
- }
- return true;
- }
-
- public void cancelIncrement() {
- mIncrement = false;
- }
-
- public void cancelDecrement() {
- mDecrement = false;
- }
-
- private static final char[] DIGIT_CHARACTERS = new char[] {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
- };
-
- private NumberPickerButton mIncrementButton;
- private NumberPickerButton mDecrementButton;
-
- private class NumberPickerInputFilter implements InputFilter {
- public CharSequence filter(CharSequence source, int start, int end,
- Spanned dest, int dstart, int dend) {
- if (mDisplayedValues == null) {
- return mNumberInputFilter.filter(source, start, end, dest, dstart, dend);
- }
- CharSequence filtered = String.valueOf(source.subSequence(start, end));
- String result = String.valueOf(dest.subSequence(0, dstart))
- + filtered
- + dest.subSequence(dend, dest.length());
- String str = String.valueOf(result).toLowerCase();
- for (String val : mDisplayedValues) {
- val = val.toLowerCase();
- if (val.startsWith(str)) {
- return filtered;
- }
- }
- return "";
- }
- }
-
- private class NumberRangeKeyListener extends NumberKeyListener {
-
- // XXX This doesn't allow for range limits when controlled by a
- // soft input method!
- public int getInputType() {
- return InputType.TYPE_CLASS_NUMBER;
- }
-
- @Override
- protected char[] getAcceptedChars() {
- return DIGIT_CHARACTERS;
- }
-
- @Override
- public CharSequence filter(CharSequence source, int start, int end,
- Spanned dest, int dstart, int dend) {
-
- CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
- if (filtered == null) {
- filtered = source.subSequence(start, end);
- }
-
- String result = String.valueOf(dest.subSequence(0, dstart))
- + filtered
- + dest.subSequence(dend, dest.length());
-
- if ("".equals(result)) {
- return result;
- }
- int val = getSelectedPos(result);
-
- /* Ensure the user can't type in a value greater
- * than the max allowed. We have to allow less than min
- * as the user might want to delete some numbers
- * and then type a new number.
- */
- if (val > mEnd) {
- return "";
- } else {
- return filtered;
- }
- }
- }
-
- private int getSelectedPos(String str) {
- if (mDisplayedValues == null) {
- return Integer.parseInt(str);
- } else {
- for (int i = 0; i < mDisplayedValues.length; i++) {
-
- /* Don't force the user to type in jan when ja will do */
- str = str.toLowerCase();
- if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
- return mStart + i;
- }
- }
-
- /* The user might have typed in a number into the month field i.e.
- * 10 instead of OCT so support that too.
- */
- try {
- return Integer.parseInt(str);
- } catch (NumberFormatException e) {
-
- /* Ignore as if it's not a number we don't care */
- }
- }
- return mStart;
- }
-
- /**
- * @return the current value.
- */
- public int getCurrent() {
- return mCurrent;
- }
-} \ No newline at end of file
diff --git a/core/java/com/android/internal/widget/NumberPickerButton.java b/core/java/com/android/internal/widget/NumberPickerButton.java
deleted file mode 100644
index 39f1e2c..0000000
--- a/core/java/com/android/internal/widget/NumberPickerButton.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.widget.ImageButton;
-
-import com.android.internal.R;
-
-/**
- * This class exists purely to cancel long click events.
- */
-public class NumberPickerButton extends ImageButton {
-
- private NumberPicker mNumberPicker;
-
- public NumberPickerButton(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public NumberPickerButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public NumberPickerButton(Context context) {
- super(context);
- }
-
- public void setNumberPicker(NumberPicker picker) {
- mNumberPicker = picker;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- cancelLongpressIfRequired(event);
- return super.onTouchEvent(event);
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event) {
- cancelLongpressIfRequired(event);
- return super.onTrackballEvent(event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if ((keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
- || (keyCode == KeyEvent.KEYCODE_ENTER)) {
- cancelLongpress();
- }
- return super.onKeyUp(keyCode, event);
- }
-
- private void cancelLongpressIfRequired(MotionEvent event) {
- if ((event.getAction() == MotionEvent.ACTION_CANCEL)
- || (event.getAction() == MotionEvent.ACTION_UP)) {
- cancelLongpress();
- }
- }
-
- private void cancelLongpress() {
- if (R.id.increment == getId()) {
- mNumberPicker.cancelIncrement();
- } else if (R.id.decrement == getId()) {
- mNumberPicker.cancelDecrement();
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/TextProgressBar.java b/core/java/com/android/internal/widget/TextProgressBar.java
deleted file mode 100644
index 5bf4601..0000000
--- a/core/java/com/android/internal/widget/TextProgressBar.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Chronometer;
-import android.widget.Chronometer.OnChronometerTickListener;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.widget.RemoteViews.RemoteView;
-
-/**
- * Container that links together a {@link ProgressBar} and {@link Chronometer}
- * as children. It subscribes to {@link Chronometer#OnChronometerTickListener}
- * and updates the {@link ProgressBar} based on a preset finishing time.
- * <p>
- * This widget expects to contain two children with specific ids
- * {@link android.R.id.progress} and {@link android.R.id.text1}.
- * <p>
- * If the {@link Chronometer} {@link android.R.attr#layout_width} is
- * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}, then the
- * {@link android.R.attr#gravity} will be used to automatically move it with
- * respect to the {@link ProgressBar} position. For example, if
- * {@link android.view.Gravity#LEFT} then the {@link Chronometer} will be placed
- * just ahead of the leading edge of the {@link ProgressBar} position.
- */
-@RemoteView
-public class TextProgressBar extends RelativeLayout implements OnChronometerTickListener {
- public static final String TAG = "TextProgressBar";
-
- static final int CHRONOMETER_ID = android.R.id.text1;
- static final int PROGRESSBAR_ID = android.R.id.progress;
-
- Chronometer mChronometer = null;
- ProgressBar mProgressBar = null;
-
- long mDurationBase = -1;
- int mDuration = -1;
-
- boolean mChronometerFollow = false;
- int mChronometerGravity = Gravity.NO_GRAVITY;
-
- public TextProgressBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public TextProgressBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public TextProgressBar(Context context) {
- super(context);
- }
-
- /**
- * Catch any interesting children when they are added.
- */
- @Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
- super.addView(child, index, params);
-
- int childId = child.getId();
- if (childId == CHRONOMETER_ID && child instanceof Chronometer) {
- mChronometer = (Chronometer) child;
- mChronometer.setOnChronometerTickListener(this);
-
- // Check if Chronometer should move with with ProgressBar
- mChronometerFollow = (params.width == ViewGroup.LayoutParams.WRAP_CONTENT);
- mChronometerGravity = (mChronometer.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
-
- } else if (childId == PROGRESSBAR_ID && child instanceof ProgressBar) {
- mProgressBar = (ProgressBar) child;
- }
- }
-
- /**
- * Set the expected termination time of the running {@link Chronometer}.
- * This value is used to adjust the {@link ProgressBar} against the elapsed
- * time.
- * <p>
- * Call this <b>after</b> adjusting the {@link Chronometer} base, if
- * necessary.
- *
- * @param durationBase Use the {@link SystemClock#elapsedRealtime} time
- * base.
- */
- @android.view.RemotableViewMethod
- public void setDurationBase(long durationBase) {
- mDurationBase = durationBase;
-
- if (mProgressBar == null || mChronometer == null) {
- throw new RuntimeException("Expecting child ProgressBar with id " +
- "'android.R.id.progress' and Chronometer id 'android.R.id.text1'");
- }
-
- // Update the ProgressBar maximum relative to Chronometer base
- mDuration = (int) (durationBase - mChronometer.getBase());
- mProgressBar.setMax(mDuration);
-
- }
-
- /**
- * Callback when {@link Chronometer} changes, indicating that we should
- * update the {@link ProgressBar} and change the layout if necessary.
- */
- public void onChronometerTick(Chronometer chronometer) {
- if (mProgressBar == null) {
- throw new RuntimeException(
- "Expecting child ProgressBar with id 'android.R.id.progress'");
- }
-
- // Stop Chronometer if we're past duration
- long now = SystemClock.elapsedRealtime();
- if (now >= mDurationBase) {
- mChronometer.stop();
- }
-
- // Update the ProgressBar status
- int remaining = (int) (mDurationBase - now);
- mProgressBar.setProgress(mDuration - remaining);
-
- // Move the Chronometer if gravity is set correctly
- if (mChronometerFollow) {
- RelativeLayout.LayoutParams params;
-
- // Calculate estimate of ProgressBar leading edge position
- params = (RelativeLayout.LayoutParams) mProgressBar.getLayoutParams();
- int contentWidth = mProgressBar.getWidth() - (params.leftMargin + params.rightMargin);
- int leadingEdge = ((contentWidth * mProgressBar.getProgress()) /
- mProgressBar.getMax()) + params.leftMargin;
-
- // Calculate any adjustment based on gravity
- int adjustLeft = 0;
- int textWidth = mChronometer.getWidth();
- if (mChronometerGravity == Gravity.RIGHT) {
- adjustLeft = -textWidth;
- } else if (mChronometerGravity == Gravity.CENTER_HORIZONTAL) {
- adjustLeft = -(textWidth / 2);
- }
-
- // Limit margin to keep text inside ProgressBar bounds
- leadingEdge += adjustLeft;
- int rightLimit = contentWidth - params.rightMargin - textWidth;
- if (leadingEdge < params.leftMargin) {
- leadingEdge = params.leftMargin;
- } else if (leadingEdge > rightLimit) {
- leadingEdge = rightLimit;
- }
-
- params = (RelativeLayout.LayoutParams) mChronometer.getLayoutParams();
- params.leftMargin = leadingEdge;
-
- // Request layout to move Chronometer
- mChronometer.requestLayout();
-
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/VerticalTextSpinner.java b/core/java/com/android/internal/widget/VerticalTextSpinner.java
deleted file mode 100644
index 50c528c..0000000
--- a/core/java/com/android/internal/widget/VerticalTextSpinner.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.TextPaint;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-
-
-public class VerticalTextSpinner extends View {
-
- private static final int SELECTOR_ARROW_HEIGHT = 15;
-
- private static final int TEXT_SPACING = 18;
- private static final int TEXT_MARGIN_RIGHT = 25;
- private static final int TEXT_SIZE = 22;
-
- /* Keep the calculations as this is really a for loop from
- * -2 to 2 but precalculated so we don't have to do in the onDraw.
- */
- private static final int TEXT1_Y = (TEXT_SIZE * (-2 + 2)) + (TEXT_SPACING * (-2 + 1));
- private static final int TEXT2_Y = (TEXT_SIZE * (-1 + 2)) + (TEXT_SPACING * (-1 + 1));
- private static final int TEXT3_Y = (TEXT_SIZE * (0 + 2)) + (TEXT_SPACING * (0 + 1));
- private static final int TEXT4_Y = (TEXT_SIZE * (1 + 2)) + (TEXT_SPACING * (1 + 1));
- private static final int TEXT5_Y = (TEXT_SIZE * (2 + 2)) + (TEXT_SPACING * (2 + 1));
-
- private static final int SCROLL_MODE_NONE = 0;
- private static final int SCROLL_MODE_UP = 1;
- private static final int SCROLL_MODE_DOWN = 2;
-
- private static final long DEFAULT_SCROLL_INTERVAL_MS = 400;
- private static final int SCROLL_DISTANCE = TEXT_SIZE + TEXT_SPACING;
- private static final int MIN_ANIMATIONS = 4;
-
- private final Drawable mBackgroundFocused;
- private final Drawable mSelectorFocused;
- private final Drawable mSelectorNormal;
- private final int mSelectorDefaultY;
- private final int mSelectorMinY;
- private final int mSelectorMaxY;
- private final int mSelectorHeight;
- private final TextPaint mTextPaintDark;
- private final TextPaint mTextPaintLight;
-
- private int mSelectorY;
- private Drawable mSelector;
- private int mDownY;
- private boolean isDraggingSelector;
- private int mScrollMode;
- private long mScrollInterval;
- private boolean mIsAnimationRunning;
- private boolean mStopAnimation;
- private boolean mWrapAround = true;
-
- private int mTotalAnimatedDistance;
- private int mNumberOfAnimations;
- private long mDelayBetweenAnimations;
- private int mDistanceOfEachAnimation;
-
- private String[] mTextList;
- private int mCurrentSelectedPos;
- private OnChangedListener mListener;
-
- private String mText1;
- private String mText2;
- private String mText3;
- private String mText4;
- private String mText5;
-
- public interface OnChangedListener {
- void onChanged(
- VerticalTextSpinner spinner, int oldPos, int newPos, String[] items);
- }
-
- public VerticalTextSpinner(Context context) {
- this(context, null);
- }
-
- public VerticalTextSpinner(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public VerticalTextSpinner(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
-
- mBackgroundFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_background);
- mSelectorFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_selected);
- mSelectorNormal = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_unselected);
-
- mSelectorHeight = mSelectorFocused.getIntrinsicHeight();
- mSelectorDefaultY = (mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight) / 2;
- mSelectorMinY = 0;
- mSelectorMaxY = mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight;
-
- mSelector = mSelectorNormal;
- mSelectorY = mSelectorDefaultY;
-
- mTextPaintDark = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaintDark.setTextSize(TEXT_SIZE);
- mTextPaintDark.setColor(context.getResources().getColor(com.android.internal.R.color.primary_text_light));
-
- mTextPaintLight = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaintLight.setTextSize(TEXT_SIZE);
- mTextPaintLight.setColor(context.getResources().getColor(com.android.internal.R.color.secondary_text_dark));
-
- mScrollMode = SCROLL_MODE_NONE;
- mScrollInterval = DEFAULT_SCROLL_INTERVAL_MS;
- calculateAnimationValues();
- }
-
- public void setOnChangeListener(OnChangedListener listener) {
- mListener = listener;
- }
-
- public void setItems(String[] textList) {
- mTextList = textList;
- calculateTextPositions();
- }
-
- public void setSelectedPos(int selectedPos) {
- mCurrentSelectedPos = selectedPos;
- calculateTextPositions();
- postInvalidate();
- }
-
- public void setScrollInterval(long interval) {
- mScrollInterval = interval;
- calculateAnimationValues();
- }
-
- public void setWrapAround(boolean wrap) {
- mWrapAround = wrap;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
-
- /* This is a bit confusing, when we get the key event
- * DPAD_DOWN we actually roll the spinner up. When the
- * key event is DPAD_UP we roll the spinner down.
- */
- if ((keyCode == KeyEvent.KEYCODE_DPAD_UP) && canScrollDown()) {
- mScrollMode = SCROLL_MODE_DOWN;
- scroll();
- mStopAnimation = true;
- return true;
- } else if ((keyCode == KeyEvent.KEYCODE_DPAD_DOWN) && canScrollUp()) {
- mScrollMode = SCROLL_MODE_UP;
- scroll();
- mStopAnimation = true;
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- private boolean canScrollDown() {
- return (mCurrentSelectedPos > 0) || mWrapAround;
- }
-
- private boolean canScrollUp() {
- return ((mCurrentSelectedPos < (mTextList.length - 1)) || mWrapAround);
- }
-
- @Override
- protected void onFocusChanged(boolean gainFocus, int direction,
- Rect previouslyFocusedRect) {
- if (gainFocus) {
- setBackgroundDrawable(mBackgroundFocused);
- mSelector = mSelectorFocused;
- } else {
- setBackgroundDrawable(null);
- mSelector = mSelectorNormal;
- mSelectorY = mSelectorDefaultY;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- final int action = event.getAction();
- final int y = (int) event.getY();
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- requestFocus();
- mDownY = y;
- isDraggingSelector = (y >= mSelectorY) && (y <= (mSelectorY + mSelector.getIntrinsicHeight()));
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (isDraggingSelector) {
- int top = mSelectorDefaultY + (y - mDownY);
- if (top <= mSelectorMinY && canScrollDown()) {
- mSelectorY = mSelectorMinY;
- mStopAnimation = false;
- if (mScrollMode != SCROLL_MODE_DOWN) {
- mScrollMode = SCROLL_MODE_DOWN;
- scroll();
- }
- } else if (top >= mSelectorMaxY && canScrollUp()) {
- mSelectorY = mSelectorMaxY;
- mStopAnimation = false;
- if (mScrollMode != SCROLL_MODE_UP) {
- mScrollMode = SCROLL_MODE_UP;
- scroll();
- }
- } else {
- mSelectorY = top;
- mStopAnimation = true;
- }
- }
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- default:
- mSelectorY = mSelectorDefaultY;
- mStopAnimation = true;
- invalidate();
- break;
- }
- return true;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
-
- /* The bounds of the selector */
- final int selectorLeft = 0;
- final int selectorTop = mSelectorY;
- final int selectorRight = mMeasuredWidth;
- final int selectorBottom = mSelectorY + mSelectorHeight;
-
- /* Draw the selector */
- mSelector.setBounds(selectorLeft, selectorTop, selectorRight, selectorBottom);
- mSelector.draw(canvas);
-
- if (mTextList == null) {
-
- /* We're not setup with values so don't draw anything else */
- return;
- }
-
- final TextPaint textPaintDark = mTextPaintDark;
- if (hasFocus()) {
-
- /* The bounds of the top area where the text should be light */
- final int topLeft = 0;
- final int topTop = 0;
- final int topRight = selectorRight;
- final int topBottom = selectorTop + SELECTOR_ARROW_HEIGHT;
-
- /* Assign a bunch of local finals for performance */
- final String text1 = mText1;
- final String text2 = mText2;
- final String text3 = mText3;
- final String text4 = mText4;
- final String text5 = mText5;
- final TextPaint textPaintLight = mTextPaintLight;
-
- /*
- * Draw the 1st, 2nd and 3rd item in light only, clip it so it only
- * draws in the area above the selector
- */
- canvas.save();
- canvas.clipRect(topLeft, topTop, topRight, topBottom);
- drawText(canvas, text1, TEXT1_Y
- + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text2, TEXT2_Y
- + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text3,
- TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
- canvas.restore();
-
- /*
- * Draw the 2nd, 3rd and 4th clipped to the selector bounds in dark
- * paint
- */
- canvas.save();
- canvas.clipRect(selectorLeft, selectorTop + SELECTOR_ARROW_HEIGHT,
- selectorRight, selectorBottom - SELECTOR_ARROW_HEIGHT);
- drawText(canvas, text2, TEXT2_Y
- + mTotalAnimatedDistance, textPaintDark);
- drawText(canvas, text3,
- TEXT3_Y + mTotalAnimatedDistance, textPaintDark);
- drawText(canvas, text4,
- TEXT4_Y + mTotalAnimatedDistance, textPaintDark);
- canvas.restore();
-
- /* The bounds of the bottom area where the text should be light */
- final int bottomLeft = 0;
- final int bottomTop = selectorBottom - SELECTOR_ARROW_HEIGHT;
- final int bottomRight = selectorRight;
- final int bottomBottom = mMeasuredHeight;
-
- /*
- * Draw the 3rd, 4th and 5th in white text, clip it so it only draws
- * in the area below the selector.
- */
- canvas.save();
- canvas.clipRect(bottomLeft, bottomTop, bottomRight, bottomBottom);
- drawText(canvas, text3,
- TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text4,
- TEXT4_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text5,
- TEXT5_Y + mTotalAnimatedDistance, textPaintLight);
- canvas.restore();
-
- } else {
- drawText(canvas, mText3, TEXT3_Y, textPaintDark);
- }
- if (mIsAnimationRunning) {
- if ((Math.abs(mTotalAnimatedDistance) + mDistanceOfEachAnimation) > SCROLL_DISTANCE) {
- mTotalAnimatedDistance = 0;
- if (mScrollMode == SCROLL_MODE_UP) {
- int oldPos = mCurrentSelectedPos;
- int newPos = getNewIndex(1);
- if (newPos >= 0) {
- mCurrentSelectedPos = newPos;
- if (mListener != null) {
- mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
- }
- }
- if (newPos < 0 || ((newPos >= mTextList.length - 1) && !mWrapAround)) {
- mStopAnimation = true;
- }
- calculateTextPositions();
- } else if (mScrollMode == SCROLL_MODE_DOWN) {
- int oldPos = mCurrentSelectedPos;
- int newPos = getNewIndex(-1);
- if (newPos >= 0) {
- mCurrentSelectedPos = newPos;
- if (mListener != null) {
- mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
- }
- }
- if (newPos < 0 || (newPos == 0 && !mWrapAround)) {
- mStopAnimation = true;
- }
- calculateTextPositions();
- }
- if (mStopAnimation) {
- final int previousScrollMode = mScrollMode;
-
- /* No longer scrolling, we wait till the current animation
- * completes then we stop.
- */
- mIsAnimationRunning = false;
- mStopAnimation = false;
- mScrollMode = SCROLL_MODE_NONE;
-
- /* If the current selected item is an empty string
- * scroll past it.
- */
- if ("".equals(mTextList[mCurrentSelectedPos])) {
- mScrollMode = previousScrollMode;
- scroll();
- mStopAnimation = true;
- }
- }
- } else {
- if (mScrollMode == SCROLL_MODE_UP) {
- mTotalAnimatedDistance -= mDistanceOfEachAnimation;
- } else if (mScrollMode == SCROLL_MODE_DOWN) {
- mTotalAnimatedDistance += mDistanceOfEachAnimation;
- }
- }
- if (mDelayBetweenAnimations > 0) {
- postInvalidateDelayed(mDelayBetweenAnimations);
- } else {
- invalidate();
- }
- }
- }
-
- /**
- * Called every time the text items or current position
- * changes. We calculate store we don't have to calculate
- * onDraw.
- */
- private void calculateTextPositions() {
- mText1 = getTextToDraw(-2);
- mText2 = getTextToDraw(-1);
- mText3 = getTextToDraw(0);
- mText4 = getTextToDraw(1);
- mText5 = getTextToDraw(2);
- }
-
- private String getTextToDraw(int offset) {
- int index = getNewIndex(offset);
- if (index < 0) {
- return "";
- }
- return mTextList[index];
- }
-
- private int getNewIndex(int offset) {
- int index = mCurrentSelectedPos + offset;
- if (index < 0) {
- if (mWrapAround) {
- index += mTextList.length;
- } else {
- return -1;
- }
- } else if (index >= mTextList.length) {
- if (mWrapAround) {
- index -= mTextList.length;
- } else {
- return -1;
- }
- }
- return index;
- }
-
- private void scroll() {
- if (mIsAnimationRunning) {
- return;
- }
- mTotalAnimatedDistance = 0;
- mIsAnimationRunning = true;
- invalidate();
- }
-
- private void calculateAnimationValues() {
- mNumberOfAnimations = (int) mScrollInterval / SCROLL_DISTANCE;
- if (mNumberOfAnimations < MIN_ANIMATIONS) {
- mNumberOfAnimations = MIN_ANIMATIONS;
- mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
- mDelayBetweenAnimations = 0;
- } else {
- mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
- mDelayBetweenAnimations = mScrollInterval / mNumberOfAnimations;
- }
- }
-
- private void drawText(Canvas canvas, String text, int y, TextPaint paint) {
- int width = (int) paint.measureText(text);
- int x = getMeasuredWidth() - width - TEXT_MARGIN_RIGHT;
- canvas.drawText(text, x, y, paint);
- }
-
- public int getCurrentSelectedPos() {
- return mCurrentSelectedPos;
- }
-}