PasswordTextViewpublic class PasswordTextView extends android.view.View A View similar to a textView which contains password text and can animate when the text is
changed |
Fields Summary |
---|
private static final float | DOT_OVERSHOOT_FACTOR | private static final long | DOT_APPEAR_DURATION_OVERSHOOT | private static final long | APPEAR_DURATION | private static final long | DISAPPEAR_DURATION | private static final long | RESET_DELAY_PER_ELEMENT | private static final long | RESET_MAX_DELAY | private static final long | DOT_APPEAR_TEXT_DISAPPEAR_OVERLAP_DURATIONThe overlap between the text disappearing and the dot appearing animation | private static final long | TEXT_REST_DURATION_AFTER_APPEARThe duration the text needs to stay there at least before it can morph into a dot | private static final long | TEXT_VISIBILITY_DURATIONThe duration the text should be visible, starting with the appear animation | private static final float | OVERSHOOT_TIME_POSITIONThe position in time from [0,1] where the overshoot should be finished and the settle back
animation of the dot should start | private final int | mTextHeightRawThe raw text size, will be multiplied by the scaled density when drawn | private ArrayList | mTextChars | private String | mText | private Stack | mCharPool | private int | mDotSize | private android.os.PowerManager | mPM | private int | mCharPadding | private final android.graphics.Paint | mDrawPaint | private android.view.animation.Interpolator | mAppearInterpolator | private android.view.animation.Interpolator | mDisappearInterpolator | private android.view.animation.Interpolator | mFastOutSlowInInterpolator | private boolean | mShowPassword |
Constructors Summary |
---|
public PasswordTextView(android.content.Context context)
this(context, null);
| public PasswordTextView(android.content.Context context, android.util.AttributeSet attrs)
this(context, attrs, 0);
| public PasswordTextView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
this(context, attrs, defStyleAttr, 0);
| public PasswordTextView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)
super(context, attrs, defStyleAttr, defStyleRes);
setFocusableInTouchMode(true);
setFocusable(true);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PasswordTextView);
try {
mTextHeightRaw = a.getInt(R.styleable.PasswordTextView_scaledTextSize, 0);
} finally {
a.recycle();
}
mDrawPaint.setFlags(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
mDrawPaint.setTextAlign(Paint.Align.CENTER);
mDrawPaint.setColor(0xffffffff);
mDrawPaint.setTypeface(Typeface.create("sans-serif-light", 0));
mDotSize = getContext().getResources().getDimensionPixelSize(R.dimen.password_dot_size);
mCharPadding = getContext().getResources().getDimensionPixelSize(R.dimen
.password_char_padding);
mShowPassword = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.TEXT_SHOW_PASSWORD, 1) == 1;
mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.linear_out_slow_in);
mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.fast_out_linear_in);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.fast_out_slow_in);
mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
Methods Summary |
---|
public void | append(char c)
int visibleChars = mTextChars.size();
String textbefore = mText;
mText = mText + c;
int newLength = mText.length();
CharState charState;
if (newLength > visibleChars) {
charState = obtainCharState(c);
mTextChars.add(charState);
} else {
charState = mTextChars.get(newLength - 1);
charState.whichChar = c;
}
charState.startAppearAnimation();
// ensure that the previous element is being swapped
if (newLength > 1) {
CharState previousState = mTextChars.get(newLength - 2);
if (previousState.isDotSwapPending) {
previousState.swapToDotWhenAppearFinished();
}
}
userActivity();
sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length(), 0, 1);
| public void | deleteLastChar()
int length = mText.length();
String textbefore = mText;
if (length > 0) {
mText = mText.substring(0, length - 1);
CharState charState = mTextChars.get(length - 1);
charState.startRemoveAnimation(0, 0);
}
userActivity();
sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
| private android.graphics.Rect | getCharBounds()
float textHeight = mTextHeightRaw * getResources().getDisplayMetrics().scaledDensity;
mDrawPaint.setTextSize(textHeight);
Rect bounds = new Rect();
mDrawPaint.getTextBounds("0", 0, 1, bounds);
return bounds;
| private float | getDrawingWidth()
int width = 0;
int length = mTextChars.size();
Rect bounds = getCharBounds();
int charLength = bounds.right - bounds.left;
for (int i = 0; i < length; i++) {
CharState charState = mTextChars.get(i);
if (i != 0) {
width += mCharPadding * charState.currentWidthFactor;
}
width += charLength * charState.currentWidthFactor;
}
return width;
| public java.lang.String | getText()
return mText;
| public boolean | hasOverlappingRendering()
return false;
| private com.android.keyguard.PasswordTextView$CharState | obtainCharState(char c)
CharState charState;
if(mCharPool.isEmpty()) {
charState = new CharState();
} else {
charState = mCharPool.pop();
charState.reset();
}
charState.whichChar = c;
return charState;
| protected void | onDraw(android.graphics.Canvas canvas)
float totalDrawingWidth = getDrawingWidth();
float currentDrawPosition = getWidth() / 2 - totalDrawingWidth / 2;
int length = mTextChars.size();
Rect bounds = getCharBounds();
int charHeight = (bounds.bottom - bounds.top);
float yPosition = getHeight() / 2;
float charLength = bounds.right - bounds.left;
for (int i = 0; i < length; i++) {
CharState charState = mTextChars.get(i);
float charWidth = charState.draw(canvas, currentDrawPosition, charHeight, yPosition,
charLength);
currentDrawPosition += charWidth;
}
| public void | onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)
super.onInitializeAccessibilityEvent(event);
event.setClassName(PasswordTextView.class.getName());
event.setPassword(true);
| public void | onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(PasswordTextView.class.getName());
info.setPassword(true);
if (shouldSpeakPasswordsForAccessibility()) {
info.setText(mText);
}
info.setEditable(true);
info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
| public void | onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)
super.onPopulateAccessibilityEvent(event);
if (shouldSpeakPasswordsForAccessibility()) {
final CharSequence text = mText;
if (!TextUtils.isEmpty(text)) {
event.getText().add(text);
}
}
| public void | reset(boolean animated)
String textbefore = mText;
mText = "";
int length = mTextChars.size();
int middleIndex = (length - 1) / 2;
long delayPerElement = RESET_DELAY_PER_ELEMENT;
for (int i = 0; i < length; i++) {
CharState charState = mTextChars.get(i);
if (animated) {
int delayIndex;
if (i <= middleIndex) {
delayIndex = i * 2;
} else {
int distToMiddle = i - middleIndex;
delayIndex = (length - 1) - (distToMiddle - 1) * 2;
}
long startDelay = delayIndex * delayPerElement;
startDelay = Math.min(startDelay, RESET_MAX_DELAY);
long maxDelay = delayPerElement * (length - 1);
maxDelay = Math.min(maxDelay, RESET_MAX_DELAY) + DISAPPEAR_DURATION;
charState.startRemoveAnimation(startDelay, maxDelay);
charState.removeDotSwapCallbacks();
} else {
mCharPool.push(charState);
}
}
if (!animated) {
mTextChars.clear();
}
sendAccessibilityEventTypeViewTextChanged(textbefore, 0, textbefore.length(), 0);
| void | sendAccessibilityEventTypeViewTextChanged(java.lang.String beforeText, int fromIndex, int removedCount, int addedCount)
if (AccessibilityManager.getInstance(mContext).isEnabled() &&
(isFocused() || isSelected() && isShown())) {
if (!shouldSpeakPasswordsForAccessibility()) {
beforeText = null;
}
AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
event.setFromIndex(fromIndex);
event.setRemovedCount(removedCount);
event.setAddedCount(addedCount);
event.setBeforeText(beforeText);
event.setPassword(true);
sendAccessibilityEventUnchecked(event);
}
| private boolean | shouldSpeakPasswordsForAccessibility()
return (Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0,
UserHandle.USER_CURRENT_OR_SELF) == 1);
| private void | userActivity()
mPM.userActivity(SystemClock.uptimeMillis(), false);
|
|