import android.os.SystemClock;
import android.provider.Settings;
import android.text.InputType;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
*/
private static final float OVERSHOOT_TIME_POSITION = 0.5f;
+ private static char DOT = '\u2022';
+
/**
* The raw text size, will be multiplied by the scaled density when drawn
*/
public void append(char c) {
int visibleChars = mTextChars.size();
- String textbefore = mText;
+ CharSequence textbefore = getTransformedText();
mText = mText + c;
int newLength = mText.length();
CharState charState;
public void deleteLastChar() {
int length = mText.length();
- String textbefore = mText;
+ CharSequence textbefore = getTransformedText();
if (length > 0) {
mText = mText.substring(0, length - 1);
CharState charState = mTextChars.get(length - 1);
return mText;
}
+ private CharSequence getTransformedText() {
+ int textLength = mTextChars.size();
+ StringBuilder stringBuilder = new StringBuilder(textLength);
+ for (int i = 0; i < textLength; i++) {
+ CharState charState = mTextChars.get(i);
+ // If the dot is disappearing, the character is disappearing entirely. Consider
+ // it gone.
+ if (charState.dotAnimator != null && !charState.dotAnimationIsGrowing) {
+ continue;
+ }
+ stringBuilder.append(charState.isCharVisibleForA11y() ? charState.whichChar : DOT);
+ }
+ return stringBuilder;
+ }
+
private CharState obtainCharState(char c) {
CharState charState;
if(mCharPool.isEmpty()) {
}
public void reset(boolean animated, boolean announce) {
- String textbefore = mText;
+ CharSequence textbefore = getTransformedText();
mText = "";
int length = mTextChars.size();
int middleIndex = (length - 1) / 2;
}
}
- void sendAccessibilityEventTypeViewTextChanged(String beforeText, int fromIndex,
+ void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, int fromIndex,
int removedCount, int addedCount) {
if (AccessibilityManager.getInstance(mContext).isEnabled() &&
(isFocused() || isSelected() && isShown())) {
event.setRemovedCount(removedCount);
event.setAddedCount(addedCount);
event.setBeforeText(beforeText);
+ CharSequence transformedText = getTransformedText();
+ if (!TextUtils.isEmpty(transformedText)) {
+ event.getText().add(transformedText);
+ }
event.setPassword(true);
sendAccessibilityEventUnchecked(event);
}
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
- info.setClassName(PasswordTextView.class.getName());
+ info.setClassName(EditText.class.getName());
info.setPassword(true);
+ info.setText(getTransformedText());
info.setEditable(true);
= new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
+ boolean textVisibleBefore = isCharVisibleForA11y();
+ float beforeTextSizeFactor = currentTextSizeFactor;
currentTextSizeFactor = (float) animation.getAnimatedValue();
+ if (textVisibleBefore != isCharVisibleForA11y()) {
+ currentTextSizeFactor = beforeTextSizeFactor;
+ CharSequence beforeText = getTransformedText();
+ currentTextSizeFactor = (float) animation.getAnimatedValue();
+ int indexOfThisChar = mTextChars.indexOf(CharState.this);
+ if (indexOfThisChar >= 0) {
+ sendAccessibilityEventTypeViewTextChanged(
+ beforeText, indexOfThisChar, 1, 1);
+ }
+ }
invalidate();
}
};
}
return charWidth + mCharPadding * currentWidthFactor;
}
+
+ public boolean isCharVisibleForA11y() {
+ // The text has size 0 when it is first added, but we want to count it as visible if
+ // it will become visible presently. Count text as visible if an animator
+ // is configured to make it grow.
+ boolean textIsGrowing = textAnimator != null && textAnimationIsGrowing;
+ return (currentTextSizeFactor > 0) || textIsGrowing;
+ }
}
}