public static void format(Editable text) { // Here, "root" means the position of "'": // 0'3, 0'90, and +81'-90 // (dash will be deleted soon, so it is actually +81'90). int rootIndex = 1; int length = text.length(); if (length > 3 && text.subSequence(0, 3).toString().equals("+81")) { rootIndex = 3; } else if (length < 1 || text.charAt(0) != '0') { return; } CharSequence saved = text.subSequence(0, length); // Strip the dashes first, as we're going to add them back int i = 0; while (i < text.length()) { if (text.charAt(i) == '-') { text.delete(i, i + 1); } else { i++; } } length = text.length(); int dashposition; i = rootIndex; int base = 0; while (i < length) { char ch = text.charAt(i); if (!Character.isDigit(ch)) { text.replace(0, length, saved); return; } short value = FORMAT_MAP[base + ch - '0']; if (value < 0) { if (value <= -100) { text.replace(0, length, saved); return; } int dashPos2 = rootIndex + (Math.abs(value) % 10); if (length > dashPos2) { text.insert(dashPos2, "-"); } int dashPos1 = rootIndex + (Math.abs(value) / 10); if (length > dashPos1) { text.insert(dashPos1, "-"); } break; } else { base = value; i++; } } if (length > 3 && rootIndex == 3) { text.insert(rootIndex, "-"); } }
@Override protected void replaceText(CharSequence text) { clearComposingText(); SpannableStringBuilder ssb = buildSpannableForText(text); TokenImageSpan tokenSpan = buildSpanForObject(selectedObject); Editable editable = getText(); int end = getSelectionEnd(); int start = tokenizer.findTokenStart(editable, end); if (start < prefix.length()) { start = prefix.length(); } String original = TextUtils.substring(editable, start, end); if (editable != null) { if (tokenSpan == null) { editable.replace(start, end, " "); } else if (!allowDuplicates && objects.contains(tokenSpan.getToken())) { editable.replace(start, end, " "); } else { QwertyKeyListener.markAsReplaced(editable, start, end, original); editable.replace(start, end, ssb); editable.setSpan( tokenSpan, start, start + ssb.length() - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } }
@Override public void afterTextChanged(Editable s) { String mask = mMask; String value = s.toString(); if (value.equals(mResult)) return; try { /* prepare the formatter*/ MaskedFormatter formatter = new MaskedFormatter(mask); formatter.setValueContainsLiteralCharacters(false); formatter.setPlaceholderCharacter( (char) 1); /* get a string with applied mask and placeholder chars*/ value = formatter.valueToString(value); try { /* find first placeholder*/ value = value.substring(0, value.indexOf((char) 1)); /*process a mask char*/ if (value.charAt(value.length() - 1) == mask.charAt(value.length() - 1)) value = value.substring(0, value.length() - 1); } catch (Exception e) { } mResult = value; s.replace(0, s.length(), value); } catch (ParseException e) { // the entered value does not match a mask int offset = e.getErrorOffset(); value = removeCharAt(value, offset); s.replace(0, s.length(), value); } }
/** * Replace {@link android.view.View.OnClickListener} with {@link * cl.monsoon.s1next.widget.TagHandler.ImageClickableSpan}. * * <p>See android.text.HtmlToSpannedConverter#startImg(android.text.SpannableStringBuilder, * org.xml.sax.Attributes, android.text.Html.ImageGetter) */ private void handleImg(boolean opening, Editable output) { if (!opening) { int end = output.length(); // \uFFFC: OBJECT REPLACEMENT CHARACTER int len = "\uFFFC".length(); ImageSpan imageSpan = output.getSpans(end - len, end, ImageSpan.class)[0]; String url = imageSpan.getSource(); // replace \uFFFC with ImageSpan's source // in order to support url copy when selected output.replace(end - len, end, url); // image from server doesn't have domain // skip this because we don't want to // make this image (emoticon or something // others) clickable if (URLUtil.isNetworkUrl(url)) { output.removeSpan(imageSpan); // make this ImageSpan clickable output.setSpan( new ImageClickableSpan(mContext, imageSpan.getDrawable(), url), end - len, output.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } }
private void submitItemAtPosition(int position) { User user = (User) getAdapter().getItem(position); if (user == null) { return; } clearComposingText(); int end = getSelectionEnd(); int start = mTokenizer.findTokenStart(getText(), end); Editable editable = getText(); QwertyKeyListener.markAsReplaced(editable, start, end, ""); CharSequence chip = createChip(user, false); if (chip != null && start >= 0 && end >= 0) { // TODO chip 사이에 새 칩을 넣을 때tokenizer가 // start를 end와 같은 위치로 잡음. 그래서 일단 start를 강제로 조절해놓음 start = end - chip.length(); editable.replace(start, end, chip); ((MemberSearchTextViewAdapter) getAdapter()).addExcludeIdxs(user.idx); } sanitizeBetween(); }
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); text.insert(prefix.length(), hintText); text.setSpan( hintSpan, prefix.length(), prefix.length() + getHint().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 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); text.removeSpan(hint); text.replace(sStart, sEnd, ""); hintVisible = false; } } }
/** * Update the mEditable state to reflect what Blink will do in response to the KeyDown for a * unicode-mapped key event. * * @param unicodeChar The Unicode character to update selection with. */ private void replaceSelectionWithUnicodeChar(int unicodeChar) { if (unicodeChar == 0) return; int selectionStart = Selection.getSelectionStart(mEditable); int selectionEnd = Selection.getSelectionEnd(mEditable); if (selectionStart > selectionEnd) { int temp = selectionStart; selectionStart = selectionEnd; selectionEnd = temp; } mEditable.replace(selectionStart, selectionEnd, Character.toString((char) unicodeChar)); updateSelectionIfRequired(); }
/** * Updates the AdapterInputConnection's internal representation of the text being edited and its * selection and composition properties. The resulting Editable is accessible through the * getEditable() method. If the text has not changed, this also calls updateSelection on the * InputMethodManager. * * @param text The String contents of the field being edited. * @param selectionStart The character offset of the selection start, or the caret position if * there is no selection. * @param selectionEnd The character offset of the selection end, or the caret position if there * is no selection. * @param compositionStart The character offset of the composition start, or -1 if there is no * composition. * @param compositionEnd The character offset of the composition end, or -1 if there is no * selection. * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript). */ @VisibleForTesting public void updateState( String text, int selectionStart, int selectionEnd, int compositionStart, int compositionEnd, boolean isNonImeChange) { if (DEBUG) { Log.w( TAG, "updateState [" + text + "] [" + selectionStart + " " + selectionEnd + "] [" + compositionStart + " " + compositionEnd + "] [" + isNonImeChange + "]"); } // If this update is from the IME, no further state modification is necessary because the // state should have been updated already by the IM framework directly. if (!isNonImeChange) return; // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces. text = text.replace('\u00A0', ' '); selectionStart = Math.min(selectionStart, text.length()); selectionEnd = Math.min(selectionEnd, text.length()); compositionStart = Math.min(compositionStart, text.length()); compositionEnd = Math.min(compositionEnd, text.length()); String prevText = mEditable.toString(); boolean textUnchanged = prevText.equals(text); if (!textUnchanged) { mEditable.replace(0, mEditable.length(), text); } Selection.setSelection(mEditable, selectionStart, selectionEnd); if (compositionStart == compositionEnd) { removeComposingSpans(mEditable); } else { super.setComposingRegion(compositionStart, compositionEnd); } updateSelectionIfRequired(); }
@DSComment("Private Method") @DSBan(DSCat.PRIVATE_METHOD) @DSGenerator( tool_name = "Doppelganger", tool_version = "2.0", generated_on = "2013-12-30 12:27:59.224 -0500", hash_original_method = "889637D7E351CCF8A657470FC2914F00", hash_generated_method = "36883B57129A6A258181D8CA0419954E") private void replaceCharacterAndClose(CharSequence replace) { int selEnd = Selection.getSelectionEnd(mText); if (mInsert || selEnd == 0) { mText.insert(selEnd, replace); } else { mText.replace(selEnd - 1, selEnd, replace); } dismiss(); }
public void onClearStyles() { if (DBG) { Log.d(LOG_TAG, "--- onClearStyles"); } Editable txt = mEST.getText(); int len = txt.length(); Object[] styles = txt.getSpans(0, len, Object.class); for (Object style : styles) { if (style instanceof ParagraphStyle || style instanceof QuoteSpan || style instanceof CharacterStyle) { if (style instanceof ImageSpan) { int start = txt.getSpanStart(style); int end = txt.getSpanEnd(style); txt.replace(start, end, ""); } txt.removeSpan(style); } } mEST.setBackgroundDrawable(mEST.mDefaultBackground); mEST.mBackgroundColor = DEFAULT_BACKGROUND_COLOR; }
private void replaceText(CharSequence text, int newCursorPosition, boolean composing) { if (DEBUG) { Log.d( LOGTAG, String.format("IME: replaceText(\"%s\", %d, %b)", text, newCursorPosition, composing)); } if (text == null) text = ""; final Editable content = getEditable(); if (content == null) { return; } beginBatchEdit(); // delete composing text set previously. int a = getComposingSpanStart(content); int b = getComposingSpanEnd(content); if (DEBUG) Log.d(LOGTAG, "Composing span: " + a + " to " + b); if (b < a) { int tmp = a; a = b; b = tmp; } if (a != -1 && b != -1) { removeComposingSpans(content); } else { clampSelection(); a = Selection.getSelectionStart(content); b = Selection.getSelectionEnd(content); } if (composing) { Spannable sp = null; if (!(text instanceof Spannable)) { sp = new SpannableStringBuilder(text); text = sp; // Underline the active composition string. sp.setSpan( new UnderlineSpan(), 0, sp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING); } else { sp = (Spannable) text; } setComposingSpans(sp); } if (DEBUG) Log.d( LOGTAG, "Replacing from " + a + " to " + b + " with \"" + text + "\", composing=" + composing + ", type=" + text.getClass().getCanonicalName()); if (DEBUG) { LogPrinter lp = new LogPrinter(Log.VERBOSE, LOGTAG); lp.println("Current text:"); TextUtils.dumpSpans(content, lp, " "); lp.println("Composing text:"); TextUtils.dumpSpans(text, lp, " "); } // Position the cursor appropriately, so that after replacing the // desired range of text it will be located in the correct spot. // This allows us to deal with filters performing edits on the text // we are providing here. if (newCursorPosition > 0) { newCursorPosition += b - 1; } else { newCursorPosition += a; } if (newCursorPosition < 0) newCursorPosition = 0; if (newCursorPosition > content.length()) newCursorPosition = content.length(); Selection.setSelection(content, newCursorPosition); content.replace(a, b, text); if (DEBUG) { LogPrinter lp = new LogPrinter(Log.VERBOSE, LOGTAG); lp.println("Final text:"); TextUtils.dumpSpans(content, lp, " "); } endBatchEdit(); }
public void setEditable(String contents) { mEditable.removeSpan(this); mEditable.replace(0, mEditable.length(), contents); mEditable.setSpan(this, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); Selection.setSelection(mEditable, contents.length()); }
public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { int selStart, selEnd; int pref = 0; if (view != null) { pref = TextKeyListener.getInstance().getPrefs(view.getContext()); } { int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); selStart = Math.min(a, b); selEnd = Math.max(a, b); } int activeStart = content.getSpanStart(TextKeyListener.ACTIVE); int activeEnd = content.getSpanEnd(TextKeyListener.ACTIVE); // now for the multitap cases... // Try to increment the character we were working on before // if we have one and it's still the same key. int rec = (content.getSpanFlags(TextKeyListener.ACTIVE) & Spannable.SPAN_USER) >>> Spannable.SPAN_USER_SHIFT; if (activeStart == selStart && activeEnd == selEnd && selEnd - selStart == 1 && rec >= 0 && rec < sRecs.size()) { if (keyCode == KeyEvent.KEYCODE_STAR) { char current = content.charAt(selStart); if (Character.isLowerCase(current)) { content.replace(selStart, selEnd, String.valueOf(current).toUpperCase()); removeTimeouts(content); new Timeout(content); // for its side effects return true; } if (Character.isUpperCase(current)) { content.replace(selStart, selEnd, String.valueOf(current).toLowerCase()); removeTimeouts(content); new Timeout(content); // for its side effects return true; } } if (sRecs.indexOfKey(keyCode) == rec) { String val = sRecs.valueAt(rec); char ch = content.charAt(selStart); int ix = val.indexOf(ch); if (ix >= 0) { ix = (ix + 1) % (val.length()); content.replace(selStart, selEnd, val, ix, ix + 1); removeTimeouts(content); new Timeout(content); // for its side effects return true; } } // Is this key one we know about at all? If so, acknowledge // that the selection is our fault but the key has changed // or the text no longer matches, so move the selection over // so that it inserts instead of replaces. rec = sRecs.indexOfKey(keyCode); if (rec >= 0) { Selection.setSelection(content, selEnd, selEnd); selStart = selEnd; } } else { rec = sRecs.indexOfKey(keyCode); } if (rec >= 0) { // We have a valid key. Replace the selection or insertion point // with the first character for that key, and remember what // record it came from for next time. String val = sRecs.valueAt(rec); int off = 0; if ((pref & TextKeyListener.AUTO_CAP) != 0 && TextKeyListener.shouldCap(mCapitalize, content, selStart)) { for (int i = 0; i < val.length(); i++) { if (Character.isUpperCase(val.charAt(i))) { off = i; break; } } } if (selStart != selEnd) { Selection.setSelection(content, selEnd); } content.setSpan(OLD_SEL_START, selStart, selStart, Spannable.SPAN_MARK_MARK); content.replace(selStart, selEnd, val, off, off + 1); int oldStart = content.getSpanStart(OLD_SEL_START); selEnd = Selection.getSelectionEnd(content); if (selEnd != oldStart) { Selection.setSelection(content, oldStart, selEnd); content.setSpan( TextKeyListener.LAST_TYPED, oldStart, selEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); content.setSpan( TextKeyListener.ACTIVE, oldStart, selEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | (rec << Spannable.SPAN_USER_SHIFT)); } removeTimeouts(content); new Timeout(content); // for its side effects // Set up the callback so we can remove the timeout if the // cursor moves. if (content.getSpanStart(this) < 0) { KeyListener[] methods = content.getSpans(0, content.length(), KeyListener.class); for (Object method : methods) { content.removeSpan(method); } content.setSpan(this, 0, content.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); } return true; } return super.onKeyDown(view, content, keyCode, event); }