Loading library/TokenAutoComplete/src/main/java/com/tokenautocomplete/HintSpan.javadeleted 100644 → 0 +0 −16 Original line number Diff line number Diff line package com.tokenautocomplete; import android.content.res.ColorStateList; import android.text.style.TextAppearanceSpan; /** * Subclass of TextAppearanceSpan just to work with how Spans get detected * * Created on 2/3/15. * @author mgod */ class HintSpan extends TextAppearanceSpan { HintSpan(String family, int style, int size, ColorStateList color, ColorStateList linkColor) { super(family, style, size, color, linkColor); } } library/TokenAutoComplete/src/main/java/com/tokenautocomplete/SpanUtils.java +1 −8 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ public class SpanUtils { } @Nullable public static Spanned ellipsizeWithSpans(@Nullable CharSequence prefix, @Nullable CountSpan countSpan, public static Spanned ellipsizeWithSpans(@Nullable CountSpan countSpan, int tokenCount, @NonNull TextPaint paint, @NonNull CharSequence originalText, float maxWidth) { Loading @@ -40,13 +40,6 @@ public class SpanUtils { TextUtils.copySpansFrom((Spanned)tempEllipsized, 0, tempEllipsized.length(), Object.class, ellipsized, 0); } if (prefix != null && prefix.length() > ellipsizeCallback.start) { //We ellipsized part of the prefix, so put it back ellipsized.replace(0, ellipsizeCallback.start, prefix); ellipsizeCallback.end = ellipsizeCallback.end + prefix.length() - ellipsizeCallback.start; ellipsizeCallback.start = prefix.length(); } if (ellipsizeCallback.start != ellipsizeCallback.end) { if (countSpan != null) { Loading library/TokenAutoComplete/src/main/java/com/tokenautocomplete/TokenCompleteTextView.java +31 −209 Original line number Diff line number Diff line package com.tokenautocomplete; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Rect; import android.graphics.Typeface; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; Loading @@ -18,12 +16,10 @@ import android.text.NoCopySpan; import android.text.Selection; import android.text.SpanWatcher; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; Loading Loading @@ -67,8 +63,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText private TokenTextWatcher textWatcher; private CountSpan countSpan; private @Nullable SpannableStringBuilder hiddenContent; private CharSequence prefix = ""; private boolean hintVisible = false; private Layout lastLayout = null; private boolean initialized = false; private boolean performBestGuess = true; Loading Loading @@ -161,22 +155,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } } //We need to not do anything when we would delete the prefix if (destinationStart < prefix.length()) { //when setText is called, which should only be called during restoring, //destinationStart and destinationEnd are 0. If not checked, it will clear out //the prefix. //This is why we need to return null in this if condition to preserve state. if (destinationStart == 0 && destinationEnd == 0) { return null; } else if (destinationEnd <= prefix.length()) { //Don't do anything return prefix.subSequence(destinationStart, destinationEnd); } else { //Delete everything up to the prefix return prefix.subSequence(destinationStart, prefix.length()); } } return null; } }}); Loading Loading @@ -238,53 +216,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText return true; } /** * A String of text that is shown before all the tokens inside the EditText * (Think "To: " in an email address field. I would advise against this: use a label and a hint. * * @param p String with the hint */ public void setPrefix(CharSequence p) { //Have to clear and set the actual text before saving the prefix to avoid the prefix filter CharSequence prevPrefix = prefix; prefix = p; Editable text = getText(); if (text != null) { internalEditInProgress = true; if (prevPrefix != null) { text.replace(0, prevPrefix.length(), p); } else { text.insert(0, p); } internalEditInProgress = false; } //prefix = p; updateHint(); } /** * <p>You can get a color integer either using * {@link androidx.core.content.ContextCompat#getColor(android.content.Context, int)} * or with {@link android.graphics.Color#parseColor(String)}.</p> * <p>{@link android.graphics.Color#parseColor(String)} * accepts these formats (copied from android.graphics.Color): * You can use: '#RRGGBB', '#AARRGGBB' * or one of the following names: 'red', 'blue', 'green', 'black', 'white', * 'gray', 'cyan', 'magenta', 'yellow', 'lightgray', 'darkgray', 'grey', * 'lightgrey', 'darkgrey', 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', * 'olive', 'purple', 'silver', 'teal'.</p> * * @param prefix prefix * @param color A single color value in the form 0xAARRGGBB. */ @SuppressWarnings("SameParameterValue") public void setPrefix(CharSequence prefix, int color) { SpannableString spannablePrefix = new SpannableString(prefix); spannablePrefix.setSpan(new ForegroundColorSpan(color), 0, spannablePrefix.length(), 0); setPrefix(spannablePrefix); } /** * Get the list of Tokens * Loading Loading @@ -463,15 +394,11 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText private Range getCurrentCandidateTokenRange() { Editable editable = getText(); int cursorEndPosition = getSelectionEnd(); int candidateStringStart = prefix.length(); int candidateStringStart = 0; int candidateStringEnd = editable.length(); if (hintVisible) { //Don't try to search the hint for possible tokenizable strings candidateStringEnd = candidateStringStart; } //We want to find the largest string that contains the selection end that is not already tokenized TokenImageSpan[] spans = editable.getSpans(prefix.length(), editable.length(), TokenImageSpan.class); TokenImageSpan[] spans = editable.getSpans(0, editable.length(), TokenImageSpan.class); for (TokenImageSpan span : spans) { int spanEnd = editable.getSpanEnd(span); if (candidateStringStart < spanEnd && cursorEndPosition >= spanEnd) { Loading Loading @@ -504,8 +431,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } protected String currentCompletionText() { if (hintVisible) return ""; //Can't have any text if the hint is visible Editable editable = getText(); Range currentRange = getCurrentCandidateTokenRange(); Loading Loading @@ -541,7 +466,7 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @Override public boolean enoughToFilter() { if (tokenizer == null || hintVisible) { if (tokenizer == null) { return false; } Loading Loading @@ -667,17 +592,9 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @Override protected void onSelectionChanged(int selStart, int selEnd) { if (hintVisible) { //Don't let users select the hint selStart = 0; } //Never let users select text selEnd = selStart; if (prefix != null && (selStart < prefix.length() || selEnd < prefix.length())) { //Don't let users select the prefix setSelection(prefix.length()); } else { Editable text = getText(); if (text != null) { //Make sure if we are in a span, we select the spot 1 space after the span end Loading @@ -697,7 +614,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText super.onSelectionChanged(selStart, selEnd); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { Loading @@ -722,7 +638,7 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText text.removeSpan(spanWatcher); CountSpan temp = preventFreeFormText ? countSpan : null; Spanned ellipsized = SpanUtils.ellipsizeWithSpans(prefix, temp, getObjects().size(), Spanned ellipsized = SpanUtils.ellipsizeWithSpans(temp, getObjects().size(), lastLayout.getPaint(), text, maxTextWidth()); if (ellipsized != null) { Loading @@ -744,16 +660,12 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText TokenImageSpan.class, getText(), 0); hiddenContent = null; if (hintVisible) { setSelection(prefix.length()); } else { post(new Runnable() { @Override public void run() { setSelection(getText().length()); } }); } TokenSpanWatcher[] watchers = getText().getSpans(0, getText().length(), TokenSpanWatcher.class); if (watchers.length == 0) { Loading Loading @@ -997,18 +909,14 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText if (hiddenContent == null) { internalEditInProgress = true; int offset = editable.length(); //There might be a hint visible... if (hintVisible) { //...so we need to put the object in in front of the hint offset = prefix.length(); } else { Range currentRange = getCurrentCandidateTokenRange(); if (currentRange.length() > 0) { // The user has entered some text that has not yet been tokenized. // Find the beginning of this text and insert the new token there. offset = currentRange.start; } } editable.insert(offset, ssb); editable.insert(offset + ssb.length(), " "); editable.setSpan(tokenSpan, offset, offset + ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Loading @@ -1023,63 +931,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } } private void updateHint() { Editable text = getText(); CharSequence hintText = getHint(); if (text == null || hintText == null) { return; } //Show hint if we need to if (prefix.length() > 0) { HintSpan[] hints = text.getSpans(0, text.length(), HintSpan.class); HintSpan hint = null; int testLength = prefix.length(); if (hints.length > 0) { hint = hints[0]; testLength += text.getSpanEnd(hint) - text.getSpanStart(hint); } if (text.length() == testLength) { hintVisible = true; if (hint != null) { return;//hint already visible } //We need to display the hint manually Typeface tf = getTypeface(); int style = Typeface.NORMAL; if (tf != null) { style = tf.getStyle(); } ColorStateList colors = getHintTextColors(); HintSpan hintSpan = new HintSpan(null, style, (int) getTextSize(), colors, colors); internalEditInProgress = true; text.insert(prefix.length(), hintText); text.setSpan(hintSpan, prefix.length(), prefix.length() + getHint().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); internalEditInProgress = false; setSelection(prefix.length()); } else { if (hint == null) { return; //hint already removed } //Remove the hint. There should only ever be one int sStart = text.getSpanStart(hint); int sEnd = text.getSpanEnd(hint); internalEditInProgress = true; text.removeSpan(hint); text.replace(sStart, sEnd, ""); internalEditInProgress = false; hintVisible = false; } } } protected class TokenImageSpan extends ViewSpan implements NoCopySpan { private T token; Loading Loading @@ -1181,8 +1032,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } } updateHint(); } @Override Loading Loading @@ -1243,7 +1092,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText savingState = false; SavedState state = new SavedState(superState); state.prefix = prefix; state.allowCollapse = allowCollapse; state.performBestGuess = performBestGuess; state.preventFreeFormText = preventFreeFormText; Loading Loading @@ -1281,11 +1129,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); internalEditInProgress = true; setText(ss.prefix); prefix = ss.prefix; internalEditInProgress = false; updateHint(); allowCollapse = ss.allowCollapse; performBestGuess = ss.performBestGuess; preventFreeFormText = ss.preventFreeFormText; Loading Loading @@ -1322,7 +1165,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText private static class SavedState extends BaseSavedState { static final String SERIALIZABLE_PLACEHOLDER = "Serializable"; CharSequence prefix; boolean allowCollapse; boolean performBestGuess; boolean preventFreeFormText; Loading @@ -1334,7 +1176,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @SuppressWarnings("unchecked") SavedState(Parcel in) { super(in); prefix = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); allowCollapse = in.readInt() != 0; performBestGuess = in.readInt() != 0; preventFreeFormText = in.readInt() != 0; Loading Loading @@ -1367,7 +1208,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @Override public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); TextUtils.writeToParcel(prefix, out, 0); out.writeInt(allowCollapse ? 1 : 0); out.writeInt(performBestGuess ? 1 : 0); out.writeInt(preventFreeFormText ? 1 : 0); Loading Loading @@ -1460,27 +1300,9 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText // Shouldn't be able to delete any text with tokens that are not removable if (!canDeleteSelection(beforeLength)) return false; //Shouldn't be able to delete prefix, so don't do anything if (getSelectionStart() <= prefix.length()) { beforeLength = 0; return super.deleteSurroundingText(beforeLength, afterLength); } return super.deleteSurroundingText(beforeLength, afterLength); } @Override public boolean setComposingRegion(int start, int end) { //The hint is displayed inline as regular text, but we want to disable normal compose //functionality on it, so if we attempt to set a composing region on the hint, set the //composing region to have length of 0, which indicates there is no composing region //Without this, on many software keyboards, the first word of the hint will be underlined if (hintVisible) { start = end = 0; } return super.setComposingRegion(start, end); } @Override public boolean setComposingText(CharSequence text, int newCursorPosition) { //There's an issue with some keyboards where they will try to insert the first word Loading Loading
library/TokenAutoComplete/src/main/java/com/tokenautocomplete/HintSpan.javadeleted 100644 → 0 +0 −16 Original line number Diff line number Diff line package com.tokenautocomplete; import android.content.res.ColorStateList; import android.text.style.TextAppearanceSpan; /** * Subclass of TextAppearanceSpan just to work with how Spans get detected * * Created on 2/3/15. * @author mgod */ class HintSpan extends TextAppearanceSpan { HintSpan(String family, int style, int size, ColorStateList color, ColorStateList linkColor) { super(family, style, size, color, linkColor); } }
library/TokenAutoComplete/src/main/java/com/tokenautocomplete/SpanUtils.java +1 −8 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ public class SpanUtils { } @Nullable public static Spanned ellipsizeWithSpans(@Nullable CharSequence prefix, @Nullable CountSpan countSpan, public static Spanned ellipsizeWithSpans(@Nullable CountSpan countSpan, int tokenCount, @NonNull TextPaint paint, @NonNull CharSequence originalText, float maxWidth) { Loading @@ -40,13 +40,6 @@ public class SpanUtils { TextUtils.copySpansFrom((Spanned)tempEllipsized, 0, tempEllipsized.length(), Object.class, ellipsized, 0); } if (prefix != null && prefix.length() > ellipsizeCallback.start) { //We ellipsized part of the prefix, so put it back ellipsized.replace(0, ellipsizeCallback.start, prefix); ellipsizeCallback.end = ellipsizeCallback.end + prefix.length() - ellipsizeCallback.start; ellipsizeCallback.start = prefix.length(); } if (ellipsizeCallback.start != ellipsizeCallback.end) { if (countSpan != null) { Loading
library/TokenAutoComplete/src/main/java/com/tokenautocomplete/TokenCompleteTextView.java +31 −209 Original line number Diff line number Diff line package com.tokenautocomplete; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Rect; import android.graphics.Typeface; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; Loading @@ -18,12 +16,10 @@ import android.text.NoCopySpan; import android.text.Selection; import android.text.SpanWatcher; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; Loading Loading @@ -67,8 +63,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText private TokenTextWatcher textWatcher; private CountSpan countSpan; private @Nullable SpannableStringBuilder hiddenContent; private CharSequence prefix = ""; private boolean hintVisible = false; private Layout lastLayout = null; private boolean initialized = false; private boolean performBestGuess = true; Loading Loading @@ -161,22 +155,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } } //We need to not do anything when we would delete the prefix if (destinationStart < prefix.length()) { //when setText is called, which should only be called during restoring, //destinationStart and destinationEnd are 0. If not checked, it will clear out //the prefix. //This is why we need to return null in this if condition to preserve state. if (destinationStart == 0 && destinationEnd == 0) { return null; } else if (destinationEnd <= prefix.length()) { //Don't do anything return prefix.subSequence(destinationStart, destinationEnd); } else { //Delete everything up to the prefix return prefix.subSequence(destinationStart, prefix.length()); } } return null; } }}); Loading Loading @@ -238,53 +216,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText return true; } /** * A String of text that is shown before all the tokens inside the EditText * (Think "To: " in an email address field. I would advise against this: use a label and a hint. * * @param p String with the hint */ public void setPrefix(CharSequence p) { //Have to clear and set the actual text before saving the prefix to avoid the prefix filter CharSequence prevPrefix = prefix; prefix = p; Editable text = getText(); if (text != null) { internalEditInProgress = true; if (prevPrefix != null) { text.replace(0, prevPrefix.length(), p); } else { text.insert(0, p); } internalEditInProgress = false; } //prefix = p; updateHint(); } /** * <p>You can get a color integer either using * {@link androidx.core.content.ContextCompat#getColor(android.content.Context, int)} * or with {@link android.graphics.Color#parseColor(String)}.</p> * <p>{@link android.graphics.Color#parseColor(String)} * accepts these formats (copied from android.graphics.Color): * You can use: '#RRGGBB', '#AARRGGBB' * or one of the following names: 'red', 'blue', 'green', 'black', 'white', * 'gray', 'cyan', 'magenta', 'yellow', 'lightgray', 'darkgray', 'grey', * 'lightgrey', 'darkgrey', 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', * 'olive', 'purple', 'silver', 'teal'.</p> * * @param prefix prefix * @param color A single color value in the form 0xAARRGGBB. */ @SuppressWarnings("SameParameterValue") public void setPrefix(CharSequence prefix, int color) { SpannableString spannablePrefix = new SpannableString(prefix); spannablePrefix.setSpan(new ForegroundColorSpan(color), 0, spannablePrefix.length(), 0); setPrefix(spannablePrefix); } /** * Get the list of Tokens * Loading Loading @@ -463,15 +394,11 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText private Range getCurrentCandidateTokenRange() { Editable editable = getText(); int cursorEndPosition = getSelectionEnd(); int candidateStringStart = prefix.length(); int candidateStringStart = 0; int candidateStringEnd = editable.length(); if (hintVisible) { //Don't try to search the hint for possible tokenizable strings candidateStringEnd = candidateStringStart; } //We want to find the largest string that contains the selection end that is not already tokenized TokenImageSpan[] spans = editable.getSpans(prefix.length(), editable.length(), TokenImageSpan.class); TokenImageSpan[] spans = editable.getSpans(0, editable.length(), TokenImageSpan.class); for (TokenImageSpan span : spans) { int spanEnd = editable.getSpanEnd(span); if (candidateStringStart < spanEnd && cursorEndPosition >= spanEnd) { Loading Loading @@ -504,8 +431,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } protected String currentCompletionText() { if (hintVisible) return ""; //Can't have any text if the hint is visible Editable editable = getText(); Range currentRange = getCurrentCandidateTokenRange(); Loading Loading @@ -541,7 +466,7 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @Override public boolean enoughToFilter() { if (tokenizer == null || hintVisible) { if (tokenizer == null) { return false; } Loading Loading @@ -667,17 +592,9 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @Override protected void onSelectionChanged(int selStart, int selEnd) { if (hintVisible) { //Don't let users select the hint selStart = 0; } //Never let users select text selEnd = selStart; if (prefix != null && (selStart < prefix.length() || selEnd < prefix.length())) { //Don't let users select the prefix setSelection(prefix.length()); } else { Editable text = getText(); if (text != null) { //Make sure if we are in a span, we select the spot 1 space after the span end Loading @@ -697,7 +614,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText super.onSelectionChanged(selStart, selEnd); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { Loading @@ -722,7 +638,7 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText text.removeSpan(spanWatcher); CountSpan temp = preventFreeFormText ? countSpan : null; Spanned ellipsized = SpanUtils.ellipsizeWithSpans(prefix, temp, getObjects().size(), Spanned ellipsized = SpanUtils.ellipsizeWithSpans(temp, getObjects().size(), lastLayout.getPaint(), text, maxTextWidth()); if (ellipsized != null) { Loading @@ -744,16 +660,12 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText TokenImageSpan.class, getText(), 0); hiddenContent = null; if (hintVisible) { setSelection(prefix.length()); } else { post(new Runnable() { @Override public void run() { setSelection(getText().length()); } }); } TokenSpanWatcher[] watchers = getText().getSpans(0, getText().length(), TokenSpanWatcher.class); if (watchers.length == 0) { Loading Loading @@ -997,18 +909,14 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText if (hiddenContent == null) { internalEditInProgress = true; int offset = editable.length(); //There might be a hint visible... if (hintVisible) { //...so we need to put the object in in front of the hint offset = prefix.length(); } else { Range currentRange = getCurrentCandidateTokenRange(); if (currentRange.length() > 0) { // The user has entered some text that has not yet been tokenized. // Find the beginning of this text and insert the new token there. offset = currentRange.start; } } editable.insert(offset, ssb); editable.insert(offset + ssb.length(), " "); editable.setSpan(tokenSpan, offset, offset + ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Loading @@ -1023,63 +931,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } } private void updateHint() { Editable text = getText(); CharSequence hintText = getHint(); if (text == null || hintText == null) { return; } //Show hint if we need to if (prefix.length() > 0) { HintSpan[] hints = text.getSpans(0, text.length(), HintSpan.class); HintSpan hint = null; int testLength = prefix.length(); if (hints.length > 0) { hint = hints[0]; testLength += text.getSpanEnd(hint) - text.getSpanStart(hint); } if (text.length() == testLength) { hintVisible = true; if (hint != null) { return;//hint already visible } //We need to display the hint manually Typeface tf = getTypeface(); int style = Typeface.NORMAL; if (tf != null) { style = tf.getStyle(); } ColorStateList colors = getHintTextColors(); HintSpan hintSpan = new HintSpan(null, style, (int) getTextSize(), colors, colors); internalEditInProgress = true; text.insert(prefix.length(), hintText); text.setSpan(hintSpan, prefix.length(), prefix.length() + getHint().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); internalEditInProgress = false; setSelection(prefix.length()); } else { if (hint == null) { return; //hint already removed } //Remove the hint. There should only ever be one int sStart = text.getSpanStart(hint); int sEnd = text.getSpanEnd(hint); internalEditInProgress = true; text.removeSpan(hint); text.replace(sStart, sEnd, ""); internalEditInProgress = false; hintVisible = false; } } } protected class TokenImageSpan extends ViewSpan implements NoCopySpan { private T token; Loading Loading @@ -1181,8 +1032,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText } } updateHint(); } @Override Loading Loading @@ -1243,7 +1092,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText savingState = false; SavedState state = new SavedState(superState); state.prefix = prefix; state.allowCollapse = allowCollapse; state.performBestGuess = performBestGuess; state.preventFreeFormText = preventFreeFormText; Loading Loading @@ -1281,11 +1129,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); internalEditInProgress = true; setText(ss.prefix); prefix = ss.prefix; internalEditInProgress = false; updateHint(); allowCollapse = ss.allowCollapse; performBestGuess = ss.performBestGuess; preventFreeFormText = ss.preventFreeFormText; Loading Loading @@ -1322,7 +1165,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText private static class SavedState extends BaseSavedState { static final String SERIALIZABLE_PLACEHOLDER = "Serializable"; CharSequence prefix; boolean allowCollapse; boolean performBestGuess; boolean preventFreeFormText; Loading @@ -1334,7 +1176,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @SuppressWarnings("unchecked") SavedState(Parcel in) { super(in); prefix = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); allowCollapse = in.readInt() != 0; performBestGuess = in.readInt() != 0; preventFreeFormText = in.readInt() != 0; Loading Loading @@ -1367,7 +1208,6 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText @Override public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); TextUtils.writeToParcel(prefix, out, 0); out.writeInt(allowCollapse ? 1 : 0); out.writeInt(performBestGuess ? 1 : 0); out.writeInt(preventFreeFormText ? 1 : 0); Loading Loading @@ -1460,27 +1300,9 @@ public abstract class TokenCompleteTextView<T> extends AppCompatAutoCompleteText // Shouldn't be able to delete any text with tokens that are not removable if (!canDeleteSelection(beforeLength)) return false; //Shouldn't be able to delete prefix, so don't do anything if (getSelectionStart() <= prefix.length()) { beforeLength = 0; return super.deleteSurroundingText(beforeLength, afterLength); } return super.deleteSurroundingText(beforeLength, afterLength); } @Override public boolean setComposingRegion(int start, int end) { //The hint is displayed inline as regular text, but we want to disable normal compose //functionality on it, so if we attempt to set a composing region on the hint, set the //composing region to have length of 0, which indicates there is no composing region //Without this, on many software keyboards, the first word of the hint will be underlined if (hintVisible) { start = end = 0; } return super.setComposingRegion(start, end); } @Override public boolean setComposingText(CharSequence text, int newCursorPosition) { //There's an issue with some keyboards where they will try to insert the first word Loading