diff options
Diffstat (limited to 'v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowTextView.java')
-rw-r--r-- | v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowTextView.java | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowTextView.java b/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowTextView.java new file mode 100644 index 000000000..3027fcc4a --- /dev/null +++ b/v1/src/main/java/com/xtremelabs/robolectric/shadows/ShadowTextView.java @@ -0,0 +1,603 @@ +package com.xtremelabs.robolectric.shadows; + +import android.content.Context; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.TextWatcher; +import android.text.method.MovementMethod; +import android.text.method.TransformationMethod; +import android.text.style.URLSpan; +import android.text.util.Linkify; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.EditorInfo; +import android.widget.TextView; +import com.xtremelabs.robolectric.internal.Implementation; +import com.xtremelabs.robolectric.internal.Implements; + +import java.util.ArrayList; +import java.util.List; + +import static android.view.View.VISIBLE; +import static com.xtremelabs.robolectric.Robolectric.shadowOf; +import static com.xtremelabs.robolectric.Robolectric.shadowOf_; + +@SuppressWarnings({"UnusedDeclaration"}) +@Implements(TextView.class) +public class ShadowTextView extends ShadowView { + private CharSequence text = ""; + private CompoundDrawables compoundDrawablesImpl = new CompoundDrawables(0, 0, 0, 0); + private Integer textColorHexValue; + private Integer hintColorHexValue; + private float textSize = 14.0f; + private boolean autoLinkPhoneNumbers; + private int autoLinkMask; + private CharSequence hintText; + private CharSequence errorText; + private int compoundDrawablePadding; + private MovementMethod movementMethod; + private boolean linksClickable; + private int gravity; + private TextView.OnEditorActionListener onEditorActionListener; + private int imeOptions = EditorInfo.IME_NULL; + private int textAppearanceId; + private TransformationMethod transformationMethod; + private int inputType; + protected int selectionStart = 0; + protected int selectionEnd = 0; + private Typeface typeface; + + private List<TextWatcher> watchers = new ArrayList<TextWatcher>(); + private List<Integer> previousKeyCodes = new ArrayList<Integer>(); + private List<KeyEvent> previousKeyEvents = new ArrayList<KeyEvent>(); + private Layout layout; + + @Override + public void applyAttributes() { + super.applyAttributes(); + applyTextAttribute(); + applyTextColorAttribute(); + applyHintAttribute(); + applyHintColorAttribute(); + applyCompoundDrawablesWithIntrinsicBoundsAttributes(); + } + + @Implementation(i18nSafe = false) + public void setText(CharSequence text) { + if (text == null) { + text = ""; + } + + sendBeforeTextChanged(text); + + CharSequence oldValue = this.text; + this.text = text; + + sendOnTextChanged(oldValue); + sendAfterTextChanged(); + } + + @Implementation + public final void append(CharSequence text) { + boolean isSelectStartAtEnd = selectionStart == this.text.length(); + boolean isSelectEndAtEnd = selectionEnd == this.text.length(); + CharSequence oldValue = this.text; + StringBuffer sb = new StringBuffer(this.text); + sb.append(text); + + sendBeforeTextChanged(sb.toString()); + this.text = sb.toString(); + + if (isSelectStartAtEnd) { + selectionStart = this.text.length(); + } + if (isSelectEndAtEnd) { + selectionEnd = this.text.length(); + } + + sendOnTextChanged(oldValue); + sendAfterTextChanged(); + } + + @Implementation + public void setText(int textResourceId) { + sendBeforeTextChanged(text); + + CharSequence oldValue = this.text; + this.text = getResources().getText(textResourceId); + + sendOnTextChanged(oldValue); + sendAfterTextChanged(); + } + + private void sendAfterTextChanged() { + for (TextWatcher watcher : watchers) { + watcher.afterTextChanged(new SpannableStringBuilder(getText())); + } + } + + private void sendOnTextChanged(CharSequence oldValue) { + for (TextWatcher watcher : watchers) { + watcher.onTextChanged(text, 0, oldValue.length(), text.length()); + } + } + + private void sendBeforeTextChanged(CharSequence newValue) { + for (TextWatcher watcher : watchers) { + watcher.beforeTextChanged(this.text, 0, this.text.length(), newValue.length()); + } + } + + @Implementation + public CharSequence getText() { + return text; + } + + @Implementation + public Typeface getTypeface() { + return typeface; + } + + @Implementation + public void setTypeface(Typeface typeface) { + this.typeface = typeface; + } + + @Implementation + public int length() { + return text.length(); + } + + @Implementation + public void setTextColor(int color) { + textColorHexValue = color; + } + + @Implementation + public void setTextSize(float size) { + textSize = size; + } + + @Implementation + public void setTextAppearance(Context context, int resid) { + textAppearanceId = resid; + } + + @Implementation + public void setInputType(int type) { + this.inputType = type; + } + + @Implementation + public int getInputType() { + return this.inputType; + } + + @Implementation + public final void setHint(int resId) { + this.hintText = getResources().getText(resId); + } + + @Implementation(i18nSafe = false) + public final void setHint(CharSequence hintText) { + this.hintText = hintText; + } + + @Implementation + public CharSequence getHint() { + return hintText; + } + + @Implementation + public final void setHintTextColor(int color) { + hintColorHexValue = color; + } + + @Implementation + public final boolean getLinksClickable() { + return linksClickable; + } + + @Implementation + public final void setLinksClickable(boolean whether) { + linksClickable = whether; + } + + @Implementation + public final MovementMethod getMovementMethod() { + return movementMethod; + } + + @Implementation + public final void setMovementMethod(MovementMethod movement) { + movementMethod = movement; + } + + @Implementation + public URLSpan[] getUrls() { + String[] words = text.toString().split("\\s+"); + List<URLSpan> urlSpans = new ArrayList<URLSpan>(); + for (String word : words) { + if (word.startsWith("http://")) { + urlSpans.add(new URLSpan(word)); + } + } + return urlSpans.toArray(new URLSpan[urlSpans.size()]); + } + + @Implementation + public final void setAutoLinkMask(int mask) { + autoLinkMask = mask; + + autoLinkPhoneNumbers = (mask & Linkify.PHONE_NUMBERS) != 0; + } + + @Implementation + public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) { + compoundDrawablesImpl = new CompoundDrawables(left, top, right, bottom); + } + + @Implementation + public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, + Drawable right, Drawable bottom) { + compoundDrawablesImpl = new CompoundDrawables(left, top, right, bottom); + } + + @Implementation + public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) { + compoundDrawablesImpl = new CompoundDrawables(left, top, right, bottom); + } + + @Implementation + public Drawable[] getCompoundDrawables() { + if (compoundDrawablesImpl == null) { + return new Drawable[]{null, null, null, null}; + } + return new Drawable[]{ + compoundDrawablesImpl.leftDrawable, + compoundDrawablesImpl.topDrawable, + compoundDrawablesImpl.rightDrawable, + compoundDrawablesImpl.bottomDrawable + }; + } + + @Implementation + public void setCompoundDrawablePadding(int compoundDrawablePadding) { + this.compoundDrawablePadding = compoundDrawablePadding; + } + + @Implementation + public int getCompoundDrawablePadding() { + return compoundDrawablePadding; + } + + @Implementation + public boolean onKeyDown(int keyCode, KeyEvent event) { + previousKeyCodes.add(keyCode); + previousKeyEvents.add(event); + if (onKeyListener != null) { + return onKeyListener.onKey(realView, keyCode, event); + } else { + return false; + } + } + + @Implementation + public boolean onKeyUp(int keyCode, KeyEvent event) { + previousKeyCodes.add(keyCode); + previousKeyEvents.add(event); + if (onKeyListener != null) { + return onKeyListener.onKey(realView, keyCode, event); + } else { + return false; + } + } + + public int getPreviousKeyCode(int index) { + return previousKeyCodes.get(index); + } + + public KeyEvent getPreviousKeyEvent(int index) { + return previousKeyEvents.get(index); + } + + @Implementation + public int getGravity() { + return gravity; + } + + @Implementation + public void setGravity(int gravity) { + this.gravity = gravity; + } + + + @Implementation + public int getImeOptions() { + return imeOptions; + } + + @Implementation + public void setImeOptions(int imeOptions) { + this.imeOptions = imeOptions; + } + + /** + * Returns the text string of this {@code TextView}. + * <p/> + * Robolectric extension. + */ + @Override + public String innerText() { + return (text == null || getVisibility() != VISIBLE) ? "" : text.toString(); + } + + @Implementation + public void setError(CharSequence error) { + errorText = error; + } + + @Implementation + public CharSequence getError() { + return errorText; + } + + @Override + @Implementation + public boolean equals(Object o) { + return super.equals(shadowOf_(o)); + } + + @Override + @Implementation + public int hashCode() { + return super.hashCode(); + } + + public CompoundDrawables getCompoundDrawablesImpl() { + return compoundDrawablesImpl; + } + + void setCompoundDrawablesImpl(CompoundDrawables compoundDrawablesImpl) { + this.compoundDrawablesImpl = compoundDrawablesImpl; + } + + public Integer getTextColorHexValue() { + return textColorHexValue; + } + + public int getTextAppearanceId() { + return textAppearanceId; + } + + public Integer getHintColorHexValue() { + return hintColorHexValue; + } + + @Implementation + public float getTextSize() { + return textSize; + } + + public boolean isAutoLinkPhoneNumbers() { + return autoLinkPhoneNumbers; + } + + private void applyTextAttribute() { + String text = attributeSet.getAttributeValue("android", "text"); + if (text != null) { + if (text.startsWith("@string/")) { + int textResId = attributeSet.getAttributeResourceValue("android", "text", 0); + text = context.getResources().getString(textResId); + } + setText(text); + } + } + + private void applyTextColorAttribute() { + String colorValue = attributeSet.getAttributeValue("android", "textColor"); + if (colorValue != null) { + if (colorValue.startsWith("@color/") || colorValue.startsWith("@android:color/")) { + int colorResId = attributeSet.getAttributeResourceValue("android", "textColor", 0); + setTextColor(context.getResources().getColor(colorResId)); + } else if (colorValue.startsWith("#")) { + int colorFromHex = (int) Long.valueOf(colorValue.replaceAll("#", ""), 16).longValue(); + setTextColor(colorFromHex); + } + } + } + + private void applyHintAttribute() { + String hint = attributeSet.getAttributeValue("android", "hint"); + if (hint != null) { + if (hint.startsWith("@string/")) { + int textResId = attributeSet.getAttributeResourceValue("android", "hint", 0); + hint = context.getResources().getString(textResId); + + } + setHint(hint); + } + } + + private void applyHintColorAttribute() { + String colorValue = attributeSet.getAttributeValue("android", "hintColor"); + if (colorValue != null) { + if (colorValue.startsWith("@color/") || colorValue.startsWith("@android:color/")) { + int colorResId = attributeSet.getAttributeResourceValue("android", "hintColor", 0); + setHintTextColor(context.getResources().getColor(colorResId)); + } else if (colorValue.startsWith("#")) { + int colorFromHex = (int) Long.valueOf(colorValue.replaceAll("#", ""), 16).longValue(); + setHintTextColor(colorFromHex); + } + } + } + + private void applyCompoundDrawablesWithIntrinsicBoundsAttributes() { + setCompoundDrawablesWithIntrinsicBounds( + attributeSet.getAttributeResourceValue("android", "drawableLeft", 0), + attributeSet.getAttributeResourceValue("android", "drawableTop", 0), + attributeSet.getAttributeResourceValue("android", "drawableRight", 0), + attributeSet.getAttributeResourceValue("android", "drawableBottom", 0)); + } + + @Implementation + public void setOnEditorActionListener(android.widget.TextView.OnEditorActionListener onEditorActionListener) { + this.onEditorActionListener = onEditorActionListener; + } + + public boolean triggerEditorAction(int imeAction) { + if (onEditorActionListener != null) { + return onEditorActionListener.onEditorAction((TextView) realView, imeAction, null); + } + return false; + } + + @Implementation + public void setTransformationMethod(TransformationMethod transformationMethod) { + this.transformationMethod = transformationMethod; + } + + @Implementation + public TransformationMethod getTransformationMethod() { + return transformationMethod; + } + + @Implementation + public void addTextChangedListener(TextWatcher watcher) { + this.watchers.add(watcher); + } + + @Implementation + public void removeTextChangedListener(TextWatcher watcher) { + this.watchers.remove(watcher); + } + + @Implementation + public TextPaint getPaint() { + return new TextPaint(); + } + + @Implementation + public Layout getLayout() { + return this.layout; + } + + public void setSelection(int index) { + setSelection(index, index); + } + + public void setSelection(int start, int end) { + selectionStart = start; + selectionEnd = end; + } + + @Implementation + public int getSelectionStart() { + return selectionStart; + } + + @Implementation + public int getSelectionEnd() { + return selectionEnd; + } + + @Implementation + public boolean onTouchEvent(MotionEvent event) { + boolean superResult = super.onTouchEvent(event); + + if (movementMethod != null) { + boolean handled = movementMethod.onTouchEvent(null, null, event); + + if (handled) { + return true; + } + } + + return superResult; + } + + /** + * @return the list of currently registered watchers/listeners + */ + public List<TextWatcher> getWatchers() { + return watchers; + } + + public void setLayout(Layout layout) { + this.layout = layout; + } + + public static class CompoundDrawables { + public Drawable leftDrawable; + public Drawable topDrawable; + public Drawable rightDrawable; + public Drawable bottomDrawable; + + public CompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) { + leftDrawable = left; + topDrawable = top; + rightDrawable = right; + bottomDrawable = bottom; + } + + public CompoundDrawables(int left, int top, int right, int bottom) { + leftDrawable = left != 0 ? ShadowDrawable.createFromResourceId(left) : null; + topDrawable = top != 0 ? ShadowDrawable.createFromResourceId(top) : null; + rightDrawable = right != 0 ? ShadowDrawable.createFromResourceId(right) : null; + bottomDrawable = bottom != 0 ? ShadowDrawable.createFromResourceId(bottom) : null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CompoundDrawables that = (CompoundDrawables) o; + + if (getBottom() != that.getBottom()) return false; + if (getLeft() != that.getLeft()) return false; + if (getRight() != that.getRight()) return false; + if (getTop() != that.getTop()) return false; + + return true; + } + + @Override + public int hashCode() { + int result = getLeft(); + result = 31 * result + getTop(); + result = 31 * result + getRight(); + result = 31 * result + getBottom(); + return result; + } + + @Override + public String toString() { + return "CompoundDrawables{" + + "left=" + getLeft() + + ", top=" + getTop() + + ", right=" + getRight() + + ", bottom=" + getBottom() + + '}'; + } + + public int getLeft() { + return shadowOf(leftDrawable).getLoadedFromResourceId(); + } + + public int getTop() { + return shadowOf(topDrawable).getLoadedFromResourceId(); + } + + public int getRight() { + return shadowOf(rightDrawable).getLoadedFromResourceId(); + } + + public int getBottom() { + return shadowOf(bottomDrawable).getLoadedFromResourceId(); + } + } +} |