diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
| commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/text | |
| parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
| download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/text')
103 files changed, 0 insertions, 21819 deletions
diff --git a/core/java/android/text/AlteredCharSequence.java b/core/java/android/text/AlteredCharSequence.java deleted file mode 100644 index 4cc71fd..0000000 --- a/core/java/android/text/AlteredCharSequence.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -// XXX should this really be in the public API at all? -/** - * An AlteredCharSequence is a CharSequence that is largely mirrored from - * another CharSequence, except that a specified range of characters are - * mirrored from a different char array instead. - */ -public class AlteredCharSequence -implements CharSequence, GetChars -{ - /** - * Create an AlteredCharSequence whose text (and possibly spans) - * are mirrored from <code>source</code>, except that the range of - * offsets <code>substart</code> inclusive to <code>subend</code> exclusive - * are mirrored instead from <code>sub</code>, beginning at offset 0. - */ - public static AlteredCharSequence make(CharSequence source, char[] sub, - int substart, int subend) { - if (source instanceof Spanned) - return new AlteredSpanned(source, sub, substart, subend); - else - return new AlteredCharSequence(source, sub, substart, subend); - } - - private AlteredCharSequence(CharSequence source, char[] sub, - int substart, int subend) { - mSource = source; - mChars = sub; - mStart = substart; - mEnd = subend; - } - - /* package */ void update(char[] sub, int substart, int subend) { - mChars = sub; - mStart = substart; - mEnd = subend; - } - - private static class AlteredSpanned - extends AlteredCharSequence - implements Spanned - { - private AlteredSpanned(CharSequence source, char[] sub, - int substart, int subend) { - super(source, sub, substart, subend); - mSpanned = (Spanned) source; - } - - public <T> T[] getSpans(int start, int end, Class<T> kind) { - return mSpanned.getSpans(start, end, kind); - } - - public int getSpanStart(Object span) { - return mSpanned.getSpanStart(span); - } - - public int getSpanEnd(Object span) { - return mSpanned.getSpanEnd(span); - } - - public int getSpanFlags(Object span) { - return mSpanned.getSpanFlags(span); - } - - public int nextSpanTransition(int start, int end, Class kind) { - return mSpanned.nextSpanTransition(start, end, kind); - } - - private Spanned mSpanned; - } - - public char charAt(int off) { - if (off >= mStart && off < mEnd) - return mChars[off - mStart]; - else - return mSource.charAt(off); - } - - public int length() { - return mSource.length(); - } - - public CharSequence subSequence(int start, int end) { - return AlteredCharSequence.make(mSource.subSequence(start, end), - mChars, mStart - start, mEnd - start); - } - - public void getChars(int start, int end, char[] dest, int off) { - TextUtils.getChars(mSource, start, end, dest, off); - - start = Math.max(mStart, start); - end = Math.min(mEnd, end); - - if (start > end) - System.arraycopy(mChars, start - mStart, dest, off, end - start); - } - - public String toString() { - int len = length(); - - char[] ret = new char[len]; - getChars(0, len, ret, 0); - return String.valueOf(ret); - } - - private int mStart; - private int mEnd; - private char[] mChars; - private CharSequence mSource; -} diff --git a/core/java/android/text/AndroidCharacter.java b/core/java/android/text/AndroidCharacter.java deleted file mode 100644 index 6dfd64d..0000000 --- a/core/java/android/text/AndroidCharacter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * AndroidCharacter exposes some character properties that are not - * easily accessed from java.lang.Character. - */ -public class AndroidCharacter -{ - /** - * Fill in the first <code>count</code> bytes of <code>dest</code> with the - * directionalities from the first <code>count</code> chars of <code>src</code>. - * This is just like Character.getDirectionality() except it is a - * batch operation. - */ - public native static void getDirectionalities(char[] src, byte[] dest, - int count); - /** - * Replace the specified slice of <code>text</code> with the chars' - * right-to-left mirrors (if any), returning true if any - * replacements were made. - */ - public native static boolean mirror(char[] text, int start, int count); - - /** - * Return the right-to-left mirror (or the original char if none) - * of the specified char. - */ - public native static char getMirror(char ch); -} diff --git a/core/java/android/text/Annotation.java b/core/java/android/text/Annotation.java deleted file mode 100644 index dbc290b..0000000 --- a/core/java/android/text/Annotation.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.os.Parcel; - -/** - * Annotations are simple key-value pairs that are preserved across - * TextView save/restore cycles and can be used to keep application-specific - * data that needs to be maintained for regions of text. - */ -public class Annotation implements ParcelableSpan { - private final String mKey; - private final String mValue; - - public Annotation(String key, String value) { - mKey = key; - mValue = value; - } - - public Annotation(Parcel src) { - mKey = src.readString(); - mValue = src.readString(); - } - - public int getSpanTypeId() { - return TextUtils.ANNOTATION; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mKey); - dest.writeString(mValue); - } - - public String getKey() { - return mKey; - } - - public String getValue() { - return mValue; - } -} diff --git a/core/java/android/text/AutoText.java b/core/java/android/text/AutoText.java deleted file mode 100644 index 508d740..0000000 --- a/core/java/android/text/AutoText.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.content.res.Resources; -import android.content.res.XmlResourceParser; -import com.android.internal.util.XmlUtils; -import android.view.View; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Locale; - -/** - * This class accesses a dictionary of corrections to frequent misspellings. - */ -public class AutoText { - // struct trie { - // char c; - // int off; - // struct trie *child; - // struct trie *next; - // }; - - private static final int TRIE_C = 0; - private static final int TRIE_OFF = 1; - private static final int TRIE_CHILD = 2; - private static final int TRIE_NEXT = 3; - - private static final int TRIE_SIZEOF = 4; - private static final char TRIE_NULL = (char) -1; - private static final int TRIE_ROOT = 0; - - private static final int INCREMENT = 1024; - - private static final int DEFAULT = 14337; // Size of the Trie 13 Aug 2007 - - private static final int RIGHT = 9300; // Size of 'right' 13 Aug 2007 - - private static AutoText sInstance = new AutoText(Resources.getSystem()); - private static Object sLock = new Object(); - - // TODO: - // - // Note the assumption that the destination strings total less than - // 64K characters and that the trie for the source side totals less - // than 64K chars/offsets/child pointers/next pointers. - // - // This seems very safe for English (currently 7K of destination, - // 14K of trie) but may need to be revisited. - - private char[] mTrie; - private char mTrieUsed; - private String mText; - private Locale mLocale; - - private AutoText(Resources resources) { - mLocale = resources.getConfiguration().locale; - init(resources); - } - - /** - * Retrieves a possible spelling correction for the specified range - * of text. Returns null if no correction can be found. - * The View is used to get the current Locale and Resources. - */ - public static String get(CharSequence src, final int start, final int end, - View view) { - Resources res = view.getContext().getResources(); - Locale locale = res.getConfiguration().locale; - AutoText instance; - - synchronized (sLock) { - instance = sInstance; - - if (!locale.equals(instance.mLocale)) { - instance = new AutoText(res); - sInstance = instance; - } - } - - return instance.lookup(src, start, end); - } - - private String lookup(CharSequence src, final int start, final int end) { - int here = mTrie[TRIE_ROOT]; - - for (int i = start; i < end; i++) { - char c = src.charAt(i); - - for (; here != TRIE_NULL; here = mTrie[here + TRIE_NEXT]) { - if (c == mTrie[here + TRIE_C]) { - if ((i == end - 1) - && (mTrie[here + TRIE_OFF] != TRIE_NULL)) { - int off = mTrie[here + TRIE_OFF]; - int len = mText.charAt(off); - - return mText.substring(off + 1, off + 1 + len); - } - - here = mTrie[here + TRIE_CHILD]; - break; - } - } - - if (here == TRIE_NULL) { - return null; - } - } - - return null; - } - - private void init(Resources r) { - XmlResourceParser parser = r.getXml(com.android.internal.R.xml.autotext); - - StringBuilder right = new StringBuilder(RIGHT); - mTrie = new char[DEFAULT]; - mTrie[TRIE_ROOT] = TRIE_NULL; - mTrieUsed = TRIE_ROOT + 1; - - try { - XmlUtils.beginDocument(parser, "words"); - String odest = ""; - char ooff = 0; - - while (true) { - XmlUtils.nextElement(parser); - - String element = parser.getName(); - if (element == null || !(element.equals("word"))) { - break; - } - - String src = parser.getAttributeValue(null, "src"); - if (parser.next() == XmlPullParser.TEXT) { - String dest = parser.getText(); - char off; - - if (dest.equals(odest)) { - off = ooff; - } else { - off = (char) right.length(); - right.append((char) dest.length()); - right.append(dest); - } - - add(src, off); - } - } - - // Don't let Resources cache a copy of all these strings. - r.flushLayoutCache(); - } catch (XmlPullParserException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - parser.close(); - } - - mText = right.toString(); - } - - private void add(String src, char off) { - int slen = src.length(); - int herep = TRIE_ROOT; - - for (int i = 0; i < slen; i++) { - char c = src.charAt(i); - boolean found = false; - - for (; mTrie[herep] != TRIE_NULL; - herep = mTrie[herep] + TRIE_NEXT) { - if (c == mTrie[mTrie[herep] + TRIE_C]) { - // There is a node for this letter, and this is the - // end, so fill in the right hand side fields. - - if (i == slen - 1) { - mTrie[mTrie[herep] + TRIE_OFF] = off; - return; - } - - // There is a node for this letter, and we need - // to go deeper into it to fill in the rest. - - herep = mTrie[herep] + TRIE_CHILD; - found = true; - break; - } - } - - if (!found) { - // No node for this letter yet. Make one. - - char node = newTrieNode(); - mTrie[herep] = node; - - mTrie[mTrie[herep] + TRIE_C] = c; - mTrie[mTrie[herep] + TRIE_OFF] = TRIE_NULL; - mTrie[mTrie[herep] + TRIE_NEXT] = TRIE_NULL; - mTrie[mTrie[herep] + TRIE_CHILD] = TRIE_NULL; - - // If this is the end of the word, fill in the offset. - - if (i == slen - 1) { - mTrie[mTrie[herep] + TRIE_OFF] = off; - return; - } - - // Otherwise, step in deeper and go to the next letter. - - herep = mTrie[herep] + TRIE_CHILD; - } - } - } - - private char newTrieNode() { - if (mTrieUsed + TRIE_SIZEOF > mTrie.length) { - char[] copy = new char[mTrie.length + INCREMENT]; - System.arraycopy(mTrie, 0, copy, 0, mTrie.length); - mTrie = copy; - } - - char ret = mTrieUsed; - mTrieUsed += TRIE_SIZEOF; - - return ret; - } -} diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java deleted file mode 100644 index 843754b..0000000 --- a/core/java/android/text/BoringLayout.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.util.FloatMath; - -/** - * A BoringLayout is a very simple Layout implementation for text that - * fits on a single line and is all left-to-right characters. - * You will probably never want to make one of these yourself; - * if you do, be sure to call {@link #isBoring} first to make sure - * the text meets the criteria. - * <p>This class is used by widgets to control text layout. You should not need - * to use this class directly unless you are implementing your own widget - * or custom display object, in which case - * you are encouraged to use a Layout instead of calling - * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) - * Canvas.drawText()} directly.</p> - */ -public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback { - public static BoringLayout make(CharSequence source, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, boolean includepad) { - return new BoringLayout(source, paint, outerwidth, align, - spacingmult, spacingadd, metrics, - includepad); - } - - public static BoringLayout make(CharSequence source, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { - return new BoringLayout(source, paint, outerwidth, align, - spacingmult, spacingadd, metrics, - includepad, ellipsize, ellipsizedWidth); - } - - /** - * Returns a BoringLayout for the specified text, potentially reusing - * this one if it is already suitable. The caller must make sure that - * no one is still using this Layout. - */ - public BoringLayout replaceOrMake(CharSequence source, TextPaint paint, - int outerwidth, Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, - boolean includepad) { - replaceWith(source, paint, outerwidth, align, spacingmult, - spacingadd); - - mEllipsizedWidth = outerwidth; - mEllipsizedStart = 0; - mEllipsizedCount = 0; - - init(source, paint, outerwidth, align, spacingmult, spacingadd, - metrics, includepad, true); - return this; - } - - /** - * Returns a BoringLayout for the specified text, potentially reusing - * this one if it is already suitable. The caller must make sure that - * no one is still using this Layout. - */ - public BoringLayout replaceOrMake(CharSequence source, TextPaint paint, - int outerwidth, Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, - boolean includepad, - TextUtils.TruncateAt ellipsize, - int ellipsizedWidth) { - boolean trust; - - if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) { - replaceWith(source, paint, outerwidth, align, spacingmult, - spacingadd); - - mEllipsizedWidth = outerwidth; - mEllipsizedStart = 0; - mEllipsizedCount = 0; - trust = true; - } else { - replaceWith(TextUtils.ellipsize(source, paint, ellipsizedWidth, - ellipsize, true, this), - paint, outerwidth, align, spacingmult, - spacingadd); - - mEllipsizedWidth = ellipsizedWidth; - trust = false; - } - - init(getText(), paint, outerwidth, align, spacingmult, spacingadd, - metrics, includepad, trust); - return this; - } - - public BoringLayout(CharSequence source, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, boolean includepad) { - super(source, paint, outerwidth, align, spacingmult, spacingadd); - - mEllipsizedWidth = outerwidth; - mEllipsizedStart = 0; - mEllipsizedCount = 0; - - init(source, paint, outerwidth, align, spacingmult, spacingadd, - metrics, includepad, true); - } - - public BoringLayout(CharSequence source, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { - /* - * It is silly to have to call super() and then replaceWith(), - * but we can't use "this" for the callback until the call to - * super() finishes. - */ - super(source, paint, outerwidth, align, spacingmult, spacingadd); - - boolean trust; - - if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) { - mEllipsizedWidth = outerwidth; - mEllipsizedStart = 0; - mEllipsizedCount = 0; - trust = true; - } else { - replaceWith(TextUtils.ellipsize(source, paint, ellipsizedWidth, - ellipsize, true, this), - paint, outerwidth, align, spacingmult, - spacingadd); - - - mEllipsizedWidth = ellipsizedWidth; - trust = false; - } - - init(getText(), paint, outerwidth, align, spacingmult, spacingadd, - metrics, includepad, trust); - } - - /* package */ void init(CharSequence source, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - BoringLayout.Metrics metrics, boolean includepad, - boolean trustWidth) { - int spacing; - - if (source instanceof String && align == Layout.Alignment.ALIGN_NORMAL) { - mDirect = source.toString(); - } else { - mDirect = null; - } - - mPaint = paint; - - if (includepad) { - spacing = metrics.bottom - metrics.top; - } else { - spacing = metrics.descent - metrics.ascent; - } - - if (spacingmult != 1 || spacingadd != 0) { - spacing = (int)(spacing * spacingmult + spacingadd + 0.5f); - } - - mBottom = spacing; - - if (includepad) { - mDesc = spacing + metrics.top; - } else { - mDesc = spacing + metrics.ascent; - } - - if (trustWidth) { - mMax = metrics.width; - } else { - /* - * If we have ellipsized, we have to actually calculate the - * width because the width that was passed in was for the - * full text, not the ellipsized form. - */ - synchronized (sTemp) { - mMax = (int) (FloatMath.ceil(Styled.measureText(paint, sTemp, - source, 0, source.length(), - null))); - } - } - - if (includepad) { - mTopPadding = metrics.top - metrics.ascent; - mBottomPadding = metrics.bottom - metrics.descent; - } - } - - /** - * Returns null if not boring; the width, ascent, and descent if boring. - */ - public static Metrics isBoring(CharSequence text, - TextPaint paint) { - return isBoring(text, paint, null); - } - - /** - * Returns null if not boring; the width, ascent, and descent in the - * provided Metrics object (or a new one if the provided one was null) - * if boring. - */ - public static Metrics isBoring(CharSequence text, TextPaint paint, - Metrics metrics) { - char[] temp = TextUtils.obtain(500); - int len = text.length(); - boolean boring = true; - - outer: - for (int i = 0; i < len; i += 500) { - int j = i + 500; - - if (j > len) - j = len; - - TextUtils.getChars(text, i, j, temp, 0); - - int n = j - i; - - for (int a = 0; a < n; a++) { - char c = temp[a]; - - if (c == '\n' || c == '\t' || c >= FIRST_RIGHT_TO_LEFT) { - boring = false; - break outer; - } - } - } - - TextUtils.recycle(temp); - - if (boring) { - Metrics fm = metrics; - if (fm == null) { - fm = new Metrics(); - } - - int wid; - - synchronized (sTemp) { - wid = (int) (FloatMath.ceil(Styled.measureText(paint, sTemp, - text, 0, text.length(), fm))); - } - fm.width = wid; - return fm; - } else { - return null; - } - } - - @Override public int getHeight() { - return mBottom; - } - - @Override public int getLineCount() { - return 1; - } - - @Override public int getLineTop(int line) { - if (line == 0) - return 0; - else - return mBottom; - } - - @Override public int getLineDescent(int line) { - return mDesc; - } - - @Override public int getLineStart(int line) { - if (line == 0) - return 0; - else - return getText().length(); - } - - @Override public int getParagraphDirection(int line) { - return DIR_LEFT_TO_RIGHT; - } - - @Override public boolean getLineContainsTab(int line) { - return false; - } - - @Override public float getLineMax(int line) { - return mMax; - } - - @Override public final Directions getLineDirections(int line) { - return Layout.DIRS_ALL_LEFT_TO_RIGHT; - } - - public int getTopPadding() { - return mTopPadding; - } - - public int getBottomPadding() { - return mBottomPadding; - } - - @Override - public int getEllipsisCount(int line) { - return mEllipsizedCount; - } - - @Override - public int getEllipsisStart(int line) { - return mEllipsizedStart; - } - - @Override - public int getEllipsizedWidth() { - return mEllipsizedWidth; - } - - // Override draw so it will be faster. - @Override - public void draw(Canvas c, Path highlight, Paint highlightpaint, - int cursorOffset) { - if (mDirect != null && highlight == null) { - c.drawText(mDirect, 0, mBottom - mDesc, mPaint); - } else { - super.draw(c, highlight, highlightpaint, cursorOffset); - } - } - - /** - * Callback for the ellipsizer to report what region it ellipsized. - */ - public void ellipsized(int start, int end) { - mEllipsizedStart = start; - mEllipsizedCount = end - start; - } - - private static final char FIRST_RIGHT_TO_LEFT = '\u0590'; - - private String mDirect; - private Paint mPaint; - - /* package */ int mBottom, mDesc; // for Direct - private int mTopPadding, mBottomPadding; - private float mMax; - private int mEllipsizedWidth, mEllipsizedStart, mEllipsizedCount; - - private static final TextPaint sTemp = - new TextPaint(); - - public static class Metrics extends Paint.FontMetricsInt { - public int width; - - @Override public String toString() { - return super.toString() + " width=" + width; - } - } -} diff --git a/core/java/android/text/ClipboardManager.java b/core/java/android/text/ClipboardManager.java deleted file mode 100644 index 52039af..0000000 --- a/core/java/android/text/ClipboardManager.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.content.Context; -import android.os.RemoteException; -import android.os.Handler; -import android.os.IBinder; -import android.os.ServiceManager; -import android.util.Log; - -/** - * Interface to the clipboard service, for placing and retrieving text in - * the global clipboard. - * - * <p> - * You do not instantiate this class directly; instead, retrieve it through - * {@link android.content.Context#getSystemService}. - * - * @see android.content.Context#getSystemService - */ -public class ClipboardManager { - private static IClipboard sService; - - private Context mContext; - - static private IClipboard getService() { - if (sService != null) { - return sService; - } - IBinder b = ServiceManager.getService("clipboard"); - sService = IClipboard.Stub.asInterface(b); - return sService; - } - - /** {@hide} */ - public ClipboardManager(Context context, Handler handler) { - mContext = context; - } - - /** - * Returns the text on the clipboard. It will eventually be possible - * to store types other than text too, in which case this will return - * null if the type cannot be coerced to text. - */ - public CharSequence getText() { - try { - return getService().getClipboardText(); - } catch (RemoteException e) { - return null; - } - } - - /** - * Sets the contents of the clipboard to the specified text. - */ - public void setText(CharSequence text) { - try { - getService().setClipboardText(text); - } catch (RemoteException e) { - } - } - - /** - * Returns true if the clipboard contains text; false otherwise. - */ - public boolean hasText() { - try { - return getService().hasClipboardText(); - } catch (RemoteException e) { - return false; - } - } -} diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java deleted file mode 100644 index 14e5655..0000000 --- a/core/java/android/text/DynamicLayout.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Paint; -import android.text.style.UpdateLayout; -import android.text.style.WrapTogetherSpan; - -import java.lang.ref.WeakReference; - -/** - * DynamicLayout is a text layout that updates itself as the text is edited. - * <p>This is used by widgets to control text layout. You should not need - * to use this class directly unless you are implementing your own widget - * or custom display object, or need to call - * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) - * Canvas.drawText()} directly.</p> - */ -public class DynamicLayout -extends Layout -{ - private static final int PRIORITY = 128; - - /** - * Make a layout for the specified text that will be updated as - * the text is changed. - */ - public DynamicLayout(CharSequence base, - TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd, - boolean includepad) { - this(base, base, paint, width, align, spacingmult, spacingadd, - includepad); - } - - /** - * Make a layout for the transformed text (password transformation - * being the primary example of a transformation) - * that will be updated as the base text is changed. - */ - public DynamicLayout(CharSequence base, CharSequence display, - TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd, - boolean includepad) { - this(base, display, paint, width, align, spacingmult, spacingadd, - includepad, null, 0); - } - - /** - * Make a layout for the transformed text (password transformation - * being the primary example of a transformation) - * that will be updated as the base text is changed. - * If ellipsize is non-null, the Layout will ellipsize the text - * down to ellipsizedWidth. - */ - public DynamicLayout(CharSequence base, CharSequence display, - TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd, - boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { - super((ellipsize == null) - ? display - : (display instanceof Spanned) - ? new SpannedEllipsizer(display) - : new Ellipsizer(display), - paint, width, align, spacingmult, spacingadd); - - mBase = base; - mDisplay = display; - - if (ellipsize != null) { - mInts = new PackedIntVector(COLUMNS_ELLIPSIZE); - mEllipsizedWidth = ellipsizedWidth; - mEllipsizeAt = ellipsize; - } else { - mInts = new PackedIntVector(COLUMNS_NORMAL); - mEllipsizedWidth = width; - mEllipsizeAt = ellipsize; - } - - mObjects = new PackedObjectVector<Directions>(1); - - mIncludePad = includepad; - - /* - * This is annoying, but we can't refer to the layout until - * superclass construction is finished, and the superclass - * constructor wants the reference to the display text. - * - * This will break if the superclass constructor ever actually - * cares about the content instead of just holding the reference. - */ - if (ellipsize != null) { - Ellipsizer e = (Ellipsizer) getText(); - - e.mLayout = this; - e.mWidth = ellipsizedWidth; - e.mMethod = ellipsize; - mEllipsize = true; - } - - // Initial state is a single line with 0 characters (0 to 0), - // with top at 0 and bottom at whatever is natural, and - // undefined ellipsis. - - int[] start; - - if (ellipsize != null) { - start = new int[COLUMNS_ELLIPSIZE]; - start[ELLIPSIS_START] = ELLIPSIS_UNDEFINED; - } else { - start = new int[COLUMNS_NORMAL]; - } - - Directions[] dirs = new Directions[] { DIRS_ALL_LEFT_TO_RIGHT }; - - Paint.FontMetricsInt fm = paint.getFontMetricsInt(); - int asc = fm.ascent; - int desc = fm.descent; - - start[DIR] = DIR_LEFT_TO_RIGHT << DIR_SHIFT; - start[TOP] = 0; - start[DESCENT] = desc; - mInts.insertAt(0, start); - - start[TOP] = desc - asc; - mInts.insertAt(1, start); - - mObjects.insertAt(0, dirs); - - // Update from 0 characters to whatever the real text is - - reflow(base, 0, 0, base.length()); - - if (base instanceof Spannable) { - if (mWatcher == null) - mWatcher = new ChangeWatcher(this); - - // Strip out any watchers for other DynamicLayouts. - Spannable sp = (Spannable) base; - ChangeWatcher[] spans = sp.getSpans(0, sp.length(), ChangeWatcher.class); - for (int i = 0; i < spans.length; i++) - sp.removeSpan(spans[i]); - - sp.setSpan(mWatcher, 0, base.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE | - (PRIORITY << Spannable.SPAN_PRIORITY_SHIFT)); - } - } - - private void reflow(CharSequence s, int where, int before, int after) { - if (s != mBase) - return; - - CharSequence text = mDisplay; - int len = text.length(); - - // seek back to the start of the paragraph - - int find = TextUtils.lastIndexOf(text, '\n', where - 1); - if (find < 0) - find = 0; - else - find = find + 1; - - { - int diff = where - find; - before += diff; - after += diff; - where -= diff; - } - - // seek forward to the end of the paragraph - - int look = TextUtils.indexOf(text, '\n', where + after); - if (look < 0) - look = len; - else - look++; // we want the index after the \n - - int change = look - (where + after); - before += change; - after += change; - - // seek further out to cover anything that is forced to wrap together - - if (text instanceof Spanned) { - Spanned sp = (Spanned) text; - boolean again; - - do { - again = false; - - Object[] force = sp.getSpans(where, where + after, - WrapTogetherSpan.class); - - for (int i = 0; i < force.length; i++) { - int st = sp.getSpanStart(force[i]); - int en = sp.getSpanEnd(force[i]); - - if (st < where) { - again = true; - - int diff = where - st; - before += diff; - after += diff; - where -= diff; - } - - if (en > where + after) { - again = true; - - int diff = en - (where + after); - before += diff; - after += diff; - } - } - } while (again); - } - - // find affected region of old layout - - int startline = getLineForOffset(where); - int startv = getLineTop(startline); - - int endline = getLineForOffset(where + before); - if (where + after == len) - endline = getLineCount(); - int endv = getLineTop(endline); - boolean islast = (endline == getLineCount()); - - // generate new layout for affected text - - StaticLayout reflowed; - - synchronized (sLock) { - reflowed = sStaticLayout; - sStaticLayout = null; - } - - if (reflowed == null) - reflowed = new StaticLayout(true); - - reflowed.generate(text, where, where + after, - getPaint(), getWidth(), getAlignment(), - getSpacingMultiplier(), getSpacingAdd(), - false, true, mEllipsize, - mEllipsizedWidth, mEllipsizeAt); - int n = reflowed.getLineCount(); - - // If the new layout has a blank line at the end, but it is not - // the very end of the buffer, then we already have a line that - // starts there, so disregard the blank line. - - if (where + after != len && - reflowed.getLineStart(n - 1) == where + after) - n--; - - // remove affected lines from old layout - - mInts.deleteAt(startline, endline - startline); - mObjects.deleteAt(startline, endline - startline); - - // adjust offsets in layout for new height and offsets - - int ht = reflowed.getLineTop(n); - int toppad = 0, botpad = 0; - - if (mIncludePad && startline == 0) { - toppad = reflowed.getTopPadding(); - mTopPadding = toppad; - ht -= toppad; - } - if (mIncludePad && islast) { - botpad = reflowed.getBottomPadding(); - mBottomPadding = botpad; - ht += botpad; - } - - mInts.adjustValuesBelow(startline, START, after - before); - mInts.adjustValuesBelow(startline, TOP, startv - endv + ht); - - // insert new layout - - int[] ints; - - if (mEllipsize) { - ints = new int[COLUMNS_ELLIPSIZE]; - ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED; - } else { - ints = new int[COLUMNS_NORMAL]; - } - - Directions[] objects = new Directions[1]; - - - for (int i = 0; i < n; i++) { - ints[START] = reflowed.getLineStart(i) | - (reflowed.getParagraphDirection(i) << DIR_SHIFT) | - (reflowed.getLineContainsTab(i) ? TAB_MASK : 0); - - int top = reflowed.getLineTop(i) + startv; - if (i > 0) - top -= toppad; - ints[TOP] = top; - - int desc = reflowed.getLineDescent(i); - if (i == n - 1) - desc += botpad; - - ints[DESCENT] = desc; - objects[0] = reflowed.getLineDirections(i); - - if (mEllipsize) { - ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i); - ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i); - } - - mInts.insertAt(startline + i, ints); - mObjects.insertAt(startline + i, objects); - } - - synchronized (sLock) { - sStaticLayout = reflowed; - } - } - - private void dump(boolean show) { - int n = getLineCount(); - - for (int i = 0; i < n; i++) { - System.out.print("line " + i + ": " + getLineStart(i) + " to " + getLineEnd(i) + " "); - - if (show) { - System.out.print(getText().subSequence(getLineStart(i), - getLineEnd(i))); - } - - System.out.println(""); - } - - System.out.println(""); - } - - public int getLineCount() { - return mInts.size() - 1; - } - - public int getLineTop(int line) { - return mInts.getValue(line, TOP); - } - - public int getLineDescent(int line) { - return mInts.getValue(line, DESCENT); - } - - public int getLineStart(int line) { - return mInts.getValue(line, START) & START_MASK; - } - - public boolean getLineContainsTab(int line) { - return (mInts.getValue(line, TAB) & TAB_MASK) != 0; - } - - public int getParagraphDirection(int line) { - return mInts.getValue(line, DIR) >> DIR_SHIFT; - } - - public final Directions getLineDirections(int line) { - return mObjects.getValue(line, 0); - } - - public int getTopPadding() { - return mTopPadding; - } - - public int getBottomPadding() { - return mBottomPadding; - } - - @Override - public int getEllipsizedWidth() { - return mEllipsizedWidth; - } - - private static class ChangeWatcher - implements TextWatcher, SpanWatcher - { - public ChangeWatcher(DynamicLayout layout) { - mLayout = new WeakReference(layout); - } - - private void reflow(CharSequence s, int where, int before, int after) { - DynamicLayout ml = (DynamicLayout) mLayout.get(); - - if (ml != null) - ml.reflow(s, where, before, after); - else if (s instanceof Spannable) - ((Spannable) s).removeSpan(this); - } - - public void beforeTextChanged(CharSequence s, - int where, int before, int after) { - ; - } - - public void onTextChanged(CharSequence s, - int where, int before, int after) { - reflow(s, where, before, after); - } - - public void afterTextChanged(Editable s) { - ; - } - - public void onSpanAdded(Spannable s, Object o, int start, int end) { - if (o instanceof UpdateLayout) - reflow(s, start, end - start, end - start); - } - - public void onSpanRemoved(Spannable s, Object o, int start, int end) { - if (o instanceof UpdateLayout) - reflow(s, start, end - start, end - start); - } - - public void onSpanChanged(Spannable s, Object o, int start, int end, - int nstart, int nend) { - if (o instanceof UpdateLayout) { - reflow(s, start, end - start, end - start); - reflow(s, nstart, nend - nstart, nend - nstart); - } - } - - private WeakReference mLayout; - } - - public int getEllipsisStart(int line) { - if (mEllipsizeAt == null) { - return 0; - } - - return mInts.getValue(line, ELLIPSIS_START); - } - - public int getEllipsisCount(int line) { - if (mEllipsizeAt == null) { - return 0; - } - - return mInts.getValue(line, ELLIPSIS_COUNT); - } - - private CharSequence mBase; - private CharSequence mDisplay; - private ChangeWatcher mWatcher; - private boolean mIncludePad; - private boolean mEllipsize; - private int mEllipsizedWidth; - private TextUtils.TruncateAt mEllipsizeAt; - - private PackedIntVector mInts; - private PackedObjectVector<Directions> mObjects; - - private int mTopPadding, mBottomPadding; - - private static StaticLayout sStaticLayout = new StaticLayout(true); - private static Object sLock = new Object(); - - private static final int START = 0; - private static final int DIR = START; - private static final int TAB = START; - private static final int TOP = 1; - private static final int DESCENT = 2; - private static final int COLUMNS_NORMAL = 3; - - private static final int ELLIPSIS_START = 3; - private static final int ELLIPSIS_COUNT = 4; - private static final int COLUMNS_ELLIPSIZE = 5; - - private static final int START_MASK = 0x1FFFFFFF; - private static final int DIR_MASK = 0xC0000000; - private static final int DIR_SHIFT = 30; - private static final int TAB_MASK = 0x20000000; - - private static final int ELLIPSIS_UNDEFINED = 0x80000000; -} diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java deleted file mode 100644 index a284a00..0000000 --- a/core/java/android/text/Editable.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * This is the interface for text whose content and markup - * can be changed (as opposed - * to immutable text like Strings). If you make a {@link DynamicLayout} - * of an Editable, the layout will be reflowed as the text is changed. - */ -public interface Editable -extends CharSequence, GetChars, Spannable, Appendable -{ - /** - * Replaces the specified range (<code>st…en</code>) of text in this - * Editable with a copy of the slice <code>start…end</code> from - * <code>source</code>. The destination slice may be empty, in which case - * the operation is an insertion, or the source slice may be empty, - * in which case the operation is a deletion. - * <p> - * Before the change is committed, each filter that was set with - * {@link #setFilters} is given the opportunity to modify the - * <code>source</code> text. - * <p> - * If <code>source</code> - * is Spanned, the spans from it are preserved into the Editable. - * Existing spans within the Editable that entirely cover the replaced - * range are retained, but any that were strictly within the range - * that was replaced are removed. As a special case, the cursor - * position is preserved even when the entire range where it is - * located is replaced. - * @return a reference to this object. - */ - public Editable replace(int st, int en, CharSequence source, int start, int end); - - /** - * Convenience for replace(st, en, text, 0, text.length()) - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable replace(int st, int en, CharSequence text); - - /** - * Convenience for replace(where, where, text, start, end) - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable insert(int where, CharSequence text, int start, int end); - - /** - * Convenience for replace(where, where, text, 0, text.length()); - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable insert(int where, CharSequence text); - - /** - * Convenience for replace(st, en, "", 0, 0) - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable delete(int st, int en); - - /** - * Convenience for replace(length(), length(), text, 0, text.length()) - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable append(CharSequence text); - - /** - * Convenience for replace(length(), length(), text, start, end) - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable append(CharSequence text, int start, int end); - - /** - * Convenience for append(String.valueOf(text)). - * @see #replace(int, int, CharSequence, int, int) - */ - public Editable append(char text); - - /** - * Convenience for replace(0, length(), "", 0, 0) - * @see #replace(int, int, CharSequence, int, int) - * Note that this clears the text, not the spans; - * use {@link #clearSpans} if you need that. - */ - public void clear(); - - /** - * Removes all spans from the Editable, as if by calling - * {@link #removeSpan} on each of them. - */ - public void clearSpans(); - - /** - * Sets the series of filters that will be called in succession - * whenever the text of this Editable is changed, each of which has - * the opportunity to limit or transform the text that is being inserted. - */ - public void setFilters(InputFilter[] filters); - - /** - * Returns the array of input filters that are currently applied - * to changes to this Editable. - */ - public InputFilter[] getFilters(); - - /** - * Factory used by TextView to create new Editables. You can subclass - * it to provide something other than SpannableStringBuilder. - */ - public static class Factory { - private static Editable.Factory sInstance = new Editable.Factory(); - - /** - * Returns the standard Editable Factory. - */ - public static Editable.Factory getInstance() { - return sInstance; - } - - /** - * Returns a new SpannedStringBuilder from the specified - * CharSequence. You can override this to provide - * a different kind of Spanned. - */ - public Editable newEditable(CharSequence source) { - return new SpannableStringBuilder(source); - } - } -} diff --git a/core/java/android/text/GetChars.java b/core/java/android/text/GetChars.java deleted file mode 100644 index 348a911..0000000 --- a/core/java/android/text/GetChars.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * Please implement this interface if your CharSequence has a - * getChars() method like the one in String that is faster than - * calling charAt() multiple times. - */ -public interface GetChars -extends CharSequence -{ - /** - * Exactly like String.getChars(): copy chars <code>start</code> - * through <code>end - 1</code> from this CharSequence into <code>dest</code> - * beginning at offset <code>destoff</code>. - */ - public void getChars(int start, int end, char[] dest, int destoff); -} diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java deleted file mode 100644 index c3bd0ae..0000000 --- a/core/java/android/text/GraphicsOperations.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Canvas; -import android.graphics.Paint; - -/** - * Please implement this interface if your CharSequence can do quick - * draw/measure/widths calculations from an internal array. - * {@hide} - */ -public interface GraphicsOperations -extends CharSequence -{ - /** - * Just like {@link Canvas#drawText}. - */ - void drawText(Canvas c, int start, int end, - float x, float y, Paint p); - - /** - * Just like {@link Paint#measureText}. - */ - float measureText(int start, int end, Paint p); - - - /** - * Just like {@link Paint#getTextWidths}. - */ - public int getTextWidths(int start, int end, float[] widths, Paint p); -} diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java deleted file mode 100644 index 8495714..0000000 --- a/core/java/android/text/Html.java +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import org.ccil.cowan.tagsoup.HTMLSchema; -import org.ccil.cowan.tagsoup.Parser; -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.InputSource; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; - -import android.content.res.Resources; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.text.style.CharacterStyle; -import android.text.style.ForegroundColorSpan; -import android.text.style.ImageSpan; -import android.text.style.ParagraphStyle; -import android.text.style.QuoteSpan; -import android.text.style.RelativeSizeSpan; -import android.text.style.StrikethroughSpan; -import android.text.style.StyleSpan; -import android.text.style.SubscriptSpan; -import android.text.style.SuperscriptSpan; -import android.text.style.TypefaceSpan; -import android.text.style.URLSpan; -import android.text.style.UnderlineSpan; -import com.android.internal.util.XmlUtils; - -import java.io.IOException; -import java.io.StringReader; -import java.nio.CharBuffer; - -/** - * This class processes HTML strings into displayable styled text. - * Not all HTML tags are supported. - */ -public class Html { - /** - * Retrieves images for HTML <img> tags. - */ - public static interface ImageGetter { - /** - * This methos is called when the HTML parser encounters an - * <img> tag. The <code>source</code> argument is the - * string from the "src" attribute; the return value should be - * a Drawable representation of the image or <code>null</code> - * for a generic replacement image. Make sure you call - * setBounds() on your Drawable if it doesn't already have - * its bounds set. - */ - public Drawable getDrawable(String source); - } - - /** - * Is notified when HTML tags are encountered that the parser does - * not know how to interpret. - */ - public static interface TagHandler { - /** - * This method will be called whenn the HTML parser encounters - * a tag that it does not know how to interpret. - */ - public void handleTag(boolean opening, String tag, - Editable output, XMLReader xmlReader); - } - - private Html() { } - - /** - * Returns displayable styled text from the provided HTML string. - * Any <img> tags in the HTML will display as a generic - * replacement image which your program can then go through and - * replace with real images. - * - * <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild. - */ - public static Spanned fromHtml(String source) { - return fromHtml(source, null, null); - } - - /** - * Lazy initialization holder for HTML parser. This class will - * a) be preloaded by the zygote, or b) not loaded until absolutely - * necessary. - */ - private static class HtmlParser { - private static final HTMLSchema schema = new HTMLSchema(); - } - - /** - * Returns displayable styled text from the provided HTML string. - * Any <img> tags in the HTML will use the specified ImageGetter - * to request a representation of the image (use null if you don't - * want this) and the specified TagHandler to handle unknown tags - * (specify null if you don't want this). - * - * <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild. - */ - public static Spanned fromHtml(String source, ImageGetter imageGetter, - TagHandler tagHandler) { - Parser parser = new Parser(); - try { - parser.setProperty(Parser.schemaProperty, HtmlParser.schema); - } catch (org.xml.sax.SAXNotRecognizedException e) { - // Should not happen. - throw new RuntimeException(e); - } catch (org.xml.sax.SAXNotSupportedException e) { - // Should not happen. - throw new RuntimeException(e); - } - - HtmlToSpannedConverter converter = - new HtmlToSpannedConverter(source, imageGetter, tagHandler, - parser); - return converter.convert(); - } - - /** - * Returns an HTML representation of the provided Spanned text. - */ - public static String toHtml(Spanned text) { - StringBuilder out = new StringBuilder(); - int len = text.length(); - - int next; - for (int i = 0; i < text.length(); i = next) { - next = text.nextSpanTransition(i, len, QuoteSpan.class); - QuoteSpan[] quotes = text.getSpans(i, next, QuoteSpan.class); - - for (QuoteSpan quote: quotes) { - out.append("<blockquote>"); - } - - withinBlockquote(out, text, i, next); - - for (QuoteSpan quote: quotes) { - out.append("</blockquote>\n"); - } - } - - return out.toString(); - } - - private static void withinBlockquote(StringBuilder out, Spanned text, - int start, int end) { - out.append("<p>"); - - int next; - for (int i = start; i < end; i = next) { - next = TextUtils.indexOf(text, '\n', i, end); - if (next < 0) { - next = end; - } - - int nl = 0; - - while (next < end && text.charAt(next) == '\n') { - nl++; - next++; - } - - withinParagraph(out, text, i, next - nl, nl, next == end); - } - - out.append("</p>\n"); - } - - private static void withinParagraph(StringBuilder out, Spanned text, - int start, int end, int nl, - boolean last) { - int next; - for (int i = start; i < end; i = next) { - next = text.nextSpanTransition(i, end, CharacterStyle.class); - CharacterStyle[] style = text.getSpans(i, next, - CharacterStyle.class); - - for (int j = 0; j < style.length; j++) { - if (style[j] instanceof StyleSpan) { - int s = ((StyleSpan) style[j]).getStyle(); - - if ((s & Typeface.BOLD) != 0) { - out.append("<b>"); - } - if ((s & Typeface.ITALIC) != 0) { - out.append("<i>"); - } - } - if (style[j] instanceof TypefaceSpan) { - String s = ((TypefaceSpan) style[j]).getFamily(); - - if (s.equals("monospace")) { - out.append("<tt>"); - } - } - if (style[j] instanceof SuperscriptSpan) { - out.append("<sup>"); - } - if (style[j] instanceof SubscriptSpan) { - out.append("<sub>"); - } - if (style[j] instanceof UnderlineSpan) { - out.append("<u>"); - } - if (style[j] instanceof StrikethroughSpan) { - out.append("<strike>"); - } - if (style[j] instanceof URLSpan) { - out.append("<a href=\""); - out.append(((URLSpan) style[j]).getURL()); - out.append("\">"); - } - if (style[j] instanceof ImageSpan) { - out.append("<img src=\""); - out.append(((ImageSpan) style[j]).getSource()); - out.append("\">"); - - // Don't output the dummy character underlying the image. - i = next; - } - } - - withinStyle(out, text, i, next); - - for (int j = style.length - 1; j >= 0; j--) { - if (style[j] instanceof URLSpan) { - out.append("</a>"); - } - if (style[j] instanceof StrikethroughSpan) { - out.append("</strike>"); - } - if (style[j] instanceof UnderlineSpan) { - out.append("</u>"); - } - if (style[j] instanceof SubscriptSpan) { - out.append("</sub>"); - } - if (style[j] instanceof SuperscriptSpan) { - out.append("</sup>"); - } - if (style[j] instanceof TypefaceSpan) { - String s = ((TypefaceSpan) style[j]).getFamily(); - - if (s.equals("monospace")) { - out.append("</tt>"); - } - } - if (style[j] instanceof StyleSpan) { - int s = ((StyleSpan) style[j]).getStyle(); - - if ((s & Typeface.BOLD) != 0) { - out.append("</b>"); - } - if ((s & Typeface.ITALIC) != 0) { - out.append("</i>"); - } - } - } - } - - String p = last ? "" : "</p>\n<p>"; - - if (nl == 1) { - out.append("<br>\n"); - } else if (nl == 2) { - out.append(p); - } else { - for (int i = 2; i < nl; i++) { - out.append("<br>"); - } - - out.append(p); - } - } - - private static void withinStyle(StringBuilder out, Spanned text, - int start, int end) { - for (int i = start; i < end; i++) { - char c = text.charAt(i); - - if (c == '<') { - out.append("<"); - } else if (c == '>') { - out.append(">"); - } else if (c == '&') { - out.append("&"); - } else if (c > 0x7E || c < ' ') { - out.append("&#" + ((int) c) + ";"); - } else if (c == ' ') { - while (i + 1 < end && text.charAt(i + 1) == ' ') { - out.append(" "); - i++; - } - - out.append(' '); - } else { - out.append(c); - } - } - } -} - -class HtmlToSpannedConverter implements ContentHandler { - - private static final float[] HEADER_SIZES = { - 1.5f, 1.4f, 1.3f, 1.2f, 1.1f, 1f, - }; - - private String mSource; - private XMLReader mReader; - private SpannableStringBuilder mSpannableStringBuilder; - private Html.ImageGetter mImageGetter; - private Html.TagHandler mTagHandler; - - public HtmlToSpannedConverter( - String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler, - Parser parser) { - mSource = source; - mSpannableStringBuilder = new SpannableStringBuilder(); - mImageGetter = imageGetter; - mTagHandler = tagHandler; - mReader = parser; - } - - public Spanned convert() { - - mReader.setContentHandler(this); - try { - mReader.parse(new InputSource(new StringReader(mSource))); - } catch (IOException e) { - // We are reading from a string. There should not be IO problems. - throw new RuntimeException(e); - } catch (SAXException e) { - // TagSoup doesn't throw parse exceptions. - throw new RuntimeException(e); - } - - // Fix flags and range for paragraph-type markup. - Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class); - for (int i = 0; i < obj.length; i++) { - int start = mSpannableStringBuilder.getSpanStart(obj[i]); - int end = mSpannableStringBuilder.getSpanEnd(obj[i]); - - // If the last line of the range is blank, back off by one. - if (end - 2 >= 0) { - if (mSpannableStringBuilder.charAt(end - 1) == '\n' && - mSpannableStringBuilder.charAt(end - 2) == '\n') { - end--; - } - } - - if (end == start) { - mSpannableStringBuilder.removeSpan(obj[i]); - } else { - mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH); - } - } - - return mSpannableStringBuilder; - } - - private void handleStartTag(String tag, Attributes attributes) { - if (tag.equalsIgnoreCase("br")) { - // We don't need to handle this. TagSoup will ensure that there's a </br> for each <br> - // so we can safely emite the linebreaks when we handle the close tag. - } else if (tag.equalsIgnoreCase("p")) { - handleP(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("div")) { - handleP(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("em")) { - start(mSpannableStringBuilder, new Bold()); - } else if (tag.equalsIgnoreCase("b")) { - start(mSpannableStringBuilder, new Bold()); - } else if (tag.equalsIgnoreCase("strong")) { - start(mSpannableStringBuilder, new Italic()); - } else if (tag.equalsIgnoreCase("cite")) { - start(mSpannableStringBuilder, new Italic()); - } else if (tag.equalsIgnoreCase("dfn")) { - start(mSpannableStringBuilder, new Italic()); - } else if (tag.equalsIgnoreCase("i")) { - start(mSpannableStringBuilder, new Italic()); - } else if (tag.equalsIgnoreCase("big")) { - start(mSpannableStringBuilder, new Big()); - } else if (tag.equalsIgnoreCase("small")) { - start(mSpannableStringBuilder, new Small()); - } else if (tag.equalsIgnoreCase("font")) { - startFont(mSpannableStringBuilder, attributes); - } else if (tag.equalsIgnoreCase("blockquote")) { - handleP(mSpannableStringBuilder); - start(mSpannableStringBuilder, new Blockquote()); - } else if (tag.equalsIgnoreCase("tt")) { - start(mSpannableStringBuilder, new Monospace()); - } else if (tag.equalsIgnoreCase("a")) { - startA(mSpannableStringBuilder, attributes); - } else if (tag.equalsIgnoreCase("u")) { - start(mSpannableStringBuilder, new Underline()); - } else if (tag.equalsIgnoreCase("sup")) { - start(mSpannableStringBuilder, new Super()); - } else if (tag.equalsIgnoreCase("sub")) { - start(mSpannableStringBuilder, new Sub()); - } else if (tag.length() == 2 && - Character.toLowerCase(tag.charAt(0)) == 'h' && - tag.charAt(1) >= '1' && tag.charAt(1) <= '6') { - handleP(mSpannableStringBuilder); - start(mSpannableStringBuilder, new Header(tag.charAt(1) - '1')); - } else if (tag.equalsIgnoreCase("img")) { - startImg(mSpannableStringBuilder, attributes, mImageGetter); - } else if (mTagHandler != null) { - mTagHandler.handleTag(true, tag, mSpannableStringBuilder, mReader); - } - } - - private void handleEndTag(String tag) { - if (tag.equalsIgnoreCase("br")) { - handleBr(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("p")) { - handleP(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("div")) { - handleP(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("em")) { - end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD)); - } else if (tag.equalsIgnoreCase("b")) { - end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD)); - } else if (tag.equalsIgnoreCase("strong")) { - end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); - } else if (tag.equalsIgnoreCase("cite")) { - end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); - } else if (tag.equalsIgnoreCase("dfn")) { - end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); - } else if (tag.equalsIgnoreCase("i")) { - end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC)); - } else if (tag.equalsIgnoreCase("big")) { - end(mSpannableStringBuilder, Big.class, new RelativeSizeSpan(1.25f)); - } else if (tag.equalsIgnoreCase("small")) { - end(mSpannableStringBuilder, Small.class, new RelativeSizeSpan(0.8f)); - } else if (tag.equalsIgnoreCase("font")) { - endFont(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("blockquote")) { - handleP(mSpannableStringBuilder); - end(mSpannableStringBuilder, Blockquote.class, new QuoteSpan()); - } else if (tag.equalsIgnoreCase("tt")) { - end(mSpannableStringBuilder, Monospace.class, - new TypefaceSpan("monospace")); - } else if (tag.equalsIgnoreCase("a")) { - endA(mSpannableStringBuilder); - } else if (tag.equalsIgnoreCase("u")) { - end(mSpannableStringBuilder, Underline.class, new UnderlineSpan()); - } else if (tag.equalsIgnoreCase("sup")) { - end(mSpannableStringBuilder, Super.class, new SuperscriptSpan()); - } else if (tag.equalsIgnoreCase("sub")) { - end(mSpannableStringBuilder, Sub.class, new SubscriptSpan()); - } else if (tag.length() == 2 && - Character.toLowerCase(tag.charAt(0)) == 'h' && - tag.charAt(1) >= '1' && tag.charAt(1) <= '6') { - handleP(mSpannableStringBuilder); - endHeader(mSpannableStringBuilder); - } else if (mTagHandler != null) { - mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader); - } - } - - private static void handleP(SpannableStringBuilder text) { - int len = text.length(); - - if (len >= 1 && text.charAt(len - 1) == '\n') { - if (len >= 2 && text.charAt(len - 2) == '\n') { - return; - } - - text.append("\n"); - return; - } - - if (len != 0) { - text.append("\n\n"); - } - } - - private static void handleBr(SpannableStringBuilder text) { - text.append("\n"); - } - - private static Object getLast(Spanned text, Class kind) { - /* - * This knows that the last returned object from getSpans() - * will be the most recently added. - */ - Object[] objs = text.getSpans(0, text.length(), kind); - - if (objs.length == 0) { - return null; - } else { - return objs[objs.length - 1]; - } - } - - private static void start(SpannableStringBuilder text, Object mark) { - int len = text.length(); - text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK); - } - - private static void end(SpannableStringBuilder text, Class kind, - Object repl) { - int len = text.length(); - Object obj = getLast(text, kind); - int where = text.getSpanStart(obj); - - text.removeSpan(obj); - - if (where != len) { - text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - return; - } - - private static void startImg(SpannableStringBuilder text, - Attributes attributes, Html.ImageGetter img) { - String src = attributes.getValue("", "src"); - Drawable d = null; - - if (img != null) { - d = img.getDrawable(src); - } - - if (d == null) { - d = Resources.getSystem(). - getDrawable(com.android.internal.R.drawable.unknown_image); - d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); - } - - int len = text.length(); - text.append("\uFFFC"); - - text.setSpan(new ImageSpan(d, src), len, text.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - private static void startFont(SpannableStringBuilder text, - Attributes attributes) { - String color = attributes.getValue("", "color"); - String face = attributes.getValue("", "face"); - - int len = text.length(); - text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK); - } - - private static void endFont(SpannableStringBuilder text) { - int len = text.length(); - Object obj = getLast(text, Font.class); - int where = text.getSpanStart(obj); - - text.removeSpan(obj); - - if (where != len) { - Font f = (Font) obj; - - if (f.mColor != null) { - int c = -1; - - if (f.mColor.equalsIgnoreCase("aqua")) { - c = 0x00FFFF; - } else if (f.mColor.equalsIgnoreCase("black")) { - c = 0x000000; - } else if (f.mColor.equalsIgnoreCase("blue")) { - c = 0x0000FF; - } else if (f.mColor.equalsIgnoreCase("fuchsia")) { - c = 0xFF00FF; - } else if (f.mColor.equalsIgnoreCase("green")) { - c = 0x008000; - } else if (f.mColor.equalsIgnoreCase("grey")) { - c = 0x808080; - } else if (f.mColor.equalsIgnoreCase("lime")) { - c = 0x00FF00; - } else if (f.mColor.equalsIgnoreCase("maroon")) { - c = 0x800000; - } else if (f.mColor.equalsIgnoreCase("navy")) { - c = 0x000080; - } else if (f.mColor.equalsIgnoreCase("olive")) { - c = 0x808000; - } else if (f.mColor.equalsIgnoreCase("purple")) { - c = 0x800080; - } else if (f.mColor.equalsIgnoreCase("red")) { - c = 0xFF0000; - } else if (f.mColor.equalsIgnoreCase("silver")) { - c = 0xC0C0C0; - } else if (f.mColor.equalsIgnoreCase("teal")) { - c = 0x008080; - } else if (f.mColor.equalsIgnoreCase("white")) { - c = 0xFFFFFF; - } else if (f.mColor.equalsIgnoreCase("yellow")) { - c = 0xFFFF00; - } else { - try { - c = XmlUtils.convertValueToInt(f.mColor, -1); - } catch (NumberFormatException nfe) { - // Can't understand the color, so just drop it. - } - } - - if (c != -1) { - text.setSpan(new ForegroundColorSpan(c | 0xFF000000), - where, len, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - - if (f.mFace != null) { - text.setSpan(new TypefaceSpan(f.mFace), where, len, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - } - - private static void startA(SpannableStringBuilder text, Attributes attributes) { - String href = attributes.getValue("", "href"); - - int len = text.length(); - text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK); - } - - private static void endA(SpannableStringBuilder text) { - int len = text.length(); - Object obj = getLast(text, Href.class); - int where = text.getSpanStart(obj); - - text.removeSpan(obj); - - if (where != len) { - Href h = (Href) obj; - - if (h.mHref != null) { - text.setSpan(new URLSpan(h.mHref), where, len, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - } - - private static void endHeader(SpannableStringBuilder text) { - int len = text.length(); - Object obj = getLast(text, Header.class); - - int where = text.getSpanStart(obj); - - text.removeSpan(obj); - - // Back off not to change only the text, not the blank line. - while (len > where && text.charAt(len - 1) == '\n') { - len--; - } - - if (where != len) { - Header h = (Header) obj; - - text.setSpan(new RelativeSizeSpan(HEADER_SIZES[h.mLevel]), - where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - text.setSpan(new StyleSpan(Typeface.BOLD), - where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - - public void setDocumentLocator(Locator locator) { - } - - public void startDocument() throws SAXException { - } - - public void endDocument() throws SAXException { - } - - public void startPrefixMapping(String prefix, String uri) throws SAXException { - } - - public void endPrefixMapping(String prefix) throws SAXException { - } - - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - handleStartTag(localName, attributes); - } - - public void endElement(String uri, String localName, String qName) throws SAXException { - handleEndTag(localName); - } - - public void characters(char ch[], int start, int length) throws SAXException { - StringBuilder sb = new StringBuilder(); - - /* - * Ignore whitespace that immediately follows other whitespace; - * newlines count as spaces. - */ - - for (int i = 0; i < length; i++) { - char c = ch[i + start]; - - if (c == ' ' || c == '\n') { - char pred; - int len = sb.length(); - - if (len == 0) { - len = mSpannableStringBuilder.length(); - - if (len == 0) { - pred = '\n'; - } else { - pred = mSpannableStringBuilder.charAt(len - 1); - } - } else { - pred = sb.charAt(len - 1); - } - - if (pred != ' ' && pred != '\n') { - sb.append(' '); - } - } else { - sb.append(c); - } - } - - mSpannableStringBuilder.append(sb); - } - - public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { - } - - public void processingInstruction(String target, String data) throws SAXException { - } - - public void skippedEntity(String name) throws SAXException { - } - - private static class Bold { } - private static class Italic { } - private static class Underline { } - private static class Big { } - private static class Small { } - private static class Monospace { } - private static class Blockquote { } - private static class Super { } - private static class Sub { } - - private static class Font { - public String mColor; - public String mFace; - - public Font(String color, String face) { - mColor = color; - mFace = face; - } - } - - private static class Href { - public String mHref; - - public Href(String href) { - mHref = href; - } - } - - private static class Header { - private int mLevel; - - public Header(int level) { - mLevel = level; - } - } -} diff --git a/core/java/android/text/IClipboard.aidl b/core/java/android/text/IClipboard.aidl deleted file mode 100644 index 4deb5c8..0000000 --- a/core/java/android/text/IClipboard.aidl +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * Programming interface to the clipboard, which allows copying and pasting - * between applications. - * {@hide} - */ -interface IClipboard { - /** - * Returns the text on the clipboard. It will eventually be possible - * to store types other than text too, in which case this will return - * null if the type cannot be coerced to text. - */ - CharSequence getClipboardText(); - - /** - * Sets the contents of the clipboard to the specified text. - */ - void setClipboardText(CharSequence text); - - /** - * Returns true if the clipboard contains text; false otherwise. - */ - boolean hasClipboardText(); -} - diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java deleted file mode 100644 index 2f55677..0000000 --- a/core/java/android/text/InputFilter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * InputFilters can be attached to {@link Editable}s to constrain the - * changes that can be made to them. - */ -public interface InputFilter -{ - /** - * This method is called when the buffer is going to replace the - * range <code>dstart … dend</code> of <code>dest</code> - * with the new text from the range <code>start … end</code> - * of <code>source</code>. Return the CharSequence that you would - * like to have placed there instead, including an empty string - * if appropriate, or <code>null</code> to accept the original - * replacement. Be careful to not to reject 0-length replacements, - * as this is what happens when you delete text. Also beware that - * you should not attempt to make any changes to <code>dest</code> - * from this method; you may only examine it for context. - * - * Note: If <var>source</var> is an instance of {@link Spanned} or - * {@link Spannable}, the span objects in the <var>source</var> should be - * copied into the filtered result (i.e. the non-null return value). - * {@link TextUtils#copySpansFrom} can be used for convenience. - */ - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend); - - /** - * This filter will capitalize all the lower case letters that are added - * through edits. - */ - public static class AllCaps implements InputFilter { - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - for (int i = start; i < end; i++) { - if (Character.isLowerCase(source.charAt(i))) { - char[] v = new char[end - start]; - TextUtils.getChars(source, start, end, v, 0); - String s = new String(v).toUpperCase(); - - if (source instanceof Spanned) { - SpannableString sp = new SpannableString(s); - TextUtils.copySpansFrom((Spanned) source, - start, end, null, sp, 0); - return sp; - } else { - return s; - } - } - } - - return null; // keep original - } - } - - /** - * This filter will constrain edits not to make the length of the text - * greater than the specified length. - */ - public static class LengthFilter implements InputFilter { - public LengthFilter(int max) { - mMax = max; - } - - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - int keep = mMax - (dest.length() - (dend - dstart)); - - if (keep <= 0) { - return ""; - } else if (keep >= end - start) { - return null; // keep original - } else { - return source.subSequence(start, start + keep); - } - } - - private int mMax; - } -} diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java deleted file mode 100644 index a073cf4..0000000 --- a/core/java/android/text/InputType.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.text.TextUtils; - -/** - * Bit definitions for an integer defining the basic content type of text - * held in an {@link Editable} object. - */ -public interface InputType { - /** - * Mask of bits that determine the overall class - * of text being given. Currently supported classes are: - * {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER}, - * {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}. - * If the class is not one you - * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation - * or flags. - */ - public static final int TYPE_MASK_CLASS = 0x0000000f; - - /** - * Mask of bits that determine the variation of - * the base content class. - */ - public static final int TYPE_MASK_VARIATION = 0x00000ff0; - - /** - * Mask of bits that provide addition bit flags - * of options. - */ - public static final int TYPE_MASK_FLAGS = 0x00fff000; - - /** - * Special content type for when no explicit type has been specified. - * This should be interpreted to mean that the target input connection - * is not rich, it can not process and show things like candidate text nor - * retrieve the current text, so the input method will need to run in a - * limited "generate key events" mode. - */ - public static final int TYPE_NULL = 0x00000000; - - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - - /** - * Class for normal text. This class supports the following flags (only - * one of which should be set): - * {@link #TYPE_TEXT_FLAG_CAP_CHARACTERS}, - * {@link #TYPE_TEXT_FLAG_CAP_WORDS}, and. - * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. It also supports the - * following variations: - * {@link #TYPE_TEXT_VARIATION_NORMAL}, and - * {@link #TYPE_TEXT_VARIATION_URI}. If you do not recognize the - * variation, normal should be assumed. - */ - public static final int TYPE_CLASS_TEXT = 0x00000001; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides - * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and - * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. - */ - public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of - * all words. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This - * value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_WORDS}. - */ - public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of - * each sentence. This value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. - */ - public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form - * text that should have auto-correction applied to it. - */ - public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the text editor is performing - * auto-completion of the text being entered based on its own semantics, - * which it will present to the user as they type. This generally means - * that the input method should not be showing candidates itself, but can - * expect for the editor to supply its own completions/candidates from - * {@link android.view.inputmethod.InputMethodSession#displayCompletions - * InputMethodSession.displayCompletions()} as a result of the editor calling - * {@link android.view.inputmethod.InputMethodManager#displayCompletions - * InputMethodManager.displayCompletions()}. - */ - public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be - * entered into the field. If this flag is not set, the text field - * will be constrained to a single line. - */ - public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the regular text view associated - * with this should not be multi-line, but when a fullscreen input method - * is providing text it should use multiple lines if it can. - */ - public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000; - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: flags any text being used as a search string - */ - public static final int TYPE_TEXT_FLAG_SEARCH = 0x00080000; - - // ---------------------------------------------------------------------- - - /** - * Default variation of {@link #TYPE_CLASS_TEXT}: plain old normal text. - */ - public static final int TYPE_TEXT_VARIATION_NORMAL = 0x00000000; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a URI. - */ - public static final int TYPE_TEXT_VARIATION_URI = 0x00000010; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering an e-mail address. - */ - public static final int TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering the subject line of - * an e-mail. - */ - public static final int TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a short, possibly informal - * message such as an instant message or a text message. - */ - public static final int TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x00000040; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of a long, possibly - * formal message such as the body of an e-mail. - */ - public static final int TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x00000050; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person. - */ - public static final int TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000060; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing address. - */ - public static final int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000070; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a password. - */ - public static final int TYPE_TEXT_VARIATION_PASSWORD = 0x00000080; - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of a web form. - */ - public static final int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x00000090; - - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - - /** - * Class for numeric text. This class supports the following flag: - * {@link #TYPE_NUMBER_FLAG_SIGNED} and - * {@link #TYPE_NUMBER_FLAG_DECIMAL}. - */ - public static final int TYPE_CLASS_NUMBER = 0x00000002; - - /** - * Flag of {@link #TYPE_CLASS_NUMBER}: the number is signed, allowing - * a positive or negative sign at the start. - */ - public static final int TYPE_NUMBER_FLAG_SIGNED = 0x00001000; - - /** - * Flag of {@link #TYPE_CLASS_NUMBER}: the number is decimal, allowing - * a decimal point to provide fractional values. - */ - public static final int TYPE_NUMBER_FLAG_DECIMAL = 0x00002000; - - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - - /** - * Class for a phone number. This class currently supports no variations - * or flags. - */ - public static final int TYPE_CLASS_PHONE = 0x00000003; - - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - // ---------------------------------------------------------------------- - - /** - * Class for dates and times. It supports the - * following variations: - * {@link #TYPE_DATETIME_VARIATION_NORMAL} - * {@link #TYPE_DATETIME_VARIATION_DATE}, and - * {@link #TYPE_DATETIME_VARIATION_TIME},. - */ - public static final int TYPE_CLASS_DATETIME = 0x00000004; - - /** - * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering - * both a date and time. - */ - public static final int TYPE_DATETIME_VARIATION_NORMAL = 0x00000000; - - /** - * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering - * only a date. - */ - public static final int TYPE_DATETIME_VARIATION_DATE = 0x00000010; - - /** - * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering - * only a time. - */ - public static final int TYPE_DATETIME_VARIATION_TIME = 0x00000020; -} diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java deleted file mode 100644 index 95acf9d..0000000 --- a/core/java/android/text/Layout.java +++ /dev/null @@ -1,1747 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.Path; -import com.android.internal.util.ArrayUtils; -import android.util.Config; - -import junit.framework.Assert; -import android.text.style.*; -import android.text.method.TextKeyListener; -import android.view.KeyEvent; - -/** - * A base class that manages text layout in visual elements on - * the screen. - * <p>For text that will be edited, use a {@link DynamicLayout}, - * which will be updated as the text changes. - * For text that will not change, use a {@link StaticLayout}. - */ -public abstract class Layout { - /** - * Return how wide a layout would be necessary to display the - * specified text with one line per paragraph. - */ - public static float getDesiredWidth(CharSequence source, - TextPaint paint) { - return getDesiredWidth(source, 0, source.length(), paint); - } - - /** - * Return how wide a layout would be necessary to display the - * specified text slice with one line per paragraph. - */ - public static float getDesiredWidth(CharSequence source, - int start, int end, - TextPaint paint) { - float need = 0; - TextPaint workPaint = new TextPaint(); - - int next; - for (int i = start; i <= end; i = next) { - next = TextUtils.indexOf(source, '\n', i, end); - - if (next < 0) - next = end; - - float w = measureText(paint, workPaint, - source, i, next, null, true, null); - - if (w > need) - need = w; - - next++; - } - - return need; - } - - /** - * Subclasses of Layout use this constructor to set the display text, - * width, and other standard properties. - */ - protected Layout(CharSequence text, TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd) { - if (width < 0) - throw new IllegalArgumentException("Layout: " + width + " < 0"); - - mText = text; - mPaint = paint; - mWorkPaint = new TextPaint(); - mWidth = width; - mAlignment = align; - mSpacingMult = spacingmult; - mSpacingAdd = spacingadd; - mSpannedText = text instanceof Spanned; - } - - /** - * Replace constructor properties of this Layout with new ones. Be careful. - */ - /* package */ void replaceWith(CharSequence text, TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd) { - if (width < 0) { - throw new IllegalArgumentException("Layout: " + width + " < 0"); - } - - mText = text; - mPaint = paint; - mWidth = width; - mAlignment = align; - mSpacingMult = spacingmult; - mSpacingAdd = spacingadd; - mSpannedText = text instanceof Spanned; - } - - /** - * Draw this Layout on the specified Canvas. - */ - public void draw(Canvas c) { - draw(c, null, null, 0); - } - - /** - * Draw the specified rectangle from this Layout on the specified Canvas, - * with the specified path drawn between the background and the text. - */ - public void draw(Canvas c, Path highlight, Paint highlightpaint, - int cursorOffsetVertical) { - int dtop, dbottom; - - synchronized (sTempRect) { - if (!c.getClipBounds(sTempRect)) { - return; - } - - dtop = sTempRect.top; - dbottom = sTempRect.bottom; - } - - TextPaint paint = mPaint; - - int top = 0; - // getLineBottom(getLineCount() -1) just calls getLineTop(getLineCount) - int bottom = getLineTop(getLineCount()); - - - if (dtop > top) { - top = dtop; - } - if (dbottom < bottom) { - bottom = dbottom; - } - - int first = getLineForVertical(top); - int last = getLineForVertical(bottom); - - int previousLineBottom = getLineTop(first); - int previousLineEnd = getLineStart(first); - - CharSequence buf = mText; - - ParagraphStyle[] nospans = ArrayUtils.emptyArray(ParagraphStyle.class); - ParagraphStyle[] spans = nospans; - int spanend = 0; - int textLength = 0; - boolean spannedText = mSpannedText; - - if (spannedText) { - spanend = 0; - textLength = buf.length(); - for (int i = first; i <= last; i++) { - int start = previousLineEnd; - int end = getLineStart(i+1); - previousLineEnd = end; - - int ltop = previousLineBottom; - int lbottom = getLineTop(i+1); - previousLineBottom = lbottom; - int lbaseline = lbottom - getLineDescent(i); - - if (start >= spanend) { - Spanned sp = (Spanned) buf; - spanend = sp.nextSpanTransition(start, textLength, - LineBackgroundSpan.class); - spans = sp.getSpans(start, spanend, - LineBackgroundSpan.class); - } - - for (int n = 0; n < spans.length; n++) { - LineBackgroundSpan back = (LineBackgroundSpan) spans[n]; - - back.drawBackground(c, paint, 0, mWidth, - ltop, lbaseline, lbottom, - buf, start, end, - i); - } - } - // reset to their original values - spanend = 0; - previousLineBottom = getLineTop(first); - previousLineEnd = getLineStart(first); - spans = nospans; - } - - // There can be a highlight even without spans if we are drawing - // a non-spanned transformation of a spanned editing buffer. - if (highlight != null) { - if (cursorOffsetVertical != 0) { - c.translate(0, cursorOffsetVertical); - } - - c.drawPath(highlight, highlightpaint); - - if (cursorOffsetVertical != 0) { - c.translate(0, -cursorOffsetVertical); - } - } - - Alignment align = mAlignment; - - for (int i = first; i <= last; i++) { - int start = previousLineEnd; - - previousLineEnd = getLineStart(i+1); - int end = getLineVisibleEnd(i, start, previousLineEnd); - - int ltop = previousLineBottom; - int lbottom = getLineTop(i+1); - previousLineBottom = lbottom; - int lbaseline = lbottom - getLineDescent(i); - - boolean par = false; - if (spannedText) { - if (start == 0 || buf.charAt(start - 1) == '\n') { - par = true; - } - if (start >= spanend) { - - Spanned sp = (Spanned) buf; - - spanend = sp.nextSpanTransition(start, textLength, - ParagraphStyle.class); - spans = sp.getSpans(start, spanend, ParagraphStyle.class); - - align = mAlignment; - - for (int n = spans.length-1; n >= 0; n--) { - if (spans[n] instanceof AlignmentSpan) { - align = ((AlignmentSpan) spans[n]).getAlignment(); - break; - } - } - } - } - - int dir = getParagraphDirection(i); - int left = 0; - int right = mWidth; - - if (spannedText) { - final int length = spans.length; - for (int n = 0; n < length; n++) { - if (spans[n] instanceof LeadingMarginSpan) { - LeadingMarginSpan margin = (LeadingMarginSpan) spans[n]; - - if (dir == DIR_RIGHT_TO_LEFT) { - margin.drawLeadingMargin(c, paint, right, dir, ltop, - lbaseline, lbottom, buf, - start, end, par, this); - - right -= margin.getLeadingMargin(par); - } else { - margin.drawLeadingMargin(c, paint, left, dir, ltop, - lbaseline, lbottom, buf, - start, end, par, this); - - left += margin.getLeadingMargin(par); - } - } - } - } - - int x; - if (align == Alignment.ALIGN_NORMAL) { - if (dir == DIR_LEFT_TO_RIGHT) { - x = left; - } else { - x = right; - } - } else { - int max = (int)getLineMax(i, spans, false); - if (align == Alignment.ALIGN_OPPOSITE) { - if (dir == DIR_RIGHT_TO_LEFT) { - x = left + max; - } else { - x = right - max; - } - } else { - // Alignment.ALIGN_CENTER - max = max & ~1; - int half = (right - left - max) >> 1; - if (dir == DIR_RIGHT_TO_LEFT) { - x = right - half; - } else { - x = left + half; - } - } - } - - Directions directions = getLineDirections(i); - boolean hasTab = getLineContainsTab(i); - if (directions == DIRS_ALL_LEFT_TO_RIGHT && - !spannedText && !hasTab) { - if (Config.DEBUG) { - Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT); - Assert.assertNotNull(c); - } - c.drawText(buf, start, end, x, lbaseline, paint); - } else { - drawText(c, buf, start, end, dir, directions, - x, ltop, lbaseline, lbottom, paint, mWorkPaint, - hasTab, spans); - } - } - } - - /** - * Return the text that is displayed by this Layout. - */ - public final CharSequence getText() { - return mText; - } - - /** - * Return the base Paint properties for this layout. - * Do NOT change the paint, which may result in funny - * drawing for this layout. - */ - public final TextPaint getPaint() { - return mPaint; - } - - /** - * Return the width of this layout. - */ - public final int getWidth() { - return mWidth; - } - - /** - * Return the width to which this Layout is ellipsizing, or - * {@link #getWidth} if it is not doing anything special. - */ - public int getEllipsizedWidth() { - return mWidth; - } - - /** - * Increase the width of this layout to the specified width. - * Be careful to use this only when you know it is appropriate -- - * it does not cause the text to reflow to use the full new width. - */ - public final void increaseWidthTo(int wid) { - if (wid < mWidth) { - throw new RuntimeException("attempted to reduce Layout width"); - } - - mWidth = wid; - } - - /** - * Return the total height of this layout. - */ - public int getHeight() { - return getLineTop(getLineCount()); // same as getLineBottom(getLineCount() - 1); - } - - /** - * Return the base alignment of this layout. - */ - public final Alignment getAlignment() { - return mAlignment; - } - - /** - * Return what the text height is multiplied by to get the line height. - */ - public final float getSpacingMultiplier() { - return mSpacingMult; - } - - /** - * Return the number of units of leading that are added to each line. - */ - public final float getSpacingAdd() { - return mSpacingAdd; - } - - /** - * Return the number of lines of text in this layout. - */ - public abstract int getLineCount(); - - /** - * Return the baseline for the specified line (0…getLineCount() - 1) - * If bounds is not null, return the top, left, right, bottom extents - * of the specified line in it. - * @param line which line to examine (0..getLineCount() - 1) - * @param bounds Optional. If not null, it returns the extent of the line - * @return the Y-coordinate of the baseline - */ - public int getLineBounds(int line, Rect bounds) { - if (bounds != null) { - bounds.left = 0; // ??? - bounds.top = getLineTop(line); - bounds.right = mWidth; // ??? - bounds.bottom = getLineBottom(line); - } - return getLineBaseline(line); - } - - /** - * Return the vertical position of the top of the specified line. - * If the specified line is one beyond the last line, returns the - * bottom of the last line. - */ - public abstract int getLineTop(int line); - - /** - * Return the descent of the specified line. - */ - public abstract int getLineDescent(int line); - - /** - * Return the text offset of the beginning of the specified line. - * If the specified line is one beyond the last line, returns the - * end of the last line. - */ - public abstract int getLineStart(int line); - - /** - * Returns the primary directionality of the paragraph containing - * the specified line. - */ - public abstract int getParagraphDirection(int line); - - /** - * Returns whether the specified line contains one or more tabs. - */ - public abstract boolean getLineContainsTab(int line); - - /** - * Returns an array of directionalities for the specified line. - * The array alternates counts of characters in left-to-right - * and right-to-left segments of the line. - */ - public abstract Directions getLineDirections(int line); - - /** - * Returns the (negative) number of extra pixels of ascent padding in the - * top line of the Layout. - */ - public abstract int getTopPadding(); - - /** - * Returns the number of extra pixels of descent padding in the - * bottom line of the Layout. - */ - public abstract int getBottomPadding(); - - /** - * Get the primary horizontal position for the specified text offset. - * This is the location where a new character would be inserted in - * the paragraph's primary direction. - */ - public float getPrimaryHorizontal(int offset) { - return getHorizontal(offset, false, true); - } - - /** - * Get the secondary horizontal position for the specified text offset. - * This is the location where a new character would be inserted in - * the direction other than the paragraph's primary direction. - */ - public float getSecondaryHorizontal(int offset) { - return getHorizontal(offset, true, true); - } - - private float getHorizontal(int offset, boolean trailing, boolean alt) { - int line = getLineForOffset(offset); - - return getHorizontal(offset, trailing, alt, line); - } - - private float getHorizontal(int offset, boolean trailing, boolean alt, - int line) { - int start = getLineStart(line); - int end = getLineVisibleEnd(line); - int dir = getParagraphDirection(line); - boolean tab = getLineContainsTab(line); - Directions directions = getLineDirections(line); - - TabStopSpan[] tabs = null; - if (tab && mText instanceof Spanned) { - tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class); - } - - float wid = measureText(mPaint, mWorkPaint, mText, start, offset, end, - dir, directions, trailing, alt, tab, tabs); - - if (offset > end) { - if (dir == DIR_RIGHT_TO_LEFT) - wid -= measureText(mPaint, mWorkPaint, - mText, end, offset, null, tab, tabs); - else - wid += measureText(mPaint, mWorkPaint, - mText, end, offset, null, tab, tabs); - } - - Alignment align = getParagraphAlignment(line); - int left = getParagraphLeft(line); - int right = getParagraphRight(line); - - if (align == Alignment.ALIGN_NORMAL) { - if (dir == DIR_RIGHT_TO_LEFT) - return right + wid; - else - return left + wid; - } - - float max = getLineMax(line); - - if (align == Alignment.ALIGN_OPPOSITE) { - if (dir == DIR_RIGHT_TO_LEFT) - return left + max + wid; - else - return right - max + wid; - } else { /* align == Alignment.ALIGN_CENTER */ - int imax = ((int) max) & ~1; - - if (dir == DIR_RIGHT_TO_LEFT) - return right - (((right - left) - imax) / 2) + wid; - else - return left + ((right - left) - imax) / 2 + wid; - } - } - - /** - * Get the leftmost position that should be exposed for horizontal - * scrolling on the specified line. - */ - public float getLineLeft(int line) { - int dir = getParagraphDirection(line); - Alignment align = getParagraphAlignment(line); - - if (align == Alignment.ALIGN_NORMAL) { - if (dir == DIR_RIGHT_TO_LEFT) - return getParagraphRight(line) - getLineMax(line); - else - return 0; - } else if (align == Alignment.ALIGN_OPPOSITE) { - if (dir == DIR_RIGHT_TO_LEFT) - return 0; - else - return mWidth - getLineMax(line); - } else { /* align == Alignment.ALIGN_CENTER */ - int left = getParagraphLeft(line); - int right = getParagraphRight(line); - int max = ((int) getLineMax(line)) & ~1; - - return left + ((right - left) - max) / 2; - } - } - - /** - * Get the rightmost position that should be exposed for horizontal - * scrolling on the specified line. - */ - public float getLineRight(int line) { - int dir = getParagraphDirection(line); - Alignment align = getParagraphAlignment(line); - - if (align == Alignment.ALIGN_NORMAL) { - if (dir == DIR_RIGHT_TO_LEFT) - return mWidth; - else - return getParagraphLeft(line) + getLineMax(line); - } else if (align == Alignment.ALIGN_OPPOSITE) { - if (dir == DIR_RIGHT_TO_LEFT) - return getLineMax(line); - else - return mWidth; - } else { /* align == Alignment.ALIGN_CENTER */ - int left = getParagraphLeft(line); - int right = getParagraphRight(line); - int max = ((int) getLineMax(line)) & ~1; - - return right - ((right - left) - max) / 2; - } - } - - /** - * Gets the horizontal extent of the specified line, excluding - * trailing whitespace. - */ - public float getLineMax(int line) { - return getLineMax(line, null, false); - } - - /** - * Gets the horizontal extent of the specified line, including - * trailing whitespace. - */ - public float getLineWidth(int line) { - return getLineMax(line, null, true); - } - - private float getLineMax(int line, Object[] tabs, boolean full) { - int start = getLineStart(line); - int end; - - if (full) { - end = getLineEnd(line); - } else { - end = getLineVisibleEnd(line); - } - boolean tab = getLineContainsTab(line); - - if (tabs == null && tab && mText instanceof Spanned) { - tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class); - } - - return measureText(mPaint, mWorkPaint, - mText, start, end, null, tab, tabs); - } - - /** - * Get the line number corresponding to the specified vertical position. - * If you ask for a position above 0, you get 0; if you ask for a position - * below the bottom of the text, you get the last line. - */ - // FIXME: It may be faster to do a linear search for layouts without many lines. - public int getLineForVertical(int vertical) { - int high = getLineCount(), low = -1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (getLineTop(guess) > vertical) - high = guess; - else - low = guess; - } - - if (low < 0) - return 0; - else - return low; - } - - /** - * Get the line number on which the specified text offset appears. - * If you ask for a position before 0, you get 0; if you ask for a position - * beyond the end of the text, you get the last line. - */ - public int getLineForOffset(int offset) { - int high = getLineCount(), low = -1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (getLineStart(guess) > offset) - high = guess; - else - low = guess; - } - - if (low < 0) - return 0; - else - return low; - } - - /** - * Get the character offset on the specfied line whose position is - * closest to the specified horizontal position. - */ - public int getOffsetForHorizontal(int line, float horiz) { - int max = getLineEnd(line) - 1; - int min = getLineStart(line); - Directions dirs = getLineDirections(line); - - if (line == getLineCount() - 1) - max++; - - int best = min; - float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz); - - int here = min; - for (int i = 0; i < dirs.mDirections.length; i++) { - int there = here + dirs.mDirections[i]; - int swap = ((i & 1) == 0) ? 1 : -1; - - if (there > max) - there = max; - - int high = there - 1 + 1, low = here + 1 - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - int adguess = getOffsetAtStartOf(guess); - - if (getPrimaryHorizontal(adguess) * swap >= horiz * swap) - high = guess; - else - low = guess; - } - - if (low < here + 1) - low = here + 1; - - if (low < there) { - low = getOffsetAtStartOf(low); - - float dist = Math.abs(getPrimaryHorizontal(low) - horiz); - - int aft = TextUtils.getOffsetAfter(mText, low); - if (aft < there) { - float other = Math.abs(getPrimaryHorizontal(aft) - horiz); - - if (other < dist) { - dist = other; - low = aft; - } - } - - if (dist < bestdist) { - bestdist = dist; - best = low; - } - } - - float dist = Math.abs(getPrimaryHorizontal(here) - horiz); - - if (dist < bestdist) { - bestdist = dist; - best = here; - } - - here = there; - } - - float dist = Math.abs(getPrimaryHorizontal(max) - horiz); - - if (dist < bestdist) { - bestdist = dist; - best = max; - } - - return best; - } - - /** - * Return the text offset after the last character on the specified line. - */ - public final int getLineEnd(int line) { - return getLineStart(line + 1); - } - - /** - * Return the text offset after the last visible character (so whitespace - * is not counted) on the specified line. - */ - public int getLineVisibleEnd(int line) { - return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1)); - } - - private int getLineVisibleEnd(int line, int start, int end) { - if (Config.DEBUG) { - Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end); - } - - CharSequence text = mText; - char ch; - if (line == getLineCount() - 1) { - return end; - } - - for (; end > start; end--) { - ch = text.charAt(end - 1); - - if (ch == '\n') { - return end - 1; - } - - if (ch != ' ' && ch != '\t') { - break; - } - - } - - return end; - } - - /** - * Return the vertical position of the bottom of the specified line. - */ - public final int getLineBottom(int line) { - return getLineTop(line + 1); - } - - /** - * Return the vertical position of the baseline of the specified line. - */ - public final int getLineBaseline(int line) { - // getLineTop(line+1) == getLineTop(line) - return getLineTop(line+1) - getLineDescent(line); - } - - /** - * Get the ascent of the text on the specified line. - * The return value is negative to match the Paint.ascent() convention. - */ - public final int getLineAscent(int line) { - // getLineTop(line+1) - getLineDescent(line) == getLineBaseLine(line) - return getLineTop(line) - (getLineTop(line+1) - getLineDescent(line)); - } - - /** - * Return the text offset that would be reached by moving left - * (possibly onto another line) from the specified offset. - */ - public int getOffsetToLeftOf(int offset) { - int line = getLineForOffset(offset); - int start = getLineStart(line); - int end = getLineEnd(line); - Directions dirs = getLineDirections(line); - - if (line != getLineCount() - 1) - end--; - - float horiz = getPrimaryHorizontal(offset); - - int best = offset; - float besth = Integer.MIN_VALUE; - int candidate; - - candidate = TextUtils.getOffsetBefore(mText, offset); - if (candidate >= start && candidate <= end) { - float h = getPrimaryHorizontal(candidate); - - if (h < horiz && h > besth) { - best = candidate; - besth = h; - } - } - - candidate = TextUtils.getOffsetAfter(mText, offset); - if (candidate >= start && candidate <= end) { - float h = getPrimaryHorizontal(candidate); - - if (h < horiz && h > besth) { - best = candidate; - besth = h; - } - } - - int here = start; - for (int i = 0; i < dirs.mDirections.length; i++) { - int there = here + dirs.mDirections[i]; - if (there > end) - there = end; - - float h = getPrimaryHorizontal(here); - - if (h < horiz && h > besth) { - best = here; - besth = h; - } - - candidate = TextUtils.getOffsetAfter(mText, here); - if (candidate >= start && candidate <= end) { - h = getPrimaryHorizontal(candidate); - - if (h < horiz && h > besth) { - best = candidate; - besth = h; - } - } - - candidate = TextUtils.getOffsetBefore(mText, there); - if (candidate >= start && candidate <= end) { - h = getPrimaryHorizontal(candidate); - - if (h < horiz && h > besth) { - best = candidate; - besth = h; - } - } - - here = there; - } - - float h = getPrimaryHorizontal(end); - - if (h < horiz && h > besth) { - best = end; - besth = h; - } - - if (best != offset) - return best; - - int dir = getParagraphDirection(line); - - if (dir > 0) { - if (line == 0) - return best; - else - return getOffsetForHorizontal(line - 1, 10000); - } else { - if (line == getLineCount() - 1) - return best; - else - return getOffsetForHorizontal(line + 1, 10000); - } - } - - /** - * Return the text offset that would be reached by moving right - * (possibly onto another line) from the specified offset. - */ - public int getOffsetToRightOf(int offset) { - int line = getLineForOffset(offset); - int start = getLineStart(line); - int end = getLineEnd(line); - Directions dirs = getLineDirections(line); - - if (line != getLineCount() - 1) - end--; - - float horiz = getPrimaryHorizontal(offset); - - int best = offset; - float besth = Integer.MAX_VALUE; - int candidate; - - candidate = TextUtils.getOffsetBefore(mText, offset); - if (candidate >= start && candidate <= end) { - float h = getPrimaryHorizontal(candidate); - - if (h > horiz && h < besth) { - best = candidate; - besth = h; - } - } - - candidate = TextUtils.getOffsetAfter(mText, offset); - if (candidate >= start && candidate <= end) { - float h = getPrimaryHorizontal(candidate); - - if (h > horiz && h < besth) { - best = candidate; - besth = h; - } - } - - int here = start; - for (int i = 0; i < dirs.mDirections.length; i++) { - int there = here + dirs.mDirections[i]; - if (there > end) - there = end; - - float h = getPrimaryHorizontal(here); - - if (h > horiz && h < besth) { - best = here; - besth = h; - } - - candidate = TextUtils.getOffsetAfter(mText, here); - if (candidate >= start && candidate <= end) { - h = getPrimaryHorizontal(candidate); - - if (h > horiz && h < besth) { - best = candidate; - besth = h; - } - } - - candidate = TextUtils.getOffsetBefore(mText, there); - if (candidate >= start && candidate <= end) { - h = getPrimaryHorizontal(candidate); - - if (h > horiz && h < besth) { - best = candidate; - besth = h; - } - } - - here = there; - } - - float h = getPrimaryHorizontal(end); - - if (h > horiz && h < besth) { - best = end; - besth = h; - } - - if (best != offset) - return best; - - int dir = getParagraphDirection(line); - - if (dir > 0) { - if (line == getLineCount() - 1) - return best; - else - return getOffsetForHorizontal(line + 1, -10000); - } else { - if (line == 0) - return best; - else - return getOffsetForHorizontal(line - 1, -10000); - } - } - - private int getOffsetAtStartOf(int offset) { - if (offset == 0) - return 0; - - CharSequence text = mText; - char c = text.charAt(offset); - - if (c >= '\uDC00' && c <= '\uDFFF') { - char c1 = text.charAt(offset - 1); - - if (c1 >= '\uD800' && c1 <= '\uDBFF') - offset -= 1; - } - - if (mSpannedText) { - ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, - ReplacementSpan.class); - - for (int i = 0; i < spans.length; i++) { - int start = ((Spanned) text).getSpanStart(spans[i]); - int end = ((Spanned) text).getSpanEnd(spans[i]); - - if (start < offset && end > offset) - offset = start; - } - } - - return offset; - } - - /** - * Fills in the specified Path with a representation of a cursor - * at the specified offset. This will often be a vertical line - * but can be multiple discontinous lines in text with multiple - * directionalities. - */ - public void getCursorPath(int point, Path dest, - CharSequence editingBuffer) { - dest.reset(); - - int line = getLineForOffset(point); - int top = getLineTop(line); - int bottom = getLineTop(line+1); - - float h1 = getPrimaryHorizontal(point) - 0.5f; - float h2 = getSecondaryHorizontal(point) - 0.5f; - - int caps = TextKeyListener.getMetaState(editingBuffer, - KeyEvent.META_SHIFT_ON) | - TextKeyListener.getMetaState(editingBuffer, - TextKeyListener.META_SELECTING); - int fn = TextKeyListener.getMetaState(editingBuffer, - KeyEvent.META_ALT_ON); - int dist = 0; - - if (caps != 0 || fn != 0) { - dist = (bottom - top) >> 2; - - if (fn != 0) - top += dist; - if (caps != 0) - bottom -= dist; - } - - if (h1 < 0.5f) - h1 = 0.5f; - if (h2 < 0.5f) - h2 = 0.5f; - - if (h1 == h2) { - dest.moveTo(h1, top); - dest.lineTo(h1, bottom); - } else { - dest.moveTo(h1, top); - dest.lineTo(h1, (top + bottom) >> 1); - - dest.moveTo(h2, (top + bottom) >> 1); - dest.lineTo(h2, bottom); - } - - if (caps == 2) { - dest.moveTo(h2, bottom); - dest.lineTo(h2 - dist, bottom + dist); - dest.lineTo(h2, bottom); - dest.lineTo(h2 + dist, bottom + dist); - } else if (caps == 1) { - dest.moveTo(h2, bottom); - dest.lineTo(h2 - dist, bottom + dist); - - dest.moveTo(h2 - dist, bottom + dist - 0.5f); - dest.lineTo(h2 + dist, bottom + dist - 0.5f); - - dest.moveTo(h2 + dist, bottom + dist); - dest.lineTo(h2, bottom); - } - - if (fn == 2) { - dest.moveTo(h1, top); - dest.lineTo(h1 - dist, top - dist); - dest.lineTo(h1, top); - dest.lineTo(h1 + dist, top - dist); - } else if (fn == 1) { - dest.moveTo(h1, top); - dest.lineTo(h1 - dist, top - dist); - - dest.moveTo(h1 - dist, top - dist + 0.5f); - dest.lineTo(h1 + dist, top - dist + 0.5f); - - dest.moveTo(h1 + dist, top - dist); - dest.lineTo(h1, top); - } - } - - private void addSelection(int line, int start, int end, - int top, int bottom, Path dest) { - int linestart = getLineStart(line); - int lineend = getLineEnd(line); - Directions dirs = getLineDirections(line); - - if (lineend > linestart && mText.charAt(lineend - 1) == '\n') - lineend--; - - int here = linestart; - for (int i = 0; i < dirs.mDirections.length; i++) { - int there = here + dirs.mDirections[i]; - if (there > lineend) - there = lineend; - - if (start <= there && end >= here) { - int st = Math.max(start, here); - int en = Math.min(end, there); - - if (st != en) { - float h1 = getHorizontal(st, false, false, line); - float h2 = getHorizontal(en, true, false, line); - - dest.addRect(h1, top, h2, bottom, Path.Direction.CW); - } - } - - here = there; - } - } - - /** - * Fills in the specified Path with a representation of a highlight - * between the specified offsets. This will often be a rectangle - * or a potentially discontinuous set of rectangles. If the start - * and end are the same, the returned path is empty. - */ - public void getSelectionPath(int start, int end, Path dest) { - dest.reset(); - - if (start == end) - return; - - if (end < start) { - int temp = end; - end = start; - start = temp; - } - - int startline = getLineForOffset(start); - int endline = getLineForOffset(end); - - int top = getLineTop(startline); - int bottom = getLineBottom(endline); - - if (startline == endline) { - addSelection(startline, start, end, top, bottom, dest); - } else { - final float width = mWidth; - - addSelection(startline, start, getLineEnd(startline), - top, getLineBottom(startline), dest); - - if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) - dest.addRect(getLineLeft(startline), top, - 0, getLineBottom(startline), Path.Direction.CW); - else - dest.addRect(getLineRight(startline), top, - width, getLineBottom(startline), Path.Direction.CW); - - for (int i = startline + 1; i < endline; i++) { - top = getLineTop(i); - bottom = getLineBottom(i); - dest.addRect(0, top, width, bottom, Path.Direction.CW); - } - - top = getLineTop(endline); - bottom = getLineBottom(endline); - - addSelection(endline, getLineStart(endline), end, - top, bottom, dest); - - if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) - dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW); - else - dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW); - } - } - - /** - * Get the alignment of the specified paragraph, taking into account - * markup attached to it. - */ - public final Alignment getParagraphAlignment(int line) { - Alignment align = mAlignment; - - if (mSpannedText) { - Spanned sp = (Spanned) mText; - AlignmentSpan[] spans = sp.getSpans(getLineStart(line), - getLineEnd(line), - AlignmentSpan.class); - - int spanLength = spans.length; - if (spanLength > 0) { - align = spans[spanLength-1].getAlignment(); - } - } - - return align; - } - - /** - * Get the left edge of the specified paragraph, inset by left margins. - */ - public final int getParagraphLeft(int line) { - int dir = getParagraphDirection(line); - - int left = 0; - - boolean par = false; - int off = getLineStart(line); - if (off == 0 || mText.charAt(off - 1) == '\n') - par = true; - - if (dir == DIR_LEFT_TO_RIGHT) { - if (mSpannedText) { - Spanned sp = (Spanned) mText; - LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line), - getLineEnd(line), - LeadingMarginSpan.class); - - for (int i = 0; i < spans.length; i++) { - left += spans[i].getLeadingMargin(par); - } - } - } - - return left; - } - - /** - * Get the right edge of the specified paragraph, inset by right margins. - */ - public final int getParagraphRight(int line) { - int dir = getParagraphDirection(line); - - int right = mWidth; - - boolean par = false; - int off = getLineStart(line); - if (off == 0 || mText.charAt(off - 1) == '\n') - par = true; - - - if (dir == DIR_RIGHT_TO_LEFT) { - if (mSpannedText) { - Spanned sp = (Spanned) mText; - LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line), - getLineEnd(line), - LeadingMarginSpan.class); - - for (int i = 0; i < spans.length; i++) { - right -= spans[i].getLeadingMargin(par); - } - } - } - - return right; - } - - private static void drawText(Canvas canvas, - CharSequence text, int start, int end, - int dir, Directions directions, - float x, int top, int y, int bottom, - TextPaint paint, - TextPaint workPaint, - boolean hasTabs, Object[] parspans) { - char[] buf; - if (!hasTabs) { - if (directions == DIRS_ALL_LEFT_TO_RIGHT) { - if (Config.DEBUG) { - Assert.assertTrue(DIR_LEFT_TO_RIGHT == dir); - } - Styled.drawText(canvas, text, start, end, dir, false, x, top, y, bottom, paint, workPaint, false); - return; - } - buf = null; - } else { - buf = TextUtils.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - } - - float h = 0; - - int here = 0; - for (int i = 0; i < directions.mDirections.length; i++) { - int there = here + directions.mDirections[i]; - if (there > end - start) - there = end - start; - - int segstart = here; - for (int j = hasTabs ? here : there; j <= there; j++) { - if (j == there || buf[j] == '\t') { - h += Styled.drawText(canvas, text, - start + segstart, start + j, - dir, (i & 1) != 0, x + h, - top, y, bottom, paint, workPaint, - start + j != end); - - if (j != there && buf[j] == '\t') - h = dir * nextTab(text, start, end, h * dir, parspans); - - segstart = j + 1; - } - } - - here = there; - } - - if (hasTabs) - TextUtils.recycle(buf); - } - - private static float measureText(TextPaint paint, - TextPaint workPaint, - CharSequence text, - int start, int offset, int end, - int dir, Directions directions, - boolean trailing, boolean alt, - boolean hasTabs, Object[] tabs) { - char[] buf = null; - - if (hasTabs) { - buf = TextUtils.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - } - - float h = 0; - - if (alt) { - if (dir == DIR_RIGHT_TO_LEFT) - trailing = !trailing; - } - - int here = 0; - for (int i = 0; i < directions.mDirections.length; i++) { - if (alt) - trailing = !trailing; - - int there = here + directions.mDirections[i]; - if (there > end - start) - there = end - start; - - int segstart = here; - for (int j = hasTabs ? here : there; j <= there; j++) { - if (j == there || buf[j] == '\t') { - float segw; - - if (offset < start + j || - (trailing && offset <= start + j)) { - if (dir == DIR_LEFT_TO_RIGHT && (i & 1) == 0) { - h += Styled.measureText(paint, workPaint, text, - start + segstart, offset, - null); - return h; - } - - if (dir == DIR_RIGHT_TO_LEFT && (i & 1) != 0) { - h -= Styled.measureText(paint, workPaint, text, - start + segstart, offset, - null); - return h; - } - } - - segw = Styled.measureText(paint, workPaint, text, - start + segstart, start + j, - null); - - if (offset < start + j || - (trailing && offset <= start + j)) { - if (dir == DIR_LEFT_TO_RIGHT) { - h += segw - Styled.measureText(paint, workPaint, - text, - start + segstart, - offset, null); - return h; - } - - if (dir == DIR_RIGHT_TO_LEFT) { - h -= segw - Styled.measureText(paint, workPaint, - text, - start + segstart, - offset, null); - return h; - } - } - - if (dir == DIR_RIGHT_TO_LEFT) - h -= segw; - else - h += segw; - - if (j != there && buf[j] == '\t') { - if (offset == start + j) - return h; - - h = dir * nextTab(text, start, end, h * dir, tabs); - } - - segstart = j + 1; - } - } - - here = there; - } - - if (hasTabs) - TextUtils.recycle(buf); - - return h; - } - - /* package */ static float measureText(TextPaint paint, - TextPaint workPaint, - CharSequence text, - int start, int end, - Paint.FontMetricsInt fm, - boolean hasTabs, Object[] tabs) { - char[] buf = null; - - if (hasTabs) { - buf = TextUtils.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - } - - int len = end - start; - - int here = 0; - float h = 0; - int ab = 0, be = 0; - int top = 0, bot = 0; - - if (fm != null) { - fm.ascent = 0; - fm.descent = 0; - } - - for (int i = hasTabs ? 0 : len; i <= len; i++) { - if (i == len || buf[i] == '\t') { - workPaint.baselineShift = 0; - - h += Styled.measureText(paint, workPaint, text, - start + here, start + i, - fm); - - if (fm != null) { - if (workPaint.baselineShift < 0) { - fm.ascent += workPaint.baselineShift; - fm.top += workPaint.baselineShift; - } else { - fm.descent += workPaint.baselineShift; - fm.bottom += workPaint.baselineShift; - } - } - - if (i != len) - h = nextTab(text, start, end, h, tabs); - - if (fm != null) { - if (fm.ascent < ab) { - ab = fm.ascent; - } - if (fm.descent > be) { - be = fm.descent; - } - - if (fm.top < top) { - top = fm.top; - } - if (fm.bottom > bot) { - bot = fm.bottom; - } - } - - here = i + 1; - } - } - - if (fm != null) { - fm.ascent = ab; - fm.descent = be; - fm.top = top; - fm.bottom = bot; - } - - if (hasTabs) - TextUtils.recycle(buf); - - return h; - } - - /* package */ static float nextTab(CharSequence text, int start, int end, - float h, Object[] tabs) { - float nh = Float.MAX_VALUE; - boolean alltabs = false; - - if (text instanceof Spanned) { - if (tabs == null) { - tabs = ((Spanned) text).getSpans(start, end, TabStopSpan.class); - alltabs = true; - } - - for (int i = 0; i < tabs.length; i++) { - if (!alltabs) { - if (!(tabs[i] instanceof TabStopSpan)) - continue; - } - - int where = ((TabStopSpan) tabs[i]).getTabStop(); - - if (where < nh && where > h) - nh = where; - } - - if (nh != Float.MAX_VALUE) - return nh; - } - - return ((int) ((h + TAB_INCREMENT) / TAB_INCREMENT)) * TAB_INCREMENT; - } - - protected final boolean isSpanned() { - return mSpannedText; - } - - private void ellipsize(int start, int end, int line, - char[] dest, int destoff) { - int ellipsisCount = getEllipsisCount(line); - - if (ellipsisCount == 0) { - return; - } - - int ellipsisStart = getEllipsisStart(line); - int linestart = getLineStart(line); - - for (int i = ellipsisStart; i < ellipsisStart + ellipsisCount; i++) { - char c; - - if (i == ellipsisStart) { - c = '\u2026'; // ellipsis - } else { - c = '\uFEFF'; // 0-width space - } - - int a = i + linestart; - - if (a >= start && a < end) { - dest[destoff + a - start] = c; - } - } - } - - /** - * Stores information about bidirectional (left-to-right or right-to-left) - * text within the layout of a line. TODO: This work is not complete - * or correct and will be fleshed out in a later revision. - */ - public static class Directions { - private short[] mDirections; - - /* package */ Directions(short[] dirs) { - mDirections = dirs; - } - } - - /** - * Return the offset of the first character to be ellipsized away, - * relative to the start of the line. (So 0 if the beginning of the - * line is ellipsized, not getLineStart().) - */ - public abstract int getEllipsisStart(int line); - /** - * Returns the number of characters to be ellipsized away, or 0 if - * no ellipsis is to take place. - */ - public abstract int getEllipsisCount(int line); - - /* package */ static class Ellipsizer implements CharSequence, GetChars { - /* package */ CharSequence mText; - /* package */ Layout mLayout; - /* package */ int mWidth; - /* package */ TextUtils.TruncateAt mMethod; - - public Ellipsizer(CharSequence s) { - mText = s; - } - - public char charAt(int off) { - char[] buf = TextUtils.obtain(1); - getChars(off, off + 1, buf, 0); - char ret = buf[0]; - - TextUtils.recycle(buf); - return ret; - } - - public void getChars(int start, int end, char[] dest, int destoff) { - int line1 = mLayout.getLineForOffset(start); - int line2 = mLayout.getLineForOffset(end); - - TextUtils.getChars(mText, start, end, dest, destoff); - - for (int i = line1; i <= line2; i++) { - mLayout.ellipsize(start, end, i, dest, destoff); - } - } - - public int length() { - return mText.length(); - } - - public CharSequence subSequence(int start, int end) { - char[] s = new char[end - start]; - getChars(start, end, s, 0); - return new String(s); - } - - public String toString() { - char[] s = new char[length()]; - getChars(0, length(), s, 0); - return new String(s); - } - - } - - /* package */ static class SpannedEllipsizer - extends Ellipsizer implements Spanned { - private Spanned mSpanned; - - public SpannedEllipsizer(CharSequence display) { - super(display); - mSpanned = (Spanned) display; - } - - public <T> T[] getSpans(int start, int end, Class<T> type) { - return mSpanned.getSpans(start, end, type); - } - - public int getSpanStart(Object tag) { - return mSpanned.getSpanStart(tag); - } - - public int getSpanEnd(Object tag) { - return mSpanned.getSpanEnd(tag); - } - - public int getSpanFlags(Object tag) { - return mSpanned.getSpanFlags(tag); - } - - public int nextSpanTransition(int start, int limit, Class type) { - return mSpanned.nextSpanTransition(start, limit, type); - } - - public CharSequence subSequence(int start, int end) { - char[] s = new char[end - start]; - getChars(start, end, s, 0); - - SpannableString ss = new SpannableString(new String(s)); - TextUtils.copySpansFrom(mSpanned, start, end, Object.class, ss, 0); - return ss; - } - } - - private CharSequence mText; - private TextPaint mPaint; - /* package */ TextPaint mWorkPaint; - private int mWidth; - private Alignment mAlignment = Alignment.ALIGN_NORMAL; - private float mSpacingMult; - private float mSpacingAdd; - private static Rect sTempRect = new Rect(); - private boolean mSpannedText; - - public static final int DIR_LEFT_TO_RIGHT = 1; - public static final int DIR_RIGHT_TO_LEFT = -1; - - public enum Alignment { - ALIGN_NORMAL, - ALIGN_OPPOSITE, - ALIGN_CENTER, - // XXX ALIGN_LEFT, - // XXX ALIGN_RIGHT, - } - - private static final int TAB_INCREMENT = 20; - - /* package */ static final Directions DIRS_ALL_LEFT_TO_RIGHT = - new Directions(new short[] { 32767 }); - /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT = - new Directions(new short[] { 0, 32767 }); - -} - diff --git a/core/java/android/text/LoginFilter.java b/core/java/android/text/LoginFilter.java deleted file mode 100644 index 27c703f..0000000 --- a/core/java/android/text/LoginFilter.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * Abstract class for filtering login-related text (user names and passwords) - * - */ -public abstract class LoginFilter implements InputFilter { - private boolean mAppendInvalid; // whether to append or ignore invalid characters - /** - * Base constructor for LoginFilter - * @param appendInvalid whether or not to append invalid characters. - */ - LoginFilter(boolean appendInvalid) { - mAppendInvalid = appendInvalid; - } - - /** - * Default constructor for LoginFilter doesn't append invalid characters. - */ - LoginFilter() { - mAppendInvalid = false; - } - - /** - * This method is called when the buffer is going to replace the - * range <code>dstart … dend</code> of <code>dest</code> - * with the new text from the range <code>start … end</code> - * of <code>source</code>. Returns the CharSequence that we want - * placed there instead, including an empty string - * if appropriate, or <code>null</code> to accept the original - * replacement. Be careful to not to reject 0-length replacements, - * as this is what happens when you delete text. - */ - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - char[] out = new char[end - start]; // reserve enough space for whole string - int outidx = 0; - boolean changed = false; - - onStart(); - - // Scan through beginning characters in dest, calling onInvalidCharacter() - // for each invalid character. - for (int i = 0; i < dstart; i++) { - char c = dest.charAt(i); - if (!isAllowed(c)) onInvalidCharacter(c); - } - - // Scan through changed characters rejecting disallowed chars - for (int i = start; i < end; i++) { - char c = source.charAt(i); - if (isAllowed(c)) { - // Character allowed. Add it to the sequence. - out[outidx++] = c; - } else { - if (mAppendInvalid) out[outidx++] = c; - else changed = true; // we changed the original string - onInvalidCharacter(c); - } - } - - // Scan through remaining characters in dest, calling onInvalidCharacter() - // for each invalid character. - for (int i = dend; i < dest.length(); i++) { - char c = dest.charAt(i); - if (!isAllowed(c)) onInvalidCharacter(c); - } - - onStop(); - - if (!changed) { - return null; - } - - String s = new String(out, 0, outidx); - - if (source instanceof Spanned) { - SpannableString sp = new SpannableString(s); - TextUtils.copySpansFrom((Spanned) source, - start, end, null, sp, 0); - return sp; - } else { - return s; - } - } - - /** - * Called when we start processing filter. - */ - public void onStart() { - - } - - /** - * Called whenever we encounter an invalid character. - * @param c the invalid character - */ - public void onInvalidCharacter(char c) { - - } - - /** - * Called when we're done processing filter - */ - public void onStop() { - - } - - /** - * Returns whether or not we allow character c. - * Subclasses must override this method. - */ - public abstract boolean isAllowed(char c); - - /** - * This filter rejects characters in the user name that are not compatible with GMail - * account creation. It prevents the user from entering user names with characters other than - * [a-zA-Z0-9.]. - * - */ - public static class UsernameFilterGMail extends LoginFilter { - - public UsernameFilterGMail() { - super(false); - } - - public UsernameFilterGMail(boolean appendInvalid) { - super(appendInvalid); - } - - @Override - public boolean isAllowed(char c) { - // Allow [a-zA-Z0-9@.] - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'z') - return true; - if ('A' <= c && c <= 'Z') - return true; - if ('.' == c) - return true; - return false; - } - } - - /** - * This filter rejects characters in the user name that are not compatible with Google login. - * It is slightly less restrictive than the above filter in that it allows [a-zA-Z0-9._-]. - * - */ - public static class UsernameFilterGeneric extends LoginFilter { - private static final String mAllowed = "@_-."; // Additional characters - - public UsernameFilterGeneric() { - super(false); - } - - public UsernameFilterGeneric(boolean appendInvalid) { - super(appendInvalid); - } - - @Override - public boolean isAllowed(char c) { - // Allow [a-zA-Z0-9@.] - if ('0' <= c && c <= '9') - return true; - if ('a' <= c && c <= 'z') - return true; - if ('A' <= c && c <= 'Z') - return true; - if (mAllowed.indexOf(c) != -1) - return true; - return false; - } - } - - /** - * This filter is compatible with GMail passwords which restricts characters to - * the Latin-1 (ISO8859-1) char set. - * - */ - public static class PasswordFilterGMail extends LoginFilter { - - public PasswordFilterGMail() { - super(false); - } - - public PasswordFilterGMail(boolean appendInvalid) { - super(appendInvalid); - } - - // We should reject anything not in the Latin-1 (ISO8859-1) charset - @Override - public boolean isAllowed(char c) { - if (32 <= c && c <= 127) - return true; // standard charset - // if (128 <= c && c <= 159) return true; // nonstandard (Windows(TM)(R)) charset - if (160 <= c && c <= 255) - return true; // extended charset - return false; - } - } -} diff --git a/core/java/android/text/NoCopySpan.java b/core/java/android/text/NoCopySpan.java deleted file mode 100644 index 0855c0b..0000000 --- a/core/java/android/text/NoCopySpan.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * This interface should be added to a span object that should not be copied - * into a new Spenned when performing a slice or copy operation on the original - * Spanned it was placed in. - */ -public interface NoCopySpan { - /** - * Convenience equivalent for when you would just want a new Object() for - * a span but want it to be no-copy. Use this instead. - */ - public class Concrete implements NoCopySpan { - } -} diff --git a/core/java/android/text/PackedIntVector.java b/core/java/android/text/PackedIntVector.java deleted file mode 100644 index d87f600..0000000 --- a/core/java/android/text/PackedIntVector.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import com.android.internal.util.ArrayUtils; - - -/** - * PackedIntVector stores a two-dimensional array of integers, - * optimized for inserting and deleting rows and for - * offsetting the values in segments of a given column. - */ -class PackedIntVector { - private final int mColumns; - private int mRows; - - private int mRowGapStart; - private int mRowGapLength; - - private int[] mValues; - private int[] mValueGap; // starts, followed by lengths - - /** - * Creates a new PackedIntVector with the specified width and - * a height of 0. - * - * @param columns the width of the PackedIntVector. - */ - public PackedIntVector(int columns) { - mColumns = columns; - mRows = 0; - - mRowGapStart = 0; - mRowGapLength = mRows; - - mValues = null; - mValueGap = new int[2 * columns]; - } - - /** - * Returns the value at the specified row and column. - * - * @param row the index of the row to return. - * @param column the index of the column to return. - * - * @return the value stored at the specified position. - * - * @throws IndexOutOfBoundsException if the row is out of range - * (row < 0 || row >= size()) or the column is out of range - * (column < 0 || column >= width()). - */ - public int getValue(int row, int column) { - final int columns = mColumns; - - if (((row | column) < 0) || (row >= size()) || (column >= columns)) { - throw new IndexOutOfBoundsException(row + ", " + column); - } - - if (row >= mRowGapStart) { - row += mRowGapLength; - } - - int value = mValues[row * columns + column]; - - int[] valuegap = mValueGap; - if (row >= valuegap[column]) { - value += valuegap[column + columns]; - } - - return value; - } - - /** - * Sets the value at the specified row and column. - * - * @param row the index of the row to set. - * @param column the index of the column to set. - * - * @throws IndexOutOfBoundsException if the row is out of range - * (row < 0 || row >= size()) or the column is out of range - * (column < 0 || column >= width()). - */ - public void setValue(int row, int column, int value) { - if (((row | column) < 0) || (row >= size()) || (column >= mColumns)) { - throw new IndexOutOfBoundsException(row + ", " + column); - } - - if (row >= mRowGapStart) { - row += mRowGapLength; - } - - int[] valuegap = mValueGap; - if (row >= valuegap[column]) { - value -= valuegap[column + mColumns]; - } - - mValues[row * mColumns + column] = value; - } - - /** - * Sets the value at the specified row and column. - * Private internal version: does not check args. - * - * @param row the index of the row to set. - * @param column the index of the column to set. - * - */ - private void setValueInternal(int row, int column, int value) { - if (row >= mRowGapStart) { - row += mRowGapLength; - } - - int[] valuegap = mValueGap; - if (row >= valuegap[column]) { - value -= valuegap[column + mColumns]; - } - - mValues[row * mColumns + column] = value; - } - - - /** - * Increments all values in the specified column whose row >= the - * specified row by the specified delta. - * - * @param startRow the row at which to begin incrementing. - * This may be == size(), which case there is no effect. - * @param column the index of the column to set. - * - * @throws IndexOutOfBoundsException if the row is out of range - * (startRow < 0 || startRow > size()) or the column - * is out of range (column < 0 || column >= width()). - */ - public void adjustValuesBelow(int startRow, int column, int delta) { - if (((startRow | column) < 0) || (startRow > size()) || - (column >= width())) { - throw new IndexOutOfBoundsException(startRow + ", " + column); - } - - if (startRow >= mRowGapStart) { - startRow += mRowGapLength; - } - - moveValueGapTo(column, startRow); - mValueGap[column + mColumns] += delta; - } - - /** - * Inserts a new row of values at the specified row offset. - * - * @param row the row above which to insert the new row. - * This may be == size(), which case the new row is added - * at the end. - * @param values the new values to be added. If this is null, - * a row of zeroes is added. - * - * @throws IndexOutOfBoundsException if the row is out of range - * (row < 0 || row > size()) or if the length of the - * values array is too small (values.length < width()). - */ - public void insertAt(int row, int[] values) { - if ((row < 0) || (row > size())) { - throw new IndexOutOfBoundsException("row " + row); - } - - if ((values != null) && (values.length < width())) { - throw new IndexOutOfBoundsException("value count " + values.length); - } - - moveRowGapTo(row); - - if (mRowGapLength == 0) { - growBuffer(); - } - - mRowGapStart++; - mRowGapLength--; - - if (values == null) { - for (int i = mColumns - 1; i >= 0; i--) { - setValueInternal(row, i, 0); - } - } else { - for (int i = mColumns - 1; i >= 0; i--) { - setValueInternal(row, i, values[i]); - } - } - } - - /** - * Deletes the specified number of rows starting with the specified - * row. - * - * @param row the index of the first row to be deleted. - * @param count the number of rows to delete. - * - * @throws IndexOutOfBoundsException if any of the rows to be deleted - * are out of range (row < 0 || count < 0 || - * row + count > size()). - */ - public void deleteAt(int row, int count) { - if (((row | count) < 0) || (row + count > size())) { - throw new IndexOutOfBoundsException(row + ", " + count); - } - - moveRowGapTo(row + count); - - mRowGapStart -= count; - mRowGapLength += count; - - // TODO: Reclaim memory when the new height is much smaller - // than the allocated size. - } - - /** - * Returns the number of rows in the PackedIntVector. This number - * will change as rows are inserted and deleted. - * - * @return the number of rows. - */ - public int size() { - return mRows - mRowGapLength; - } - - /** - * Returns the width of the PackedIntVector. This number is set - * at construction and will not change. - * - * @return the number of columns. - */ - public int width() { - return mColumns; - } - - /** - * Grows the value and gap arrays to be large enough to store at least - * one more than the current number of rows. - */ - private final void growBuffer() { - final int columns = mColumns; - int newsize = size() + 1; - newsize = ArrayUtils.idealIntArraySize(newsize * columns) / columns; - int[] newvalues = new int[newsize * columns]; - - final int[] valuegap = mValueGap; - final int rowgapstart = mRowGapStart; - - int after = mRows - (rowgapstart + mRowGapLength); - - if (mValues != null) { - System.arraycopy(mValues, 0, newvalues, 0, columns * rowgapstart); - System.arraycopy(mValues, (mRows - after) * columns, - newvalues, (newsize - after) * columns, - after * columns); - } - - for (int i = 0; i < columns; i++) { - if (valuegap[i] >= rowgapstart) { - valuegap[i] += newsize - mRows; - - if (valuegap[i] < rowgapstart) { - valuegap[i] = rowgapstart; - } - } - } - - mRowGapLength += newsize - mRows; - mRows = newsize; - mValues = newvalues; - } - - /** - * Moves the gap in the values of the specified column to begin at - * the specified row. - */ - private final void moveValueGapTo(int column, int where) { - final int[] valuegap = mValueGap; - final int[] values = mValues; - final int columns = mColumns; - - if (where == valuegap[column]) { - return; - } else if (where > valuegap[column]) { - for (int i = valuegap[column]; i < where; i++) { - values[i * columns + column] += valuegap[column + columns]; - } - } else /* where < valuegap[column] */ { - for (int i = where; i < valuegap[column]; i++) { - values[i * columns + column] -= valuegap[column + columns]; - } - } - - valuegap[column] = where; - } - - /** - * Moves the gap in the row indices to begin at the specified row. - */ - private final void moveRowGapTo(int where) { - if (where == mRowGapStart) { - return; - } else if (where > mRowGapStart) { - int moving = where + mRowGapLength - (mRowGapStart + mRowGapLength); - final int columns = mColumns; - final int[] valuegap = mValueGap; - final int[] values = mValues; - final int gapend = mRowGapStart + mRowGapLength; - - for (int i = gapend; i < gapend + moving; i++) { - int destrow = i - gapend + mRowGapStart; - - for (int j = 0; j < columns; j++) { - int val = values[i * columns+ j]; - - if (i >= valuegap[j]) { - val += valuegap[j + columns]; - } - - if (destrow >= valuegap[j]) { - val -= valuegap[j + columns]; - } - - values[destrow * columns + j] = val; - } - } - } else /* where < mRowGapStart */ { - int moving = mRowGapStart - where; - final int columns = mColumns; - final int[] valuegap = mValueGap; - final int[] values = mValues; - final int gapend = mRowGapStart + mRowGapLength; - - for (int i = where + moving - 1; i >= where; i--) { - int destrow = i - where + gapend - moving; - - for (int j = 0; j < columns; j++) { - int val = values[i * columns+ j]; - - if (i >= valuegap[j]) { - val += valuegap[j + columns]; - } - - if (destrow >= valuegap[j]) { - val -= valuegap[j + columns]; - } - - values[destrow * columns + j] = val; - } - } - } - - mRowGapStart = where; - } -} diff --git a/core/java/android/text/PackedObjectVector.java b/core/java/android/text/PackedObjectVector.java deleted file mode 100644 index a29df09..0000000 --- a/core/java/android/text/PackedObjectVector.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import com.android.internal.util.ArrayUtils; - -class PackedObjectVector<E> -{ - private int mColumns; - private int mRows; - - private int mRowGapStart; - private int mRowGapLength; - - private Object[] mValues; - - public - PackedObjectVector(int columns) - { - mColumns = columns; - mRows = ArrayUtils.idealIntArraySize(0) / mColumns; - - mRowGapStart = 0; - mRowGapLength = mRows; - - mValues = new Object[mRows * mColumns]; - } - - public E - getValue(int row, int column) - { - if (row >= mRowGapStart) - row += mRowGapLength; - - Object value = mValues[row * mColumns + column]; - - return (E) value; - } - - public void - setValue(int row, int column, E value) - { - if (row >= mRowGapStart) - row += mRowGapLength; - - mValues[row * mColumns + column] = value; - } - - public void - insertAt(int row, E[] values) - { - moveRowGapTo(row); - - if (mRowGapLength == 0) - growBuffer(); - - mRowGapStart++; - mRowGapLength--; - - if (values == null) - for (int i = 0; i < mColumns; i++) - setValue(row, i, null); - else - for (int i = 0; i < mColumns; i++) - setValue(row, i, values[i]); - } - - public void - deleteAt(int row, int count) - { - moveRowGapTo(row + count); - - mRowGapStart -= count; - mRowGapLength += count; - - if (mRowGapLength > size() * 2) - { - // dump(); - // growBuffer(); - } - } - - public int - size() - { - return mRows - mRowGapLength; - } - - public int - width() - { - return mColumns; - } - - private void - growBuffer() - { - int newsize = size() + 1; - newsize = ArrayUtils.idealIntArraySize(newsize * mColumns) / mColumns; - Object[] newvalues = new Object[newsize * mColumns]; - - int after = mRows - (mRowGapStart + mRowGapLength); - - System.arraycopy(mValues, 0, newvalues, 0, mColumns * mRowGapStart); - System.arraycopy(mValues, (mRows - after) * mColumns, newvalues, (newsize - after) * mColumns, after * mColumns); - - mRowGapLength += newsize - mRows; - mRows = newsize; - mValues = newvalues; - } - - private void - moveRowGapTo(int where) - { - if (where == mRowGapStart) - return; - - if (where > mRowGapStart) - { - int moving = where + mRowGapLength - (mRowGapStart + mRowGapLength); - - for (int i = mRowGapStart + mRowGapLength; i < mRowGapStart + mRowGapLength + moving; i++) - { - int destrow = i - (mRowGapStart + mRowGapLength) + mRowGapStart; - - for (int j = 0; j < mColumns; j++) - { - Object val = mValues[i * mColumns + j]; - - mValues[destrow * mColumns + j] = val; - } - } - } - else /* where < mRowGapStart */ - { - int moving = mRowGapStart - where; - - for (int i = where + moving - 1; i >= where; i--) - { - int destrow = i - where + mRowGapStart + mRowGapLength - moving; - - for (int j = 0; j < mColumns; j++) - { - Object val = mValues[i * mColumns + j]; - - mValues[destrow * mColumns + j] = val; - } - } - } - - mRowGapStart = where; - } - - public void // XXX - dump() - { - for (int i = 0; i < mRows; i++) - { - for (int j = 0; j < mColumns; j++) - { - Object val = mValues[i * mColumns + j]; - - if (i < mRowGapStart || i >= mRowGapStart + mRowGapLength) - System.out.print(val + " "); - else - System.out.print("(" + val + ") "); - } - - System.out.print(" << \n"); - } - - System.out.print("-----\n\n"); - } -} diff --git a/core/java/android/text/ParcelableSpan.java b/core/java/android/text/ParcelableSpan.java deleted file mode 100644 index 224511a..0000000 --- a/core/java/android/text/ParcelableSpan.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.os.Parcelable; - -/** - * A special kind of Parcelable for objects that will serve as text spans. - * This can only be used by code in the framework; it is not intended for - * applications to implement their own Parcelable spans. - */ -public interface ParcelableSpan extends Parcelable { - /** - * Return a special type identifier for this span class. - */ - public abstract int getSpanTypeId(); -} diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java deleted file mode 100644 index bb98bce..0000000 --- a/core/java/android/text/Selection.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - - -/** - * Utility class for manipulating cursors and selections in CharSequences. - * A cursor is a selection where the start and end are at the same offset. - */ -public class Selection { - private Selection() { /* cannot be instantiated */ } - - /* - * Retrieving the selection - */ - - /** - * Return the offset of the selection anchor or cursor, or -1 if - * there is no selection or cursor. - */ - public static final int getSelectionStart(CharSequence text) { - if (text instanceof Spanned) - return ((Spanned) text).getSpanStart(SELECTION_START); - else - return -1; - } - - /** - * Return the offset of the selection edge or cursor, or -1 if - * there is no selection or cursor. - */ - public static final int getSelectionEnd(CharSequence text) { - if (text instanceof Spanned) - return ((Spanned) text).getSpanStart(SELECTION_END); - else - return -1; - } - - /* - * Setting the selection - */ - - // private static int pin(int value, int min, int max) { - // return value < min ? 0 : (value > max ? max : value); - // } - - /** - * Set the selection anchor to <code>start</code> and the selection edge - * to <code>stop</code>. - */ - public static void setSelection(Spannable text, int start, int stop) { - // int len = text.length(); - // start = pin(start, 0, len); XXX remove unless we really need it - // stop = pin(stop, 0, len); - - int ostart = getSelectionStart(text); - int oend = getSelectionEnd(text); - - if (ostart != start || oend != stop) { - text.setSpan(SELECTION_START, start, start, - Spanned.SPAN_POINT_POINT|Spanned.SPAN_INTERMEDIATE); - text.setSpan(SELECTION_END, stop, stop, - Spanned.SPAN_POINT_POINT); - } - } - - /** - * Move the cursor to offset <code>index</code>. - */ - public static final void setSelection(Spannable text, int index) { - setSelection(text, index, index); - } - - /** - * Select the entire text. - */ - public static final void selectAll(Spannable text) { - setSelection(text, 0, text.length()); - } - - /** - * Move the selection edge to offset <code>index</code>. - */ - public static final void extendSelection(Spannable text, int index) { - if (text.getSpanStart(SELECTION_END) != index) - text.setSpan(SELECTION_END, index, index, Spanned.SPAN_POINT_POINT); - } - - /** - * Remove the selection or cursor, if any, from the text. - */ - public static final void removeSelection(Spannable text) { - text.removeSpan(SELECTION_START); - text.removeSpan(SELECTION_END); - } - - /* - * Moving the selection within the layout - */ - - /** - * Move the cursor to the buffer offset physically above the current - * offset, or return false if the cursor is already on the top line. - */ - public static boolean moveUp(Spannable text, Layout layout) { - int start = getSelectionStart(text); - int end = getSelectionEnd(text); - - if (start != end) { - int min = Math.min(start, end); - int max = Math.max(start, end); - - setSelection(text, min); - - if (min == 0 && max == text.length()) { - return false; - } - - return true; - } else { - int line = layout.getLineForOffset(end); - - if (line > 0) { - int move; - - if (layout.getParagraphDirection(line) == - layout.getParagraphDirection(line - 1)) { - float h = layout.getPrimaryHorizontal(end); - move = layout.getOffsetForHorizontal(line - 1, h); - } else { - move = layout.getLineStart(line - 1); - } - - setSelection(text, move); - return true; - } - } - - return false; - } - - /** - * Move the cursor to the buffer offset physically below the current - * offset, or return false if the cursor is already on the bottom line. - */ - public static boolean moveDown(Spannable text, Layout layout) { - int start = getSelectionStart(text); - int end = getSelectionEnd(text); - - if (start != end) { - int min = Math.min(start, end); - int max = Math.max(start, end); - - setSelection(text, max); - - if (min == 0 && max == text.length()) { - return false; - } - - return true; - } else { - int line = layout.getLineForOffset(end); - - if (line < layout.getLineCount() - 1) { - int move; - - if (layout.getParagraphDirection(line) == - layout.getParagraphDirection(line + 1)) { - float h = layout.getPrimaryHorizontal(end); - move = layout.getOffsetForHorizontal(line + 1, h); - } else { - move = layout.getLineStart(line + 1); - } - - setSelection(text, move); - return true; - } - } - - return false; - } - - /** - * Move the cursor to the buffer offset physically to the left of - * the current offset, or return false if the cursor is already - * at the left edge of the line and there is not another line to move it to. - */ - public static boolean moveLeft(Spannable text, Layout layout) { - int start = getSelectionStart(text); - int end = getSelectionEnd(text); - - if (start != end) { - setSelection(text, chooseHorizontal(layout, -1, start, end)); - return true; - } else { - int to = layout.getOffsetToLeftOf(end); - - if (to != end) { - setSelection(text, to); - return true; - } - } - - return false; - } - - /** - * Move the cursor to the buffer offset physically to the right of - * the current offset, or return false if the cursor is already at - * at the right edge of the line and there is not another line - * to move it to. - */ - public static boolean moveRight(Spannable text, Layout layout) { - int start = getSelectionStart(text); - int end = getSelectionEnd(text); - - if (start != end) { - setSelection(text, chooseHorizontal(layout, 1, start, end)); - return true; - } else { - int to = layout.getOffsetToRightOf(end); - - if (to != end) { - setSelection(text, to); - return true; - } - } - - return false; - } - - /** - * Move the selection end to the buffer offset physically above - * the current selection end. - */ - public static boolean extendUp(Spannable text, Layout layout) { - int end = getSelectionEnd(text); - int line = layout.getLineForOffset(end); - - if (line > 0) { - int move; - - if (layout.getParagraphDirection(line) == - layout.getParagraphDirection(line - 1)) { - float h = layout.getPrimaryHorizontal(end); - move = layout.getOffsetForHorizontal(line - 1, h); - } else { - move = layout.getLineStart(line - 1); - } - - extendSelection(text, move); - return true; - } else if (end != 0) { - extendSelection(text, 0); - return true; - } - - return true; - } - - /** - * Move the selection end to the buffer offset physically below - * the current selection end. - */ - public static boolean extendDown(Spannable text, Layout layout) { - int end = getSelectionEnd(text); - int line = layout.getLineForOffset(end); - - if (line < layout.getLineCount() - 1) { - int move; - - if (layout.getParagraphDirection(line) == - layout.getParagraphDirection(line + 1)) { - float h = layout.getPrimaryHorizontal(end); - move = layout.getOffsetForHorizontal(line + 1, h); - } else { - move = layout.getLineStart(line + 1); - } - - extendSelection(text, move); - return true; - } else if (end != text.length()) { - extendSelection(text, text.length()); - return true; - } - - return true; - } - - /** - * Move the selection end to the buffer offset physically to the left of - * the current selection end. - */ - public static boolean extendLeft(Spannable text, Layout layout) { - int end = getSelectionEnd(text); - int to = layout.getOffsetToLeftOf(end); - - if (to != end) { - extendSelection(text, to); - return true; - } - - return true; - } - - /** - * Move the selection end to the buffer offset physically to the right of - * the current selection end. - */ - public static boolean extendRight(Spannable text, Layout layout) { - int end = getSelectionEnd(text); - int to = layout.getOffsetToRightOf(end); - - if (to != end) { - extendSelection(text, to); - return true; - } - - return true; - } - - public static boolean extendToLeftEdge(Spannable text, Layout layout) { - int where = findEdge(text, layout, -1); - extendSelection(text, where); - return true; - } - - public static boolean extendToRightEdge(Spannable text, Layout layout) { - int where = findEdge(text, layout, 1); - extendSelection(text, where); - return true; - } - - public static boolean moveToLeftEdge(Spannable text, Layout layout) { - int where = findEdge(text, layout, -1); - setSelection(text, where); - return true; - } - - public static boolean moveToRightEdge(Spannable text, Layout layout) { - int where = findEdge(text, layout, 1); - setSelection(text, where); - return true; - } - - private static int findEdge(Spannable text, Layout layout, int dir) { - int pt = getSelectionEnd(text); - int line = layout.getLineForOffset(pt); - int pdir = layout.getParagraphDirection(line); - - if (dir * pdir < 0) { - return layout.getLineStart(line); - } else { - int end = layout.getLineEnd(line); - - if (line == layout.getLineCount() - 1) - return end; - else - return end - 1; - } - } - - private static int chooseHorizontal(Layout layout, int direction, - int off1, int off2) { - int line1 = layout.getLineForOffset(off1); - int line2 = layout.getLineForOffset(off2); - - if (line1 == line2) { - // same line, so it goes by pure physical direction - - float h1 = layout.getPrimaryHorizontal(off1); - float h2 = layout.getPrimaryHorizontal(off2); - - if (direction < 0) { - // to left - - if (h1 < h2) - return off1; - else - return off2; - } else { - // to right - - if (h1 > h2) - return off1; - else - return off2; - } - } else { - // different line, so which line is "left" and which is "right" - // depends upon the directionality of the text - - // This only checks at one end, but it's not clear what the - // right thing to do is if the ends don't agree. Even if it - // is wrong it should still not be too bad. - int line = layout.getLineForOffset(off1); - int textdir = layout.getParagraphDirection(line); - - if (textdir == direction) - return Math.max(off1, off2); - else - return Math.min(off1, off2); - } - } - - private static final class START implements NoCopySpan { }; - private static final class END implements NoCopySpan { }; - - /* - * Public constants - */ - - public static final Object SELECTION_START = new START(); - public static final Object SELECTION_END = new END(); -} diff --git a/core/java/android/text/SpanWatcher.java b/core/java/android/text/SpanWatcher.java deleted file mode 100644 index 01e82c8..0000000 --- a/core/java/android/text/SpanWatcher.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * When an object of this type is attached to a Spannable, its methods - * will be called to notify it that other markup objects have been - * added, changed, or removed. - */ -public interface SpanWatcher extends NoCopySpan { - /** - * This method is called to notify you that the specified object - * has been attached to the specified range of the text. - */ - public void onSpanAdded(Spannable text, Object what, int start, int end); - /** - * This method is called to notify you that the specified object - * has been detached from the specified range of the text. - */ - public void onSpanRemoved(Spannable text, Object what, int start, int end); - /** - * This method is called to notify you that the specified object - * has been relocated from the range <code>ostart…oend</code> - * to the new range <code>nstart…nend</code> of the text. - */ - public void onSpanChanged(Spannable text, Object what, int ostart, int oend, - int nstart, int nend); -} diff --git a/core/java/android/text/Spannable.java b/core/java/android/text/Spannable.java deleted file mode 100644 index ae5d356..0000000 --- a/core/java/android/text/Spannable.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * This is the interface for text to which markup objects can be - * attached and detached. Not all Spannable classes have mutable text; - * see {@link Editable} for that. - */ -public interface Spannable -extends Spanned -{ - /** - * Attach the specified markup object to the range <code>start…end</code> - * of the text, or move the object to that range if it was already - * attached elsewhere. See {@link Spanned} for an explanation of - * what the flags mean. The object can be one that has meaning only - * within your application, or it can be one that the text system will - * use to affect text display or behavior. Some noteworthy ones are - * the subclasses of {@link android.text.style.CharacterStyle} and - * {@link android.text.style.ParagraphStyle}, and - * {@link android.text.TextWatcher} and - * {@link android.text.SpanWatcher}. - */ - public void setSpan(Object what, int start, int end, int flags); - - /** - * Remove the specified object from the range of text to which it - * was attached, if any. It is OK to remove an object that was never - * attached in the first place. - */ - public void removeSpan(Object what); - - /** - * Factory used by TextView to create new Spannables. You can subclass - * it to provide something other than SpannableString. - */ - public static class Factory { - private static Spannable.Factory sInstance = new Spannable.Factory(); - - /** - * Returns the standard Spannable Factory. - */ - public static Spannable.Factory getInstance() { - return sInstance; - } - - /** - * Returns a new SpannableString from the specified CharSequence. - * You can override this to provide a different kind of Spannable. - */ - public Spannable newSpannable(CharSequence source) { - return new SpannableString(source); - } - } -} diff --git a/core/java/android/text/SpannableString.java b/core/java/android/text/SpannableString.java deleted file mode 100644 index 56d0946..0000000 --- a/core/java/android/text/SpannableString.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - - -/** - * This is the class for text whose content is immutable but to which - * markup objects can be attached and detached. - * For mutable text, see {@link SpannableStringBuilder}. - */ -public class SpannableString -extends SpannableStringInternal -implements CharSequence, GetChars, Spannable -{ - public SpannableString(CharSequence source) { - super(source, 0, source.length()); - } - - private SpannableString(CharSequence source, int start, int end) { - super(source, start, end); - } - - public static SpannableString valueOf(CharSequence source) { - if (source instanceof SpannableString) { - return (SpannableString) source; - } else { - return new SpannableString(source); - } - } - - public void setSpan(Object what, int start, int end, int flags) { - super.setSpan(what, start, end, flags); - } - - public void removeSpan(Object what) { - super.removeSpan(what); - } - - public final CharSequence subSequence(int start, int end) { - return new SpannableString(this, start, end); - } -} diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java deleted file mode 100644 index caaafa1..0000000 --- a/core/java/android/text/SpannableStringBuilder.java +++ /dev/null @@ -1,1140 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import com.android.internal.util.ArrayUtils; -import android.graphics.Paint; -import android.graphics.Canvas; - -import java.lang.reflect.Array; - -/** - * This is the class for text whose content and markup can both be changed. - */ -public class SpannableStringBuilder -implements CharSequence, GetChars, Spannable, Editable, Appendable, - GraphicsOperations -{ - /** - * Create a new SpannableStringBuilder with empty contents - */ - public SpannableStringBuilder() { - this(""); - } - - /** - * Create a new SpannableStringBuilder containing a copy of the - * specified text, including its spans if any. - */ - public SpannableStringBuilder(CharSequence text) { - this(text, 0, text.length()); - } - - /** - * Create a new SpannableStringBuilder containing a copy of the - * specified slice of the specified text, including its spans if any. - */ - public SpannableStringBuilder(CharSequence text, int start, int end) { - int srclen = end - start; - - int len = ArrayUtils.idealCharArraySize(srclen + 1); - mText = new char[len]; - mGapStart = srclen; - mGapLength = len - srclen; - - TextUtils.getChars(text, start, end, mText, 0); - - mSpanCount = 0; - int alloc = ArrayUtils.idealIntArraySize(0); - mSpans = new Object[alloc]; - mSpanStarts = new int[alloc]; - mSpanEnds = new int[alloc]; - mSpanFlags = new int[alloc]; - - if (text instanceof Spanned) { - Spanned sp = (Spanned) text; - Object[] spans = sp.getSpans(start, end, Object.class); - - for (int i = 0; i < spans.length; i++) { - if (spans[i] instanceof NoCopySpan) { - continue; - } - - int st = sp.getSpanStart(spans[i]) - start; - int en = sp.getSpanEnd(spans[i]) - start; - int fl = sp.getSpanFlags(spans[i]); - - if (st < 0) - st = 0; - if (st > end - start) - st = end - start; - - if (en < 0) - en = 0; - if (en > end - start) - en = end - start; - - setSpan(spans[i], st, en, fl); - } - } - } - - public static SpannableStringBuilder valueOf(CharSequence source) { - if (source instanceof SpannableStringBuilder) { - return (SpannableStringBuilder) source; - } else { - return new SpannableStringBuilder(source); - } - } - - /** - * Return the char at the specified offset within the buffer. - */ - public char charAt(int where) { - int len = length(); - if (where < 0) { - throw new IndexOutOfBoundsException("charAt: " + where + " < 0"); - } else if (where >= len) { - throw new IndexOutOfBoundsException("charAt: " + where + - " >= length " + len); - } - - if (where >= mGapStart) - return mText[where + mGapLength]; - else - return mText[where]; - } - - /** - * Return the number of chars in the buffer. - */ - public int length() { - return mText.length - mGapLength; - } - - private void resizeFor(int size) { - int newlen = ArrayUtils.idealCharArraySize(size + 1); - char[] newtext = new char[newlen]; - - int after = mText.length - (mGapStart + mGapLength); - - System.arraycopy(mText, 0, newtext, 0, mGapStart); - System.arraycopy(mText, mText.length - after, - newtext, newlen - after, after); - - for (int i = 0; i < mSpanCount; i++) { - if (mSpanStarts[i] > mGapStart) - mSpanStarts[i] += newlen - mText.length; - if (mSpanEnds[i] > mGapStart) - mSpanEnds[i] += newlen - mText.length; - } - - int oldlen = mText.length; - mText = newtext; - mGapLength += mText.length - oldlen; - - if (mGapLength < 1) - new Exception("mGapLength < 1").printStackTrace(); - } - - private void moveGapTo(int where) { - if (where == mGapStart) - return; - - boolean atend = (where == length()); - - if (where < mGapStart) { - int overlap = mGapStart - where; - - System.arraycopy(mText, where, - mText, mGapStart + mGapLength - overlap, overlap); - } else /* where > mGapStart */ { - int overlap = where - mGapStart; - - System.arraycopy(mText, where + mGapLength - overlap, - mText, mGapStart, overlap); - } - - // XXX be more clever - for (int i = 0; i < mSpanCount; i++) { - int start = mSpanStarts[i]; - int end = mSpanEnds[i]; - - if (start > mGapStart) - start -= mGapLength; - if (start > where) - start += mGapLength; - else if (start == where) { - int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; - - if (flag == POINT || (atend && flag == PARAGRAPH)) - start += mGapLength; - } - - if (end > mGapStart) - end -= mGapLength; - if (end > where) - end += mGapLength; - else if (end == where) { - int flag = (mSpanFlags[i] & END_MASK); - - if (flag == POINT || (atend && flag == PARAGRAPH)) - end += mGapLength; - } - - mSpanStarts[i] = start; - mSpanEnds[i] = end; - } - - mGapStart = where; - } - - // Documentation from interface - public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) { - return replace(where, where, tb, start, end); - } - - // Documentation from interface - public SpannableStringBuilder insert(int where, CharSequence tb) { - return replace(where, where, tb, 0, tb.length()); - } - - // Documentation from interface - public SpannableStringBuilder delete(int start, int end) { - SpannableStringBuilder ret = replace(start, end, "", 0, 0); - - if (mGapLength > 2 * length()) - resizeFor(length()); - - return ret; // == this - } - - // Documentation from interface - public void clear() { - replace(0, length(), "", 0, 0); - } - - // Documentation from interface - public void clearSpans() { - for (int i = mSpanCount - 1; i >= 0; i--) { - Object what = mSpans[i]; - int ostart = mSpanStarts[i]; - int oend = mSpanEnds[i]; - - if (ostart > mGapStart) - ostart -= mGapLength; - if (oend > mGapStart) - oend -= mGapLength; - - mSpanCount = i; - mSpans[i] = null; - - sendSpanRemoved(what, ostart, oend); - } - } - - // Documentation from interface - public SpannableStringBuilder append(CharSequence text) { - int length = length(); - return replace(length, length, text, 0, text.length()); - } - - // Documentation from interface - public SpannableStringBuilder append(CharSequence text, int start, int end) { - int length = length(); - return replace(length, length, text, start, end); - } - - // Documentation from interface - public SpannableStringBuilder append(char text) { - return append(String.valueOf(text)); - } - - private int change(int start, int end, - CharSequence tb, int tbstart, int tbend) { - return change(true, start, end, tb, tbstart, tbend); - } - - private int change(boolean notify, int start, int end, - CharSequence tb, int tbstart, int tbend) { - checkRange("replace", start, end); - int ret = tbend - tbstart; - TextWatcher[] recipients = null; - - if (notify) - recipients = sendTextWillChange(start, end - start, - tbend - tbstart); - - for (int i = mSpanCount - 1; i >= 0; i--) { - if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) { - int st = mSpanStarts[i]; - if (st > mGapStart) - st -= mGapLength; - - int en = mSpanEnds[i]; - if (en > mGapStart) - en -= mGapLength; - - int ost = st; - int oen = en; - int clen = length(); - - if (st > start && st <= end) { - for (st = end; st < clen; st++) - if (st > end && charAt(st - 1) == '\n') - break; - } - - if (en > start && en <= end) { - for (en = end; en < clen; en++) - if (en > end && charAt(en - 1) == '\n') - break; - } - - if (st != ost || en != oen) - setSpan(mSpans[i], st, en, mSpanFlags[i]); - } - } - - moveGapTo(end); - - if (tbend - tbstart >= mGapLength + (end - start)) - resizeFor(mText.length - mGapLength + - tbend - tbstart - (end - start)); - - mGapStart += tbend - tbstart - (end - start); - mGapLength -= tbend - tbstart - (end - start); - - if (mGapLength < 1) - new Exception("mGapLength < 1").printStackTrace(); - - TextUtils.getChars(tb, tbstart, tbend, mText, start); - - if (tb instanceof Spanned) { - Spanned sp = (Spanned) tb; - Object[] spans = sp.getSpans(tbstart, tbend, Object.class); - - for (int i = 0; i < spans.length; i++) { - int st = sp.getSpanStart(spans[i]); - int en = sp.getSpanEnd(spans[i]); - - if (st < tbstart) - st = tbstart; - if (en > tbend) - en = tbend; - - if (getSpanStart(spans[i]) < 0) { - setSpan(false, spans[i], - st - tbstart + start, - en - tbstart + start, - sp.getSpanFlags(spans[i])); - } - } - } - - // no need for span fixup on pure insertion - if (tbend > tbstart && end - start == 0) { - if (notify) { - sendTextChange(recipients, start, end - start, tbend - tbstart); - sendTextHasChanged(recipients); - } - - return ret; - } - - boolean atend = (mGapStart + mGapLength == mText.length); - - for (int i = mSpanCount - 1; i >= 0; i--) { - if (mSpanStarts[i] >= start && - mSpanStarts[i] < mGapStart + mGapLength) { - int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; - - if (flag == POINT || (flag == PARAGRAPH && atend)) - mSpanStarts[i] = mGapStart + mGapLength; - else - mSpanStarts[i] = start; - } - - if (mSpanEnds[i] >= start && - mSpanEnds[i] < mGapStart + mGapLength) { - int flag = (mSpanFlags[i] & END_MASK); - - if (flag == POINT || (flag == PARAGRAPH && atend)) - mSpanEnds[i] = mGapStart + mGapLength; - else - mSpanEnds[i] = start; - } - - // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE - // XXX send notification on removal - - if (mSpanEnds[i] < mSpanStarts[i]) { - System.arraycopy(mSpans, i + 1, - mSpans, i, mSpanCount - (i + 1)); - System.arraycopy(mSpanStarts, i + 1, - mSpanStarts, i, mSpanCount - (i + 1)); - System.arraycopy(mSpanEnds, i + 1, - mSpanEnds, i, mSpanCount - (i + 1)); - System.arraycopy(mSpanFlags, i + 1, - mSpanFlags, i, mSpanCount - (i + 1)); - - mSpanCount--; - } - } - - if (notify) { - sendTextChange(recipients, start, end - start, tbend - tbstart); - sendTextHasChanged(recipients); - } - - return ret; - } - - // Documentation from interface - public SpannableStringBuilder replace(int start, int end, CharSequence tb) { - return replace(start, end, tb, 0, tb.length()); - } - - // Documentation from interface - public SpannableStringBuilder replace(final int start, final int end, - CharSequence tb, int tbstart, int tbend) { - int filtercount = mFilters.length; - for (int i = 0; i < filtercount; i++) { - CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, - this, start, end); - - if (repl != null) { - tb = repl; - tbstart = 0; - tbend = repl.length(); - } - } - - if (end == start && tbstart == tbend) { - return this; - } - - if (end == start || tbstart == tbend) { - change(start, end, tb, tbstart, tbend); - } else { - int selstart = Selection.getSelectionStart(this); - int selend = Selection.getSelectionEnd(this); - - // XXX just make the span fixups in change() do the right thing - // instead of this madness! - - checkRange("replace", start, end); - moveGapTo(end); - TextWatcher[] recipients; - - recipients = sendTextWillChange(start, end - start, - tbend - tbstart); - - int origlen = end - start; - - if (mGapLength < 2) - resizeFor(length() + 1); - - for (int i = mSpanCount - 1; i >= 0; i--) { - if (mSpanStarts[i] == mGapStart) - mSpanStarts[i]++; - - if (mSpanEnds[i] == mGapStart) - mSpanEnds[i]++; - } - - mText[mGapStart] = ' '; - mGapStart++; - mGapLength--; - - if (mGapLength < 1) - new Exception("mGapLength < 1").printStackTrace(); - - int oldlen = (end + 1) - start; - - int inserted = change(false, start + 1, start + 1, - tb, tbstart, tbend); - change(false, start, start + 1, "", 0, 0); - change(false, start + inserted, start + inserted + oldlen - 1, - "", 0, 0); - - /* - * Special case to keep the cursor in the same position - * if it was somewhere in the middle of the replaced region. - * If it was at the start or the end or crossing the whole - * replacement, it should already be where it belongs. - * TODO: Is there some more general mechanism that could - * accomplish this? - */ - if (selstart > start && selstart < end) { - long off = selstart - start; - - off = off * inserted / (end - start); - selstart = (int) off + start; - - setSpan(false, Selection.SELECTION_START, selstart, selstart, - Spanned.SPAN_POINT_POINT); - } - if (selend > start && selend < end) { - long off = selend - start; - - off = off * inserted / (end - start); - selend = (int) off + start; - - setSpan(false, Selection.SELECTION_END, selend, selend, - Spanned.SPAN_POINT_POINT); - } - - sendTextChange(recipients, start, origlen, inserted); - sendTextHasChanged(recipients); - } - return this; - } - - /** - * Mark the specified range of text with the specified object. - * The flags determine how the span will behave when text is - * inserted at the start or end of the span's range. - */ - public void setSpan(Object what, int start, int end, int flags) { - setSpan(true, what, start, end, flags); - } - - private void setSpan(boolean send, - Object what, int start, int end, int flags) { - int nstart = start; - int nend = end; - - checkRange("setSpan", start, end); - - if ((flags & START_MASK) == (PARAGRAPH << START_SHIFT)) { - if (start != 0 && start != length()) { - char c = charAt(start - 1); - - if (c != '\n') - throw new RuntimeException( - "PARAGRAPH span must start at paragraph boundary"); - } - } - - if ((flags & END_MASK) == PARAGRAPH) { - if (end != 0 && end != length()) { - char c = charAt(end - 1); - - if (c != '\n') - throw new RuntimeException( - "PARAGRAPH span must end at paragraph boundary"); - } - } - - if (start > mGapStart) - start += mGapLength; - else if (start == mGapStart) { - int flag = (flags & START_MASK) >> START_SHIFT; - - if (flag == POINT || (flag == PARAGRAPH && start == length())) - start += mGapLength; - } - - if (end > mGapStart) - end += mGapLength; - else if (end == mGapStart) { - int flag = (flags & END_MASK); - - if (flag == POINT || (flag == PARAGRAPH && end == length())) - end += mGapLength; - } - - int count = mSpanCount; - Object[] spans = mSpans; - - for (int i = 0; i < count; i++) { - if (spans[i] == what) { - int ostart = mSpanStarts[i]; - int oend = mSpanEnds[i]; - - if (ostart > mGapStart) - ostart -= mGapLength; - if (oend > mGapStart) - oend -= mGapLength; - - mSpanStarts[i] = start; - mSpanEnds[i] = end; - mSpanFlags[i] = flags; - - if (send) - sendSpanChanged(what, ostart, oend, nstart, nend); - - return; - } - } - - if (mSpanCount + 1 >= mSpans.length) { - int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1); - Object[] newspans = new Object[newsize]; - int[] newspanstarts = new int[newsize]; - int[] newspanends = new int[newsize]; - int[] newspanflags = new int[newsize]; - - System.arraycopy(mSpans, 0, newspans, 0, mSpanCount); - System.arraycopy(mSpanStarts, 0, newspanstarts, 0, mSpanCount); - System.arraycopy(mSpanEnds, 0, newspanends, 0, mSpanCount); - System.arraycopy(mSpanFlags, 0, newspanflags, 0, mSpanCount); - - mSpans = newspans; - mSpanStarts = newspanstarts; - mSpanEnds = newspanends; - mSpanFlags = newspanflags; - } - - mSpans[mSpanCount] = what; - mSpanStarts[mSpanCount] = start; - mSpanEnds[mSpanCount] = end; - mSpanFlags[mSpanCount] = flags; - mSpanCount++; - - if (send) - sendSpanAdded(what, nstart, nend); - } - - /** - * Remove the specified markup object from the buffer. - */ - public void removeSpan(Object what) { - for (int i = mSpanCount - 1; i >= 0; i--) { - if (mSpans[i] == what) { - int ostart = mSpanStarts[i]; - int oend = mSpanEnds[i]; - - if (ostart > mGapStart) - ostart -= mGapLength; - if (oend > mGapStart) - oend -= mGapLength; - - int count = mSpanCount - (i + 1); - - System.arraycopy(mSpans, i + 1, mSpans, i, count); - System.arraycopy(mSpanStarts, i + 1, mSpanStarts, i, count); - System.arraycopy(mSpanEnds, i + 1, mSpanEnds, i, count); - System.arraycopy(mSpanFlags, i + 1, mSpanFlags, i, count); - - mSpanCount--; - mSpans[mSpanCount] = null; - - sendSpanRemoved(what, ostart, oend); - return; - } - } - } - - /** - * Return the buffer offset of the beginning of the specified - * markup object, or -1 if it is not attached to this buffer. - */ - public int getSpanStart(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - int where = mSpanStarts[i]; - - if (where > mGapStart) - where -= mGapLength; - - return where; - } - } - - return -1; - } - - /** - * Return the buffer offset of the end of the specified - * markup object, or -1 if it is not attached to this buffer. - */ - public int getSpanEnd(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - int where = mSpanEnds[i]; - - if (where > mGapStart) - where -= mGapLength; - - return where; - } - } - - return -1; - } - - /** - * Return the flags of the end of the specified - * markup object, or 0 if it is not attached to this buffer. - */ - public int getSpanFlags(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - return mSpanFlags[i]; - } - } - - return 0; - } - - /** - * Return an array of the spans of the specified type that overlap - * the specified range of the buffer. The kind may be Object.class to get - * a list of all the spans regardless of type. - */ - public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) { - int spanCount = mSpanCount; - Object[] spans = mSpans; - int[] starts = mSpanStarts; - int[] ends = mSpanEnds; - int[] flags = mSpanFlags; - int gapstart = mGapStart; - int gaplen = mGapLength; - - int count = 0; - Object[] ret = null; - Object ret1 = null; - - for (int i = 0; i < spanCount; i++) { - int spanStart = starts[i]; - int spanEnd = ends[i]; - - if (spanStart > gapstart) { - spanStart -= gaplen; - } - if (spanEnd > gapstart) { - spanEnd -= gaplen; - } - - if (spanStart > queryEnd) { - continue; - } - if (spanEnd < queryStart) { - continue; - } - - if (spanStart != spanEnd && queryStart != queryEnd) { - if (spanStart == queryEnd) - continue; - if (spanEnd == queryStart) - continue; - } - - if (kind != null && !kind.isInstance(spans[i])) { - continue; - } - - if (count == 0) { - ret1 = spans[i]; - count++; - } else { - if (count == 1) { - ret = (Object[]) Array.newInstance(kind, spanCount - i + 1); - ret[0] = ret1; - } - - int prio = flags[i] & SPAN_PRIORITY; - if (prio != 0) { - int j; - - for (j = 0; j < count; j++) { - int p = getSpanFlags(ret[j]) & SPAN_PRIORITY; - - if (prio > p) { - break; - } - } - - System.arraycopy(ret, j, ret, j + 1, count - j); - ret[j] = spans[i]; - count++; - } else { - ret[count++] = spans[i]; - } - } - } - - if (count == 0) { - return (T[]) ArrayUtils.emptyArray(kind); - } - if (count == 1) { - ret = (Object[]) Array.newInstance(kind, 1); - ret[0] = ret1; - return (T[]) ret; - } - if (count == ret.length) { - return (T[]) ret; - } - - Object[] nret = (Object[]) Array.newInstance(kind, count); - System.arraycopy(ret, 0, nret, 0, count); - return (T[]) nret; - } - - /** - * Return the next offset after <code>start</code> but less than or - * equal to <code>limit</code> where a span of the specified type - * begins or ends. - */ - public int nextSpanTransition(int start, int limit, Class kind) { - int count = mSpanCount; - Object[] spans = mSpans; - int[] starts = mSpanStarts; - int[] ends = mSpanEnds; - int gapstart = mGapStart; - int gaplen = mGapLength; - - if (kind == null) { - kind = Object.class; - } - - for (int i = 0; i < count; i++) { - int st = starts[i]; - int en = ends[i]; - - if (st > gapstart) - st -= gaplen; - if (en > gapstart) - en -= gaplen; - - if (st > start && st < limit && kind.isInstance(spans[i])) - limit = st; - if (en > start && en < limit && kind.isInstance(spans[i])) - limit = en; - } - - return limit; - } - - /** - * Return a new CharSequence containing a copy of the specified - * range of this buffer, including the overlapping spans. - */ - public CharSequence subSequence(int start, int end) { - return new SpannableStringBuilder(this, start, end); - } - - /** - * Copy the specified range of chars from this buffer into the - * specified array, beginning at the specified offset. - */ - public void getChars(int start, int end, char[] dest, int destoff) { - checkRange("getChars", start, end); - - if (end <= mGapStart) { - System.arraycopy(mText, start, dest, destoff, end - start); - } else if (start >= mGapStart) { - System.arraycopy(mText, start + mGapLength, - dest, destoff, end - start); - } else { - System.arraycopy(mText, start, dest, destoff, mGapStart - start); - System.arraycopy(mText, mGapStart + mGapLength, - dest, destoff + (mGapStart - start), - end - mGapStart); - } - } - - /** - * Return a String containing a copy of the chars in this buffer. - */ - public String toString() { - int len = length(); - char[] buf = new char[len]; - - getChars(0, len, buf, 0); - return new String(buf); - } - - private TextWatcher[] sendTextWillChange(int start, int before, int after) { - TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].beforeTextChanged(this, start, before, after); - } - - return recip; - } - - private void sendTextChange(TextWatcher[] recip, int start, int before, - int after) { - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onTextChanged(this, start, before, after); - } - } - - private void sendTextHasChanged(TextWatcher[] recip) { - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].afterTextChanged(this); - } - } - - private void sendSpanAdded(Object what, int start, int end) { - SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onSpanAdded(this, what, start, end); - } - } - - private void sendSpanRemoved(Object what, int start, int end) { - SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onSpanRemoved(this, what, start, end); - } - } - - private void sendSpanChanged(Object what, int s, int e, int st, int en) { - SpanWatcher[] recip = getSpans(Math.min(s, st), Math.max(e, en), - SpanWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onSpanChanged(this, what, s, e, st, en); - } - } - - private static String region(int start, int end) { - return "(" + start + " ... " + end + ")"; - } - - private void checkRange(final String operation, int start, int end) { - if (end < start) { - throw new IndexOutOfBoundsException(operation + " " + - region(start, end) + - " has end before start"); - } - - int len = length(); - - if (start > len || end > len) { - throw new IndexOutOfBoundsException(operation + " " + - region(start, end) + - " ends beyond length " + len); - } - - if (start < 0 || end < 0) { - throw new IndexOutOfBoundsException(operation + " " + - region(start, end) + - " starts before 0"); - } - } - - private boolean isprint(char c) { // XXX - if (c >= ' ' && c <= '~') - return true; - else - return false; - } - -/* - private static final int startFlag(int flag) { - return (flag >> 4) & 0x0F; - } - - private static final int endFlag(int flag) { - return flag & 0x0F; - } - - public void dump() { // XXX - for (int i = 0; i < mGapStart; i++) { - System.out.print('|'); - System.out.print(' '); - System.out.print(isprint(mText[i]) ? mText[i] : '.'); - System.out.print(' '); - } - - for (int i = mGapStart; i < mGapStart + mGapLength; i++) { - System.out.print('|'); - System.out.print('('); - System.out.print(isprint(mText[i]) ? mText[i] : '.'); - System.out.print(')'); - } - - for (int i = mGapStart + mGapLength; i < mText.length; i++) { - System.out.print('|'); - System.out.print(' '); - System.out.print(isprint(mText[i]) ? mText[i] : '.'); - System.out.print(' '); - } - - System.out.print('\n'); - - for (int i = 0; i < mText.length + 1; i++) { - int found = 0; - int wfound = 0; - - for (int j = 0; j < mSpanCount; j++) { - if (mSpanStarts[j] == i) { - found = 1; - wfound = j; - break; - } - - if (mSpanEnds[j] == i) { - found = 2; - wfound = j; - break; - } - } - - if (found == 1) { - if (startFlag(mSpanFlags[wfound]) == MARK) - System.out.print("( "); - if (startFlag(mSpanFlags[wfound]) == PARAGRAPH) - System.out.print("< "); - else - System.out.print("[ "); - } else if (found == 2) { - if (endFlag(mSpanFlags[wfound]) == POINT) - System.out.print(") "); - if (endFlag(mSpanFlags[wfound]) == PARAGRAPH) - System.out.print("> "); - else - System.out.print("] "); - } else { - System.out.print(" "); - } - } - - System.out.print("\n"); - } -*/ - - /** - * Don't call this yourself -- exists for Canvas to use internally. - * {@hide} - */ - public void drawText(Canvas c, int start, int end, - float x, float y, Paint p) { - checkRange("drawText", start, end); - - if (end <= mGapStart) { - c.drawText(mText, start, end - start, x, y, p); - } else if (start >= mGapStart) { - c.drawText(mText, start + mGapLength, end - start, x, y, p); - } else { - char[] buf = TextUtils.obtain(end - start); - - getChars(start, end, buf, 0); - c.drawText(buf, 0, end - start, x, y, p); - TextUtils.recycle(buf); - } - } - - /** - * Don't call this yourself -- exists for Paint to use internally. - * {@hide} - */ - public float measureText(int start, int end, Paint p) { - checkRange("measureText", start, end); - - float ret; - - if (end <= mGapStart) { - ret = p.measureText(mText, start, end - start); - } else if (start >= mGapStart) { - ret = p.measureText(mText, start + mGapLength, end - start); - } else { - char[] buf = TextUtils.obtain(end - start); - - getChars(start, end, buf, 0); - ret = p.measureText(buf, 0, end - start); - TextUtils.recycle(buf); - } - - return ret; - } - - /** - * Don't call this yourself -- exists for Paint to use internally. - * {@hide} - */ - public int getTextWidths(int start, int end, float[] widths, Paint p) { - checkRange("getTextWidths", start, end); - - int ret; - - if (end <= mGapStart) { - ret = p.getTextWidths(mText, start, end - start, widths); - } else if (start >= mGapStart) { - ret = p.getTextWidths(mText, start + mGapLength, end - start, - widths); - } else { - char[] buf = TextUtils.obtain(end - start); - - getChars(start, end, buf, 0); - ret = p.getTextWidths(buf, 0, end - start, widths); - TextUtils.recycle(buf); - } - - return ret; - } - - // Documentation from interface - public void setFilters(InputFilter[] filters) { - if (filters == null) { - throw new IllegalArgumentException(); - } - - mFilters = filters; - } - - // Documentation from interface - public InputFilter[] getFilters() { - return mFilters; - } - - private static final InputFilter[] NO_FILTERS = new InputFilter[0]; - private InputFilter[] mFilters = NO_FILTERS; - - private char[] mText; - private int mGapStart; - private int mGapLength; - - private Object[] mSpans; - private int[] mSpanStarts; - private int[] mSpanEnds; - private int[] mSpanFlags; - private int mSpanCount; - - private static final int MARK = 1; - private static final int POINT = 2; - private static final int PARAGRAPH = 3; - - private static final int START_MASK = 0xF0; - private static final int END_MASK = 0x0F; - private static final int START_SHIFT = 4; -} diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java deleted file mode 100644 index 0412285..0000000 --- a/core/java/android/text/SpannableStringInternal.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import com.android.internal.util.ArrayUtils; - -import java.lang.reflect.Array; - -/* package */ abstract class SpannableStringInternal -{ - /* package */ SpannableStringInternal(CharSequence source, - int start, int end) { - if (start == 0 && end == source.length()) - mText = source.toString(); - else - mText = source.toString().substring(start, end); - - int initial = ArrayUtils.idealIntArraySize(0); - mSpans = new Object[initial]; - mSpanData = new int[initial * 3]; - - if (source instanceof Spanned) { - Spanned sp = (Spanned) source; - Object[] spans = sp.getSpans(start, end, Object.class); - - for (int i = 0; i < spans.length; i++) { - int st = sp.getSpanStart(spans[i]); - int en = sp.getSpanEnd(spans[i]); - int fl = sp.getSpanFlags(spans[i]); - - if (st < start) - st = start; - if (en > end) - en = end; - - setSpan(spans[i], st - start, en - start, fl); - } - } - } - - public final int length() { - return mText.length(); - } - - public final char charAt(int i) { - return mText.charAt(i); - } - - public final String toString() { - return mText; - } - - /* subclasses must do subSequence() to preserve type */ - - public final void getChars(int start, int end, char[] dest, int off) { - mText.getChars(start, end, dest, off); - } - - /* package */ void setSpan(Object what, int start, int end, int flags) { - int nstart = start; - int nend = end; - - checkRange("setSpan", start, end); - - if ((flags & Spannable.SPAN_PARAGRAPH) == Spannable.SPAN_PARAGRAPH) { - if (start != 0 && start != length()) { - char c = charAt(start - 1); - - if (c != '\n') - throw new RuntimeException( - "PARAGRAPH span must start at paragraph boundary" + - " (" + start + " follows " + c + ")"); - } - - if (end != 0 && end != length()) { - char c = charAt(end - 1); - - if (c != '\n') - throw new RuntimeException( - "PARAGRAPH span must end at paragraph boundary" + - " (" + end + " follows " + c + ")"); - } - } - - int count = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - - for (int i = 0; i < count; i++) { - if (spans[i] == what) { - int ostart = data[i * COLUMNS + START]; - int oend = data[i * COLUMNS + END]; - - data[i * COLUMNS + START] = start; - data[i * COLUMNS + END] = end; - data[i * COLUMNS + FLAGS] = flags; - - sendSpanChanged(what, ostart, oend, nstart, nend); - return; - } - } - - if (mSpanCount + 1 >= mSpans.length) { - int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1); - Object[] newtags = new Object[newsize]; - int[] newdata = new int[newsize * 3]; - - System.arraycopy(mSpans, 0, newtags, 0, mSpanCount); - System.arraycopy(mSpanData, 0, newdata, 0, mSpanCount * 3); - - mSpans = newtags; - mSpanData = newdata; - } - - mSpans[mSpanCount] = what; - mSpanData[mSpanCount * COLUMNS + START] = start; - mSpanData[mSpanCount * COLUMNS + END] = end; - mSpanData[mSpanCount * COLUMNS + FLAGS] = flags; - mSpanCount++; - - if (this instanceof Spannable) - sendSpanAdded(what, nstart, nend); - } - - /* package */ void removeSpan(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - int ostart = data[i * COLUMNS + START]; - int oend = data[i * COLUMNS + END]; - - int c = count - (i + 1); - - System.arraycopy(spans, i + 1, spans, i, c); - System.arraycopy(data, (i + 1) * COLUMNS, - data, i * COLUMNS, c * COLUMNS); - - mSpanCount--; - - sendSpanRemoved(what, ostart, oend); - return; - } - } - } - - public int getSpanStart(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - return data[i * COLUMNS + START]; - } - } - - return -1; - } - - public int getSpanEnd(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - return data[i * COLUMNS + END]; - } - } - - return -1; - } - - public int getSpanFlags(Object what) { - int count = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - - for (int i = count - 1; i >= 0; i--) { - if (spans[i] == what) { - return data[i * COLUMNS + FLAGS]; - } - } - - return 0; - } - - public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) { - int count = 0; - - int spanCount = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - Object[] ret = null; - Object ret1 = null; - - for (int i = 0; i < spanCount; i++) { - int spanStart = data[i * COLUMNS + START]; - int spanEnd = data[i * COLUMNS + END]; - - if (spanStart > queryEnd) { - continue; - } - if (spanEnd < queryStart) { - continue; - } - - if (spanStart != spanEnd && queryStart != queryEnd) { - if (spanStart == queryEnd) { - continue; - } - if (spanEnd == queryStart) { - continue; - } - } - - if (kind != null && !kind.isInstance(spans[i])) { - continue; - } - - if (count == 0) { - ret1 = spans[i]; - count++; - } else { - if (count == 1) { - ret = (Object[]) Array.newInstance(kind, spanCount - i + 1); - ret[0] = ret1; - } - - int prio = data[i * COLUMNS + FLAGS] & Spanned.SPAN_PRIORITY; - if (prio != 0) { - int j; - - for (j = 0; j < count; j++) { - int p = getSpanFlags(ret[j]) & Spanned.SPAN_PRIORITY; - - if (prio > p) { - break; - } - } - - System.arraycopy(ret, j, ret, j + 1, count - j); - ret[j] = spans[i]; - count++; - } else { - ret[count++] = spans[i]; - } - } - } - - if (count == 0) { - return (T[]) ArrayUtils.emptyArray(kind); - } - if (count == 1) { - ret = (Object[]) Array.newInstance(kind, 1); - ret[0] = ret1; - return (T[]) ret; - } - if (count == ret.length) { - return (T[]) ret; - } - - Object[] nret = (Object[]) Array.newInstance(kind, count); - System.arraycopy(ret, 0, nret, 0, count); - return (T[]) nret; - } - - public int nextSpanTransition(int start, int limit, Class kind) { - int count = mSpanCount; - Object[] spans = mSpans; - int[] data = mSpanData; - - if (kind == null) { - kind = Object.class; - } - - for (int i = 0; i < count; i++) { - int st = data[i * COLUMNS + START]; - int en = data[i * COLUMNS + END]; - - if (st > start && st < limit && kind.isInstance(spans[i])) - limit = st; - if (en > start && en < limit && kind.isInstance(spans[i])) - limit = en; - } - - return limit; - } - - private void sendSpanAdded(Object what, int start, int end) { - SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onSpanAdded((Spannable) this, what, start, end); - } - } - - private void sendSpanRemoved(Object what, int start, int end) { - SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onSpanRemoved((Spannable) this, what, start, end); - } - } - - private void sendSpanChanged(Object what, int s, int e, int st, int en) { - SpanWatcher[] recip = getSpans(Math.min(s, st), Math.max(e, en), - SpanWatcher.class); - int n = recip.length; - - for (int i = 0; i < n; i++) { - recip[i].onSpanChanged((Spannable) this, what, s, e, st, en); - } - } - - private static String region(int start, int end) { - return "(" + start + " ... " + end + ")"; - } - - private void checkRange(final String operation, int start, int end) { - if (end < start) { - throw new IndexOutOfBoundsException(operation + " " + - region(start, end) + - " has end before start"); - } - - int len = length(); - - if (start > len || end > len) { - throw new IndexOutOfBoundsException(operation + " " + - region(start, end) + - " ends beyond length " + len); - } - - if (start < 0 || end < 0) { - throw new IndexOutOfBoundsException(operation + " " + - region(start, end) + - " starts before 0"); - } - } - - private String mText; - private Object[] mSpans; - private int[] mSpanData; - private int mSpanCount; - - /* package */ static final Object[] EMPTY = new Object[0]; - - private static final int START = 0; - private static final int END = 1; - private static final int FLAGS = 2; - private static final int COLUMNS = 3; -} diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java deleted file mode 100644 index 154497d..0000000 --- a/core/java/android/text/Spanned.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * This is the interface for text that has markup objects attached to - * ranges of it. Not all text classes have mutable markup or text; - * see {@link Spannable} for mutable markup and {@link Editable} for - * mutable text. - */ -public interface Spanned -extends CharSequence -{ - /** - * Bitmask of bits that are relevent for controlling point/mark behavior - * of spans. - */ - public static final int SPAN_POINT_MARK_MASK = 0x33; - - /** - * 0-length spans with type SPAN_MARK_MARK behave like text marks: - * they remain at their original offset when text is inserted - * at that offset. - */ - public static final int SPAN_MARK_MARK = 0x11; - /** - * SPAN_MARK_POINT is a synonym for {@link #SPAN_INCLUSIVE_INCLUSIVE}. - */ - public static final int SPAN_MARK_POINT = 0x12; - /** - * SPAN_POINT_MARK is a synonym for {@link #SPAN_EXCLUSIVE_EXCLUSIVE}. - */ - public static final int SPAN_POINT_MARK = 0x21; - - /** - * 0-length spans with type SPAN_POINT_POINT behave like cursors: - * they are pushed forward by the length of the insertion when text - * is inserted at their offset. - */ - public static final int SPAN_POINT_POINT = 0x22; - - /** - * SPAN_PARAGRAPH behaves like SPAN_INCLUSIVE_EXCLUSIVE - * (SPAN_MARK_MARK), except that if either end of the span is - * at the end of the buffer, that end behaves like _POINT - * instead (so SPAN_INCLUSIVE_INCLUSIVE if it starts in the - * middle and ends at the end, or SPAN_EXCLUSIVE_INCLUSIVE - * if it both starts and ends at the end). - * <p> - * Its endpoints must be the start or end of the buffer or - * immediately after a \n character, and if the \n - * that anchors it is deleted, the endpoint is pulled to the - * next \n that follows in the buffer (or to the end of - * the buffer). - */ - public static final int SPAN_PARAGRAPH = 0x33; - - /** - * Non-0-length spans of type SPAN_INCLUSIVE_EXCLUSIVE expand - * to include text inserted at their starting point but not at their - * ending point. When 0-length, they behave like marks. - */ - public static final int SPAN_INCLUSIVE_EXCLUSIVE = SPAN_MARK_MARK; - - /** - * Spans of type SPAN_INCLUSIVE_INCLUSIVE expand - * to include text inserted at either their starting or ending point. - */ - public static final int SPAN_INCLUSIVE_INCLUSIVE = SPAN_MARK_POINT; - - /** - * Spans of type SPAN_EXCLUSIVE_EXCLUSIVE do not expand - * to include text inserted at either their starting or ending point. - * They can never have a length of 0 and are automatically removed - * from the buffer if all the text they cover is removed. - */ - public static final int SPAN_EXCLUSIVE_EXCLUSIVE = SPAN_POINT_MARK; - - /** - * Non-0-length spans of type SPAN_INCLUSIVE_EXCLUSIVE expand - * to include text inserted at their ending point but not at their - * starting point. When 0-length, they behave like points. - */ - public static final int SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_POINT; - - /** - * This flag is set on spans that are being used to apply temporary - * styling information on the composing text of an input method, so that - * they can be found and removed when the composing text is being - * replaced. - */ - public static final int SPAN_COMPOSING = 0x100; - - /** - * This flag will be set for intermediate span changes, meaning there - * is guaranteed to be another change following it. Typically it is - * used for {@link Selection} which automatically uses this with the first - * offset it sets when updating the selection. - */ - public static final int SPAN_INTERMEDIATE = 0x200; - - /** - * The bits numbered SPAN_USER_SHIFT and above are available - * for callers to use to store scalar data associated with their - * span object. - */ - public static final int SPAN_USER_SHIFT = 24; - /** - * The bits specified by the SPAN_USER bitfield are available - * for callers to use to store scalar data associated with their - * span object. - */ - public static final int SPAN_USER = 0xFFFFFFFF << SPAN_USER_SHIFT; - - /** - * The bits numbered just above SPAN_PRIORITY_SHIFT determine the order - * of change notifications -- higher numbers go first. You probably - * don't need to set this; it is used so that when text changes, the - * text layout gets the chance to update itself before any other - * callbacks can inquire about the layout of the text. - */ - public static final int SPAN_PRIORITY_SHIFT = 16; - /** - * The bits specified by the SPAN_PRIORITY bitmap determine the order - * of change notifications -- higher numbers go first. You probably - * don't need to set this; it is used so that when text changes, the - * text layout gets the chance to update itself before any other - * callbacks can inquire about the layout of the text. - */ - public static final int SPAN_PRIORITY = 0xFF << SPAN_PRIORITY_SHIFT; - - /** - * Return an array of the markup objects attached to the specified - * slice of this CharSequence and whose type is the specified type - * or a subclass of it. Specify Object.class for the type if you - * want all the objects regardless of type. - */ - public <T> T[] getSpans(int start, int end, Class<T> type); - - /** - * Return the beginning of the range of text to which the specified - * markup object is attached, or -1 if the object is not attached. - */ - public int getSpanStart(Object tag); - - /** - * Return the end of the range of text to which the specified - * markup object is attached, or -1 if the object is not attached. - */ - public int getSpanEnd(Object tag); - - /** - * Return the flags that were specified when {@link Spannable#setSpan} was - * used to attach the specified markup object, or 0 if the specified - * object has not been attached. - */ - public int getSpanFlags(Object tag); - - /** - * Return the first offset greater than or equal to <code>start</code> - * where a markup object of class <code>type</code> begins or ends, - * or <code>limit</code> if there are no starts or ends greater than or - * equal to <code>start</code> but less than <code>limit</code>. Specify - * <code>null</code> or Object.class for the type if you want every - * transition regardless of type. - */ - public int nextSpanTransition(int start, int limit, Class type); -} diff --git a/core/java/android/text/SpannedString.java b/core/java/android/text/SpannedString.java deleted file mode 100644 index afed221..0000000 --- a/core/java/android/text/SpannedString.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - - -/** - * This is the class for text whose content and markup are immutable. - * For mutable markup, see {@link SpannableString}; for mutable text, - * see {@link SpannableStringBuilder}. - */ -public final class SpannedString -extends SpannableStringInternal -implements CharSequence, GetChars, Spanned -{ - public SpannedString(CharSequence source) { - super(source, 0, source.length()); - } - - private SpannedString(CharSequence source, int start, int end) { - super(source, start, end); - } - - public CharSequence subSequence(int start, int end) { - return new SpannedString(this, start, end); - } - - public static SpannedString valueOf(CharSequence source) { - if (source instanceof SpannedString) { - return (SpannedString) source; - } else { - return new SpannedString(source); - } - } -} diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java deleted file mode 100644 index 0fef40b..0000000 --- a/core/java/android/text/StaticLayout.java +++ /dev/null @@ -1,1195 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Paint; -import com.android.internal.util.ArrayUtils; -import android.util.Log; -import android.text.style.LeadingMarginSpan; -import android.text.style.LineHeightSpan; -import android.text.style.MetricAffectingSpan; -import android.text.style.ReplacementSpan; - -/** - * StaticLayout is a Layout for text that will not be edited after it - * is laid out. Use {@link DynamicLayout} for text that may change. - * <p>This is used by widgets to control text layout. You should not need - * to use this class directly unless you are implementing your own widget - * or custom display object, or would be tempted to call - * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) - * Canvas.drawText()} directly.</p> - */ -public class -StaticLayout -extends Layout -{ - public StaticLayout(CharSequence source, TextPaint paint, - int width, - Alignment align, float spacingmult, float spacingadd, - boolean includepad) { - this(source, 0, source.length(), paint, width, align, - spacingmult, spacingadd, includepad); - } - - public StaticLayout(CharSequence source, int bufstart, int bufend, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - boolean includepad) { - this(source, bufstart, bufend, paint, outerwidth, align, - spacingmult, spacingadd, includepad, null, 0); - } - - public StaticLayout(CharSequence source, int bufstart, int bufend, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { - super((ellipsize == null) - ? source - : (source instanceof Spanned) - ? new SpannedEllipsizer(source) - : new Ellipsizer(source), - paint, outerwidth, align, spacingmult, spacingadd); - - /* - * This is annoying, but we can't refer to the layout until - * superclass construction is finished, and the superclass - * constructor wants the reference to the display text. - * - * This will break if the superclass constructor ever actually - * cares about the content instead of just holding the reference. - */ - if (ellipsize != null) { - Ellipsizer e = (Ellipsizer) getText(); - - e.mLayout = this; - e.mWidth = ellipsizedWidth; - e.mMethod = ellipsize; - mEllipsizedWidth = ellipsizedWidth; - - mColumns = COLUMNS_ELLIPSIZE; - } else { - mColumns = COLUMNS_NORMAL; - mEllipsizedWidth = outerwidth; - } - - mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)]; - mLineDirections = new Directions[ - ArrayUtils.idealIntArraySize(2 * mColumns)]; - - generate(source, bufstart, bufend, paint, outerwidth, align, - spacingmult, spacingadd, includepad, includepad, - ellipsize != null, ellipsizedWidth, ellipsize); - - mChdirs = null; - mChs = null; - mWidths = null; - mFontMetricsInt = null; - } - - /* package */ StaticLayout(boolean ellipsize) { - super(null, null, 0, null, 0, 0); - - mColumns = COLUMNS_ELLIPSIZE; - mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)]; - mLineDirections = new Directions[ - ArrayUtils.idealIntArraySize(2 * mColumns)]; - } - - /* package */ void generate(CharSequence source, int bufstart, int bufend, - TextPaint paint, int outerwidth, - Alignment align, - float spacingmult, float spacingadd, - boolean includepad, boolean trackpad, - boolean breakOnlyAtSpaces, - float ellipsizedWidth, TextUtils.TruncateAt where) { - mLineCount = 0; - - int v = 0; - boolean needMultiply = (spacingmult != 1 || spacingadd != 0); - - Paint.FontMetricsInt fm = mFontMetricsInt; - int[] choosehtv = null; - - int end = TextUtils.indexOf(source, '\n', bufstart, bufend); - int bufsiz = end >= 0 ? end - bufstart : bufend - bufstart; - boolean first = true; - - if (mChdirs == null) { - mChdirs = new byte[ArrayUtils.idealByteArraySize(bufsiz + 1)]; - mChs = new char[ArrayUtils.idealCharArraySize(bufsiz + 1)]; - mWidths = new float[ArrayUtils.idealIntArraySize((bufsiz + 1) * 2)]; - } - - byte[] chdirs = mChdirs; - char[] chs = mChs; - float[] widths = mWidths; - - AlteredCharSequence alter = null; - Spanned spanned = null; - - if (source instanceof Spanned) - spanned = (Spanned) source; - - int DEFAULT_DIR = DIR_LEFT_TO_RIGHT; // XXX - - for (int start = bufstart; start <= bufend; start = end) { - if (first) - first = false; - else - end = TextUtils.indexOf(source, '\n', start, bufend); - - if (end < 0) - end = bufend; - else - end++; - - int firstwidth = outerwidth; - int restwidth = outerwidth; - - LineHeightSpan[] chooseht = null; - - if (spanned != null) { - LeadingMarginSpan[] sp; - - sp = spanned.getSpans(start, end, LeadingMarginSpan.class); - for (int i = 0; i < sp.length; i++) { - firstwidth -= sp[i].getLeadingMargin(true); - restwidth -= sp[i].getLeadingMargin(false); - } - - chooseht = spanned.getSpans(start, end, LineHeightSpan.class); - - if (chooseht.length != 0) { - if (choosehtv == null || - choosehtv.length < chooseht.length) { - choosehtv = new int[ArrayUtils.idealIntArraySize( - chooseht.length)]; - } - - for (int i = 0; i < chooseht.length; i++) { - int o = spanned.getSpanStart(chooseht[i]); - - if (o < start) { - // starts in this layout, before the - // current paragraph - - choosehtv[i] = getLineTop(getLineForOffset(o)); - } else { - // starts in this paragraph - - choosehtv[i] = v; - } - } - } - } - - if (end - start > chdirs.length) { - chdirs = new byte[ArrayUtils.idealByteArraySize(end - start)]; - mChdirs = chdirs; - } - if (end - start > chs.length) { - chs = new char[ArrayUtils.idealCharArraySize(end - start)]; - mChs = chs; - } - if ((end - start) * 2 > widths.length) { - widths = new float[ArrayUtils.idealIntArraySize((end - start) * 2)]; - mWidths = widths; - } - - TextUtils.getChars(source, start, end, chs, 0); - final int n = end - start; - - boolean easy = true; - boolean altered = false; - int dir = DEFAULT_DIR; // XXX - - for (int i = 0; i < n; i++) { - if (chs[i] >= FIRST_RIGHT_TO_LEFT) { - easy = false; - break; - } - } - - if (!easy) { - AndroidCharacter.getDirectionalities(chs, chdirs, end - start); - - /* - * Determine primary paragraph direction - */ - - for (int j = start; j < end; j++) { - int d = chdirs[j - start]; - - if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) { - dir = DIR_LEFT_TO_RIGHT; - break; - } - if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) { - dir = DIR_RIGHT_TO_LEFT; - break; - } - } - - /* - * XXX Explicit overrides should go here - */ - - /* - * Weak type resolution - */ - - final byte SOR = dir == DIR_LEFT_TO_RIGHT ? - Character.DIRECTIONALITY_LEFT_TO_RIGHT : - Character.DIRECTIONALITY_RIGHT_TO_LEFT; - - // dump(chdirs, n, "initial"); - - // W1 non spacing marks - for (int j = 0; j < n; j++) { - if (chdirs[j] == Character.NON_SPACING_MARK) { - if (j == 0) - chdirs[j] = SOR; - else - chdirs[j] = chdirs[j - 1]; - } - } - - // dump(chdirs, n, "W1"); - - // W2 european numbers - byte cur = SOR; - for (int j = 0; j < n; j++) { - byte d = chdirs[j]; - - if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT || - d == Character.DIRECTIONALITY_RIGHT_TO_LEFT || - d == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) - cur = d; - else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) { - if (cur == - Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) - chdirs[j] = Character.DIRECTIONALITY_ARABIC_NUMBER; - } - } - - // dump(chdirs, n, "W2"); - - // W3 arabic letters - for (int j = 0; j < n; j++) { - if (chdirs[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) - chdirs[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT; - } - - // dump(chdirs, n, "W3"); - - // W4 single separator between numbers - for (int j = 1; j < n - 1; j++) { - byte d = chdirs[j]; - byte prev = chdirs[j - 1]; - byte next = chdirs[j + 1]; - - if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) { - if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER && - next == Character.DIRECTIONALITY_EUROPEAN_NUMBER) - chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER; - } else if (d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR) { - if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER && - next == Character.DIRECTIONALITY_EUROPEAN_NUMBER) - chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER; - if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER && - next == Character.DIRECTIONALITY_ARABIC_NUMBER) - chdirs[j] = Character.DIRECTIONALITY_ARABIC_NUMBER; - } - } - - // dump(chdirs, n, "W4"); - - // W5 european number terminators - boolean adjacent = false; - for (int j = 0; j < n; j++) { - byte d = chdirs[j]; - - if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) - adjacent = true; - else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR && adjacent) - chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER; - else - adjacent = false; - } - - //dump(chdirs, n, "W5"); - - // W5 european number terminators part 2, - // W6 separators and terminators - adjacent = false; - for (int j = n - 1; j >= 0; j--) { - byte d = chdirs[j]; - - if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) - adjacent = true; - else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR) { - if (adjacent) - chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER; - else - chdirs[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS; - } - else { - adjacent = false; - - if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR || - d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR || - d == Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR || - d == Character.DIRECTIONALITY_SEGMENT_SEPARATOR) - chdirs[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS; - } - } - - // dump(chdirs, n, "W6"); - - // W7 strong direction of european numbers - cur = SOR; - for (int j = 0; j < n; j++) { - byte d = chdirs[j]; - - if (d == SOR || - d == Character.DIRECTIONALITY_LEFT_TO_RIGHT || - d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) - cur = d; - - if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) - chdirs[j] = cur; - } - - // dump(chdirs, n, "W7"); - - // N1, N2 neutrals - cur = SOR; - for (int j = 0; j < n; j++) { - byte d = chdirs[j]; - - if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT || - d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) { - cur = d; - } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER || - d == Character.DIRECTIONALITY_ARABIC_NUMBER) { - cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT; - } else { - byte dd = SOR; - int k; - - for (k = j + 1; k < n; k++) { - dd = chdirs[k]; - - if (dd == Character.DIRECTIONALITY_LEFT_TO_RIGHT || - dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) { - break; - } - if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER || - dd == Character.DIRECTIONALITY_ARABIC_NUMBER) { - dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT; - break; - } - } - - for (int y = j; y < k; y++) { - if (dd == cur) - chdirs[y] = cur; - else - chdirs[y] = SOR; - } - - j = k - 1; - } - } - - // dump(chdirs, n, "final"); - - // extra: enforce that all tabs go the primary direction - - for (int j = 0; j < n; j++) { - if (chs[j] == '\t') - chdirs[j] = SOR; - } - - // extra: enforce that object replacements go to the - // primary direction - // and that none of the underlying characters are treated - // as viable breakpoints - - if (source instanceof Spanned) { - Spanned sp = (Spanned) source; - ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class); - - for (int y = 0; y < spans.length; y++) { - int a = sp.getSpanStart(spans[y]); - int b = sp.getSpanEnd(spans[y]); - - for (int x = a; x < b; x++) { - chdirs[x - start] = SOR; - chs[x - start] = '\uFFFC'; - } - } - } - - // Do mirroring for right-to-left segments - - for (int i = 0; i < n; i++) { - if (chdirs[i] == Character.DIRECTIONALITY_RIGHT_TO_LEFT) { - int j; - - for (j = i; j < n; j++) { - if (chdirs[j] != - Character.DIRECTIONALITY_RIGHT_TO_LEFT) - break; - } - - if (AndroidCharacter.mirror(chs, i, j - i)) - altered = true; - - i = j - 1; - } - } - } - - CharSequence sub; - - if (altered) { - if (alter == null) - alter = AlteredCharSequence.make(source, chs, start, end); - else - alter.update(chs, start, end); - - sub = alter; - } else { - sub = source; - } - - int width = firstwidth; - - float w = 0; - int here = start; - - int ok = start; - float okwidth = w; - int okascent = 0, okdescent = 0, oktop = 0, okbottom = 0; - - int fit = start; - float fitwidth = w; - int fitascent = 0, fitdescent = 0, fittop = 0, fitbottom = 0; - - boolean tab = false; - - int next; - for (int i = start; i < end; i = next) { - if (spanned == null) - next = end; - else - next = spanned.nextSpanTransition(i, end, - MetricAffectingSpan. - class); - - if (spanned == null) { - paint.getTextWidths(sub, i, next, widths); - System.arraycopy(widths, 0, widths, - end - start + (i - start), next - i); - - paint.getFontMetricsInt(fm); - } else { - mWorkPaint.baselineShift = 0; - - Styled.getTextWidths(paint, mWorkPaint, - spanned, i, next, - widths, fm); - System.arraycopy(widths, 0, widths, - end - start + (i - start), next - i); - - if (mWorkPaint.baselineShift < 0) { - fm.ascent += mWorkPaint.baselineShift; - fm.top += mWorkPaint.baselineShift; - } else { - fm.descent += mWorkPaint.baselineShift; - fm.bottom += mWorkPaint.baselineShift; - } - } - - int fmtop = fm.top; - int fmbottom = fm.bottom; - int fmascent = fm.ascent; - int fmdescent = fm.descent; - - if (false) { - StringBuilder sb = new StringBuilder(); - for (int j = i; j < next; j++) { - sb.append(widths[j - start + (end - start)]); - sb.append(' '); - } - - Log.e("text", sb.toString()); - } - - for (int j = i; j < next; j++) { - char c = chs[j - start]; - float before = w; - - switch (c) { - case '\n': - break; - - case '\t': - w = Layout.nextTab(sub, start, end, w, null); - tab = true; - break; - - default: - w += widths[j - start + (end - start)]; - } - - // Log.e("text", "was " + before + " now " + w + " after " + c + " within " + width); - - if (w <= width) { - fitwidth = w; - fit = j + 1; - - if (fmtop < fittop) - fittop = fmtop; - if (fmascent < fitascent) - fitascent = fmascent; - if (fmdescent > fitdescent) - fitdescent = fmdescent; - if (fmbottom > fitbottom) - fitbottom = fmbottom; - - /* - * From the Unicode Line Breaking Algorithm: - * (at least approximately) - * - * .,:; are class IS: breakpoints - * except when adjacent to digits - * / is class SY: a breakpoint - * except when followed by a digit. - * - is class HY: a breakpoint - * except when followed by a digit. - * - * Ideographs are class ID: breakpoints when adjacent. - */ - - if (c == ' ' || c == '\t' || - ((c == '.' || c == ',' || c == ':' || c == ';') && - (j - 1 < here || !Character.isDigit(chs[j - 1 - start])) && - (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) || - ((c == '/' || c == '-') && - (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) || - (c >= FIRST_CJK && isIdeographic(c) && - j + 1 < next && isIdeographic(chs[j + 1 - start]))) { - okwidth = w; - ok = j + 1; - - if (fittop < oktop) - oktop = fittop; - if (fitascent < okascent) - okascent = fitascent; - if (fitdescent > okdescent) - okdescent = fitdescent; - if (fitbottom > okbottom) - okbottom = fitbottom; - } - } else if (breakOnlyAtSpaces) { - if (ok != here) { - // Log.e("text", "output ok " + here + " to " +ok); - - while (ok < next && chs[ok - start] == ' ') { - ok++; - } - - v = out(source, - here, ok, - okascent, okdescent, oktop, okbottom, - v, - spacingmult, spacingadd, chooseht, - choosehtv, fm, tab, - needMultiply, start, chdirs, dir, easy, - ok == bufend, includepad, trackpad, - widths, start, end - start, - where, ellipsizedWidth, okwidth, - paint); - - here = ok; - } else { - // Act like it fit even though it didn't. - - fitwidth = w; - fit = j + 1; - - if (fmtop < fittop) - fittop = fmtop; - if (fmascent < fitascent) - fitascent = fmascent; - if (fmdescent > fitdescent) - fitdescent = fmdescent; - if (fmbottom > fitbottom) - fitbottom = fmbottom; - } - } else { - if (ok != here) { - // Log.e("text", "output ok " + here + " to " +ok); - - while (ok < next && chs[ok - start] == ' ') { - ok++; - } - - v = out(source, - here, ok, - okascent, okdescent, oktop, okbottom, - v, - spacingmult, spacingadd, chooseht, - choosehtv, fm, tab, - needMultiply, start, chdirs, dir, easy, - ok == bufend, includepad, trackpad, - widths, start, end - start, - where, ellipsizedWidth, okwidth, - paint); - - here = ok; - } else if (fit != here) { - // Log.e("text", "output fit " + here + " to " +fit); - v = out(source, - here, fit, - fitascent, fitdescent, - fittop, fitbottom, - v, - spacingmult, spacingadd, chooseht, - choosehtv, fm, tab, - needMultiply, start, chdirs, dir, easy, - fit == bufend, includepad, trackpad, - widths, start, end - start, - where, ellipsizedWidth, fitwidth, - paint); - - here = fit; - } else { - // Log.e("text", "output one " + here + " to " +(here + 1)); - measureText(paint, mWorkPaint, - source, here, here + 1, fm, tab, - null); - - v = out(source, - here, here+1, - fm.ascent, fm.descent, - fm.top, fm.bottom, - v, - spacingmult, spacingadd, chooseht, - choosehtv, fm, tab, - needMultiply, start, chdirs, dir, easy, - here + 1 == bufend, includepad, - trackpad, - widths, start, end - start, - where, ellipsizedWidth, - widths[here - start], paint); - - here = here + 1; - } - - if (here < i) { - j = next = here; // must remeasure - } else { - j = here - 1; // continue looping - } - - ok = fit = here; - w = 0; - fitascent = fitdescent = fittop = fitbottom = 0; - okascent = okdescent = oktop = okbottom = 0; - - width = restwidth; - } - } - } - - if (end != here) { - if ((fittop | fitbottom | fitdescent | fitascent) == 0) { - paint.getFontMetricsInt(fm); - - fittop = fm.top; - fitbottom = fm.bottom; - fitascent = fm.ascent; - fitdescent = fm.descent; - } - - // Log.e("text", "output rest " + here + " to " + end); - - v = out(source, - here, end, fitascent, fitdescent, - fittop, fitbottom, - v, - spacingmult, spacingadd, chooseht, - choosehtv, fm, tab, - needMultiply, start, chdirs, dir, easy, - end == bufend, includepad, trackpad, - widths, start, end - start, - where, ellipsizedWidth, w, paint); - } - - start = end; - - if (end == bufend) - break; - } - - if (bufend == bufstart || source.charAt(bufend - 1) == '\n') { - // Log.e("text", "output last " + bufend); - - paint.getFontMetricsInt(fm); - - v = out(source, - bufend, bufend, fm.ascent, fm.descent, - fm.top, fm.bottom, - v, - spacingmult, spacingadd, null, - null, fm, false, - needMultiply, bufend, chdirs, DEFAULT_DIR, true, - true, includepad, trackpad, - widths, bufstart, 0, - where, ellipsizedWidth, 0, paint); - } - } - - private static final char FIRST_CJK = '\u2E80'; - /** - * Returns true if the specified character is one of those specified - * as being Ideographic (class ID) by the Unicode Line Breaking Algorithm - * (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK - * to break between a pair of. - */ - private static final boolean isIdeographic(char c) { - if (c >= '\u2E80' && c <= '\u2FFF') { - return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS - } - if (c == '\u3000') { - return true; // IDEOGRAPHIC SPACE - } - if (c >= '\u3040' && c <= '\u309F') { - return true; // Hiragana (except small characters) - } - if (c >= '\u30A0' && c <= '\u30FF') { - return true; // Katakana (except small characters) - } - if (c >= '\u3400' && c <= '\u4DB5') { - return true; // CJK UNIFIED IDEOGRAPHS EXTENSION A - } - if (c >= '\u4E00' && c <= '\u9FBB') { - return true; // CJK UNIFIED IDEOGRAPHS - } - if (c >= '\uF900' && c <= '\uFAD9') { - return true; // CJK COMPATIBILITY IDEOGRAPHS - } - if (c >= '\uA000' && c <= '\uA48F') { - return true; // YI SYLLABLES - } - if (c >= '\uA490' && c <= '\uA4CF') { - return true; // YI RADICALS - } - if (c >= '\uFE62' && c <= '\uFE66') { - return true; // SMALL PLUS SIGN to SMALL EQUALS SIGN - } - if (c >= '\uFF10' && c <= '\uFF19') { - return true; // WIDE DIGITS - } - - return false; - } - -/* - private static void dump(byte[] data, int count, String label) { - if (false) { - System.out.print(label); - - for (int i = 0; i < count; i++) - System.out.print(" " + data[i]); - - System.out.println(); - } - } -*/ - - private static int getFit(TextPaint paint, - TextPaint workPaint, - CharSequence text, int start, int end, - float wid) { - int high = end + 1, low = start - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (measureText(paint, workPaint, - text, start, guess, null, true, null) > wid) - high = guess; - else - low = guess; - } - - if (low < start) - return start; - else - return low; - } - - private int out(CharSequence text, int start, int end, - int above, int below, int top, int bottom, int v, - float spacingmult, float spacingadd, - LineHeightSpan[] chooseht, int[] choosehtv, - Paint.FontMetricsInt fm, boolean tab, - boolean needMultiply, int pstart, byte[] chdirs, - int dir, boolean easy, boolean last, - boolean includepad, boolean trackpad, - float[] widths, int widstart, int widoff, - TextUtils.TruncateAt ellipsize, float ellipsiswidth, - float textwidth, TextPaint paint) { - int j = mLineCount; - int off = j * mColumns; - int want = off + mColumns + TOP; - int[] lines = mLines; - - // Log.e("text", "line " + start + " to " + end + (last ? "===" : "")); - - if (want >= lines.length) { - int nlen = ArrayUtils.idealIntArraySize(want + 1); - int[] grow = new int[nlen]; - System.arraycopy(lines, 0, grow, 0, lines.length); - mLines = grow; - lines = grow; - - Directions[] grow2 = new Directions[nlen]; - System.arraycopy(mLineDirections, 0, grow2, 0, - mLineDirections.length); - mLineDirections = grow2; - } - - if (chooseht != null) { - fm.ascent = above; - fm.descent = below; - fm.top = top; - fm.bottom = bottom; - - for (int i = 0; i < chooseht.length; i++) { - chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm); - } - - above = fm.ascent; - below = fm.descent; - top = fm.top; - bottom = fm.bottom; - } - - if (j == 0) { - if (trackpad) { - mTopPadding = top - above; - } - - if (includepad) { - above = top; - } - } - if (last) { - if (trackpad) { - mBottomPadding = bottom - below; - } - - if (includepad) { - below = bottom; - } - } - - int extra; - - if (needMultiply) { - extra = (int) ((below - above) * (spacingmult - 1) - + spacingadd + 0.5); - } else { - extra = 0; - } - - lines[off + START] = start; - lines[off + TOP] = v; - lines[off + DESCENT] = below + extra; - - v += (below - above) + extra; - lines[off + mColumns + START] = end; - lines[off + mColumns + TOP] = v; - - if (tab) - lines[off + TAB] |= TAB_MASK; - - { - lines[off + DIR] |= dir << DIR_SHIFT; - - int cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT; - int count = 0; - - if (!easy) { - for (int k = start; k < end; k++) { - if (chdirs[k - pstart] != cur) { - count++; - cur = chdirs[k - pstart]; - } - } - } - - Directions linedirs; - - if (count == 0) { - linedirs = DIRS_ALL_LEFT_TO_RIGHT; - } else { - short[] ld = new short[count + 1]; - - cur = Character.DIRECTIONALITY_LEFT_TO_RIGHT; - count = 0; - int here = start; - - for (int k = start; k < end; k++) { - if (chdirs[k - pstart] != cur) { - // XXX check to make sure we don't - // overflow short - ld[count++] = (short) (k - here); - cur = chdirs[k - pstart]; - here = k; - } - } - - ld[count] = (short) (end - here); - - if (count == 1 && ld[0] == 0) { - linedirs = DIRS_ALL_RIGHT_TO_LEFT; - } else { - linedirs = new Directions(ld); - } - } - - mLineDirections[j] = linedirs; - - // If ellipsize is in marquee mode, do not apply ellipsis on the first line - if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) { - calculateEllipsis(start, end, widths, widstart, widoff, - ellipsiswidth, ellipsize, j, - textwidth, paint); - } - } - - mLineCount++; - return v; - } - - private void calculateEllipsis(int linestart, int lineend, - float[] widths, int widstart, int widoff, - float avail, TextUtils.TruncateAt where, - int line, float textwidth, TextPaint paint) { - int len = lineend - linestart; - - if (textwidth <= avail) { - // Everything fits! - mLines[mColumns * line + ELLIPSIS_START] = 0; - mLines[mColumns * line + ELLIPSIS_COUNT] = 0; - return; - } - - float ellipsiswid = paint.measureText("\u2026"); - int ellipsisStart, ellipsisCount; - - if (where == TextUtils.TruncateAt.START) { - float sum = 0; - int i; - - for (i = len; i >= 0; i--) { - float w = widths[i - 1 + linestart - widstart + widoff]; - - if (w + sum + ellipsiswid > avail) { - break; - } - - sum += w; - } - - ellipsisStart = 0; - ellipsisCount = i; - } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE) { - float sum = 0; - int i; - - for (i = 0; i < len; i++) { - float w = widths[i + linestart - widstart + widoff]; - - if (w + sum + ellipsiswid > avail) { - break; - } - - sum += w; - } - - ellipsisStart = i; - ellipsisCount = len - i; - } else /* where = TextUtils.TruncateAt.MIDDLE */ { - float lsum = 0, rsum = 0; - int left = 0, right = len; - - float ravail = (avail - ellipsiswid) / 2; - for (right = len; right >= 0; right--) { - float w = widths[right - 1 + linestart - widstart + widoff]; - - if (w + rsum > ravail) { - break; - } - - rsum += w; - } - - float lavail = avail - ellipsiswid - rsum; - for (left = 0; left < right; left++) { - float w = widths[left + linestart - widstart + widoff]; - - if (w + lsum > lavail) { - break; - } - - lsum += w; - } - - ellipsisStart = left; - ellipsisCount = right - left; - } - - mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart; - mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount; - } - - // Override the baseclass so we can directly access our members, - // rather than relying on member functions. - // The logic mirrors that of Layout.getLineForVertical - // FIXME: It may be faster to do a linear search for layouts without many lines. - public int getLineForVertical(int vertical) { - int high = mLineCount; - int low = -1; - int guess; - int[] lines = mLines; - while (high - low > 1) { - guess = (high + low) >> 1; - if (lines[mColumns * guess + TOP] > vertical){ - high = guess; - } else { - low = guess; - } - } - if (low < 0) { - return 0; - } else { - return low; - } - } - - public int getLineCount() { - return mLineCount; - } - - public int getLineTop(int line) { - return mLines[mColumns * line + TOP]; - } - - public int getLineDescent(int line) { - return mLines[mColumns * line + DESCENT]; - } - - public int getLineStart(int line) { - return mLines[mColumns * line + START] & START_MASK; - } - - public int getParagraphDirection(int line) { - return mLines[mColumns * line + DIR] >> DIR_SHIFT; - } - - public boolean getLineContainsTab(int line) { - return (mLines[mColumns * line + TAB] & TAB_MASK) != 0; - } - - public final Directions getLineDirections(int line) { - return mLineDirections[line]; - } - - public int getTopPadding() { - return mTopPadding; - } - - public int getBottomPadding() { - return mBottomPadding; - } - - @Override - public int getEllipsisCount(int line) { - if (mColumns < COLUMNS_ELLIPSIZE) { - return 0; - } - - return mLines[mColumns * line + ELLIPSIS_COUNT]; - } - - @Override - public int getEllipsisStart(int line) { - if (mColumns < COLUMNS_ELLIPSIZE) { - return 0; - } - - return mLines[mColumns * line + ELLIPSIS_START]; - } - - @Override - public int getEllipsizedWidth() { - return mEllipsizedWidth; - } - - private int mLineCount; - private int mTopPadding, mBottomPadding; - private int mColumns; - private int mEllipsizedWidth; - - private static final int COLUMNS_NORMAL = 3; - private static final int COLUMNS_ELLIPSIZE = 5; - private static final int START = 0; - private static final int DIR = START; - private static final int TAB = START; - private static final int TOP = 1; - private static final int DESCENT = 2; - private static final int ELLIPSIS_START = 3; - private static final int ELLIPSIS_COUNT = 4; - - private int[] mLines; - private Directions[] mLineDirections; - - private static final int START_MASK = 0x1FFFFFFF; - private static final int DIR_MASK = 0xC0000000; - private static final int DIR_SHIFT = 30; - private static final int TAB_MASK = 0x20000000; - - private static final char FIRST_RIGHT_TO_LEFT = '\u0590'; - - /* - * These are reused across calls to generate() - */ - private byte[] mChdirs; - private char[] mChs; - private float[] mWidths; - private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); -} diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java deleted file mode 100644 index 05c27ea..0000000 --- a/core/java/android/text/Styled.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Paint; -import android.graphics.Canvas; -import android.graphics.Path; -import android.graphics.RectF; -import android.graphics.Typeface; -import android.graphics.MaskFilter; -import android.graphics.Rasterizer; -import android.graphics.LayerRasterizer; -import android.text.style.*; - -/* package */ class Styled -{ - private static float each(Canvas canvas, - Spanned text, int start, int end, - int dir, boolean reverse, - float x, int top, int y, int bottom, - Paint.FontMetricsInt fm, - TextPaint realPaint, - TextPaint paint, - boolean needwid) { - - boolean havewid = false; - float ret = 0; - CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class); - - ReplacementSpan replacement = null; - - realPaint.bgColor = 0; - realPaint.baselineShift = 0; - paint.set(realPaint); - - if (spans.length > 0) { - for (int i = 0; i < spans.length; i++) { - CharacterStyle span = spans[i]; - - if (span instanceof ReplacementSpan) { - replacement = (ReplacementSpan)span; - } - else { - span.updateDrawState(paint); - } - } - } - - if (replacement == null) { - CharSequence tmp; - int tmpstart, tmpend; - - if (reverse) { - tmp = TextUtils.getReverse(text, start, end); - tmpstart = 0; - tmpend = end - start; - } else { - tmp = text; - tmpstart = start; - tmpend = end; - } - - if (fm != null) { - paint.getFontMetricsInt(fm); - } - - if (canvas != null) { - if (paint.bgColor != 0) { - int c = paint.getColor(); - Paint.Style s = paint.getStyle(); - paint.setColor(paint.bgColor); - paint.setStyle(Paint.Style.FILL); - - if (!havewid) { - ret = paint.measureText(tmp, tmpstart, tmpend); - havewid = true; - } - - if (dir == Layout.DIR_RIGHT_TO_LEFT) - canvas.drawRect(x - ret, top, x, bottom, paint); - else - canvas.drawRect(x, top, x + ret, bottom, paint); - - paint.setStyle(s); - paint.setColor(c); - } - - if (dir == Layout.DIR_RIGHT_TO_LEFT) { - if (!havewid) { - ret = paint.measureText(tmp, tmpstart, tmpend); - havewid = true; - } - - canvas.drawText(tmp, tmpstart, tmpend, - x - ret, y + paint.baselineShift, paint); - } else { - if (needwid) { - if (!havewid) { - ret = paint.measureText(tmp, tmpstart, tmpend); - havewid = true; - } - } - - canvas.drawText(tmp, tmpstart, tmpend, - x, y + paint.baselineShift, paint); - } - } else { - if (needwid && !havewid) { - ret = paint.measureText(tmp, tmpstart, tmpend); - havewid = true; - } - } - } else { - ret = replacement.getSize(paint, text, start, end, fm); - - if (canvas != null) { - if (dir == Layout.DIR_RIGHT_TO_LEFT) - replacement.draw(canvas, text, start, end, - x - ret, top, y, bottom, paint); - else - replacement.draw(canvas, text, start, end, - x, top, y, bottom, paint); - } - } - - if (dir == Layout.DIR_RIGHT_TO_LEFT) - return -ret; - else - return ret; - } - - public static int getTextWidths(TextPaint realPaint, - TextPaint paint, - Spanned text, int start, int end, - float[] widths, Paint.FontMetricsInt fm) { - - MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class); - - ReplacementSpan replacement = null; - paint.set(realPaint); - - for (int i = 0; i < spans.length; i++) { - MetricAffectingSpan span = spans[i]; - if (span instanceof ReplacementSpan) { - replacement = (ReplacementSpan)span; - } - else { - span.updateMeasureState(paint); - } - } - - if (replacement == null) { - paint.getFontMetricsInt(fm); - paint.getTextWidths(text, start, end, widths); - } else { - int wid = replacement.getSize(paint, text, start, end, fm); - - if (end > start) { - widths[0] = wid; - - for (int i = start + 1; i < end; i++) - widths[i - start] = 0; - } - } - return end - start; - } - - private static float foreach(Canvas canvas, - CharSequence text, int start, int end, - int dir, boolean reverse, - float x, int top, int y, int bottom, - Paint.FontMetricsInt fm, - TextPaint paint, - TextPaint workPaint, - boolean needwid) { - if (! (text instanceof Spanned)) { - float ret = 0; - - if (reverse) { - CharSequence tmp = TextUtils.getReverse(text, start, end); - int tmpend = end - start; - - if (canvas != null || needwid) - ret = paint.measureText(tmp, 0, tmpend); - - if (canvas != null) - canvas.drawText(tmp, 0, tmpend, - x - ret, y, paint); - } else { - if (needwid) - ret = paint.measureText(text, start, end); - - if (canvas != null) - canvas.drawText(text, start, end, x, y, paint); - } - - if (fm != null) { - paint.getFontMetricsInt(fm); - } - - return ret * dir; //Layout.DIR_RIGHT_TO_LEFT == -1 - } - - float ox = x; - int asc = 0, desc = 0; - int ftop = 0, fbot = 0; - - Spanned sp = (Spanned) text; - Class division; - - if (canvas == null) - division = MetricAffectingSpan.class; - else - division = CharacterStyle.class; - - int next; - for (int i = start; i < end; i = next) { - next = sp.nextSpanTransition(i, end, division); - - x += each(canvas, sp, i, next, dir, reverse, - x, top, y, bottom, fm, paint, workPaint, - needwid || next != end); - - if (fm != null) { - if (fm.ascent < asc) - asc = fm.ascent; - if (fm.descent > desc) - desc = fm.descent; - - if (fm.top < ftop) - ftop = fm.top; - if (fm.bottom > fbot) - fbot = fm.bottom; - } - } - - if (fm != null) { - if (start == end) { - paint.getFontMetricsInt(fm); - } else { - fm.ascent = asc; - fm.descent = desc; - fm.top = ftop; - fm.bottom = fbot; - } - } - - return x - ox; - } - - public static float drawText(Canvas canvas, - CharSequence text, int start, int end, - int dir, boolean reverse, - float x, int top, int y, int bottom, - TextPaint paint, - TextPaint workPaint, - boolean needwid) { - if ((dir == Layout.DIR_RIGHT_TO_LEFT && !reverse)||(reverse && dir == Layout.DIR_LEFT_TO_RIGHT)) { - float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT, - false, 0, 0, 0, 0, null, paint, workPaint, - true); - - ch *= dir; // DIR_RIGHT_TO_LEFT == -1 - foreach(canvas, text, start, end, -dir, - reverse, x + ch, top, y, bottom, null, paint, - workPaint, true); - - return ch; - } - - return foreach(canvas, text, start, end, dir, reverse, - x, top, y, bottom, null, paint, workPaint, - needwid); - } - - public static float measureText(TextPaint paint, - TextPaint workPaint, - CharSequence text, int start, int end, - Paint.FontMetricsInt fm) { - return foreach(null, text, start, end, - Layout.DIR_LEFT_TO_RIGHT, false, - 0, 0, 0, 0, fm, paint, workPaint, true); - } -} diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java deleted file mode 100644 index f13820d..0000000 --- a/core/java/android/text/TextPaint.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.graphics.Paint; - -/** - * TextPaint is an extension of Paint that leaves room for some extra - * data used during text measuring and drawing. - */ -public class TextPaint extends Paint { - public int bgColor; - public int baselineShift; - public int linkColor; - public int[] drawableState; - - public TextPaint() { - super(); - } - - public TextPaint(int flags) { - super(flags); - } - - public TextPaint(Paint p) { - super(p); - } - - /** - * Copy the fields from tp into this TextPaint, including the - * fields inherited from Paint. - */ - public void set(TextPaint tp) { - super.set(tp); - - bgColor = tp.bgColor; - baselineShift = tp.baselineShift; - linkColor = tp.linkColor; - drawableState = tp.drawableState; - } -} diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java deleted file mode 100644 index 5b4c380..0000000 --- a/core/java/android/text/TextUtils.java +++ /dev/null @@ -1,1620 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import com.android.internal.R; - -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.method.TextKeyListener.Capitalize; -import android.text.style.AbsoluteSizeSpan; -import android.text.style.AlignmentSpan; -import android.text.style.BackgroundColorSpan; -import android.text.style.BulletSpan; -import android.text.style.CharacterStyle; -import android.text.style.ForegroundColorSpan; -import android.text.style.LeadingMarginSpan; -import android.text.style.MetricAffectingSpan; -import android.text.style.QuoteSpan; -import android.text.style.RelativeSizeSpan; -import android.text.style.ReplacementSpan; -import android.text.style.ScaleXSpan; -import android.text.style.StrikethroughSpan; -import android.text.style.StyleSpan; -import android.text.style.SubscriptSpan; -import android.text.style.SuperscriptSpan; -import android.text.style.TextAppearanceSpan; -import android.text.style.TypefaceSpan; -import android.text.style.URLSpan; -import android.text.style.UnderlineSpan; -import android.util.Printer; - -import com.android.internal.util.ArrayUtils; - -import java.util.regex.Pattern; -import java.util.Iterator; - -public class TextUtils { - private TextUtils() { /* cannot be instantiated */ } - - private static String[] EMPTY_STRING_ARRAY = new String[]{}; - - public static void getChars(CharSequence s, int start, int end, - char[] dest, int destoff) { - Class c = s.getClass(); - - if (c == String.class) - ((String) s).getChars(start, end, dest, destoff); - else if (c == StringBuffer.class) - ((StringBuffer) s).getChars(start, end, dest, destoff); - else if (c == StringBuilder.class) - ((StringBuilder) s).getChars(start, end, dest, destoff); - else if (s instanceof GetChars) - ((GetChars) s).getChars(start, end, dest, destoff); - else { - for (int i = start; i < end; i++) - dest[destoff++] = s.charAt(i); - } - } - - public static int indexOf(CharSequence s, char ch) { - return indexOf(s, ch, 0); - } - - public static int indexOf(CharSequence s, char ch, int start) { - Class c = s.getClass(); - - if (c == String.class) - return ((String) s).indexOf(ch, start); - - return indexOf(s, ch, start, s.length()); - } - - public static int indexOf(CharSequence s, char ch, int start, int end) { - Class c = s.getClass(); - - if (s instanceof GetChars || c == StringBuffer.class || - c == StringBuilder.class || c == String.class) { - final int INDEX_INCREMENT = 500; - char[] temp = obtain(INDEX_INCREMENT); - - while (start < end) { - int segend = start + INDEX_INCREMENT; - if (segend > end) - segend = end; - - getChars(s, start, segend, temp, 0); - - int count = segend - start; - for (int i = 0; i < count; i++) { - if (temp[i] == ch) { - recycle(temp); - return i + start; - } - } - - start = segend; - } - - recycle(temp); - return -1; - } - - for (int i = start; i < end; i++) - if (s.charAt(i) == ch) - return i; - - return -1; - } - - public static int lastIndexOf(CharSequence s, char ch) { - return lastIndexOf(s, ch, s.length() - 1); - } - - public static int lastIndexOf(CharSequence s, char ch, int last) { - Class c = s.getClass(); - - if (c == String.class) - return ((String) s).lastIndexOf(ch, last); - - return lastIndexOf(s, ch, 0, last); - } - - public static int lastIndexOf(CharSequence s, char ch, - int start, int last) { - if (last < 0) - return -1; - if (last >= s.length()) - last = s.length() - 1; - - int end = last + 1; - - Class c = s.getClass(); - - if (s instanceof GetChars || c == StringBuffer.class || - c == StringBuilder.class || c == String.class) { - final int INDEX_INCREMENT = 500; - char[] temp = obtain(INDEX_INCREMENT); - - while (start < end) { - int segstart = end - INDEX_INCREMENT; - if (segstart < start) - segstart = start; - - getChars(s, segstart, end, temp, 0); - - int count = end - segstart; - for (int i = count - 1; i >= 0; i--) { - if (temp[i] == ch) { - recycle(temp); - return i + segstart; - } - } - - end = segstart; - } - - recycle(temp); - return -1; - } - - for (int i = end - 1; i >= start; i--) - if (s.charAt(i) == ch) - return i; - - return -1; - } - - public static int indexOf(CharSequence s, CharSequence needle) { - return indexOf(s, needle, 0, s.length()); - } - - public static int indexOf(CharSequence s, CharSequence needle, int start) { - return indexOf(s, needle, start, s.length()); - } - - public static int indexOf(CharSequence s, CharSequence needle, - int start, int end) { - int nlen = needle.length(); - if (nlen == 0) - return start; - - char c = needle.charAt(0); - - for (;;) { - start = indexOf(s, c, start); - if (start > end - nlen) { - break; - } - - if (start < 0) { - return -1; - } - - if (regionMatches(s, start, needle, 0, nlen)) { - return start; - } - - start++; - } - return -1; - } - - public static boolean regionMatches(CharSequence one, int toffset, - CharSequence two, int ooffset, - int len) { - char[] temp = obtain(2 * len); - - getChars(one, toffset, toffset + len, temp, 0); - getChars(two, ooffset, ooffset + len, temp, len); - - boolean match = true; - for (int i = 0; i < len; i++) { - if (temp[i] != temp[i + len]) { - match = false; - break; - } - } - - recycle(temp); - return match; - } - - /** - * Create a new String object containing the given range of characters - * from the source string. This is different than simply calling - * {@link CharSequence#subSequence(int, int) CharSequence.subSequence} - * in that it does not preserve any style runs in the source sequence, - * allowing a more efficient implementation. - */ - public static String substring(CharSequence source, int start, int end) { - if (source instanceof String) - return ((String) source).substring(start, end); - if (source instanceof StringBuilder) - return ((StringBuilder) source).substring(start, end); - if (source instanceof StringBuffer) - return ((StringBuffer) source).substring(start, end); - - char[] temp = obtain(end - start); - getChars(source, start, end, temp, 0); - String ret = new String(temp, 0, end - start); - recycle(temp); - - return ret; - } - - /** - * Returns a string containing the tokens joined by delimiters. - * @param tokens an array objects to be joined. Strings will be formed from - * the objects by calling object.toString(). - */ - public static String join(CharSequence delimiter, Object[] tokens) { - StringBuilder sb = new StringBuilder(); - boolean firstTime = true; - for (Object token: tokens) { - if (firstTime) { - firstTime = false; - } else { - sb.append(delimiter); - } - sb.append(token); - } - return sb.toString(); - } - - /** - * Returns a string containing the tokens joined by delimiters. - * @param tokens an array objects to be joined. Strings will be formed from - * the objects by calling object.toString(). - */ - public static String join(CharSequence delimiter, Iterable tokens) { - StringBuilder sb = new StringBuilder(); - boolean firstTime = true; - for (Object token: tokens) { - if (firstTime) { - firstTime = false; - } else { - sb.append(delimiter); - } - sb.append(token); - } - return sb.toString(); - } - - /** - * String.split() returns [''] when the string to be split is empty. This returns []. This does - * not remove any empty strings from the result. For example split("a,", "," ) returns {"a", ""}. - * - * @param text the string to split - * @param expression the regular expression to match - * @return an array of strings. The array will be empty if text is empty - * - * @throws NullPointerException if expression or text is null - */ - public static String[] split(String text, String expression) { - if (text.length() == 0) { - return EMPTY_STRING_ARRAY; - } else { - return text.split(expression, -1); - } - } - - /** - * Splits a string on a pattern. String.split() returns [''] when the string to be - * split is empty. This returns []. This does not remove any empty strings from the result. - * @param text the string to split - * @param pattern the regular expression to match - * @return an array of strings. The array will be empty if text is empty - * - * @throws NullPointerException if expression or text is null - */ - public static String[] split(String text, Pattern pattern) { - if (text.length() == 0) { - return EMPTY_STRING_ARRAY; - } else { - return pattern.split(text, -1); - } - } - - /** - * An interface for splitting strings according to rules that are opaque to the user of this - * interface. This also has less overhead than split, which uses regular expressions and - * allocates an array to hold the results. - * - * <p>The most efficient way to use this class is: - * - * <pre> - * // Once - * TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(delimiter); - * - * // Once per string to split - * splitter.setString(string); - * for (String s : splitter) { - * ... - * } - * </pre> - */ - public interface StringSplitter extends Iterable<String> { - public void setString(String string); - } - - /** - * A simple string splitter. - * - * <p>If the final character in the string to split is the delimiter then no empty string will - * be returned for the empty string after that delimeter. That is, splitting <tt>"a,b,"</tt> on - * comma will return <tt>"a", "b"</tt>, not <tt>"a", "b", ""</tt>. - */ - public static class SimpleStringSplitter implements StringSplitter, Iterator<String> { - private String mString; - private char mDelimiter; - private int mPosition; - private int mLength; - - /** - * Initializes the splitter. setString may be called later. - * @param delimiter the delimeter on which to split - */ - public SimpleStringSplitter(char delimiter) { - mDelimiter = delimiter; - } - - /** - * Sets the string to split - * @param string the string to split - */ - public void setString(String string) { - mString = string; - mPosition = 0; - mLength = mString.length(); - } - - public Iterator<String> iterator() { - return this; - } - - public boolean hasNext() { - return mPosition < mLength; - } - - public String next() { - int end = mString.indexOf(mDelimiter, mPosition); - if (end == -1) { - end = mLength; - } - String nextString = mString.substring(mPosition, end); - mPosition = end + 1; // Skip the delimiter. - return nextString; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - } - - public static CharSequence stringOrSpannedString(CharSequence source) { - if (source == null) - return null; - if (source instanceof SpannedString) - return source; - if (source instanceof Spanned) - return new SpannedString(source); - - return source.toString(); - } - - /** - * Returns true if the string is null or 0-length. - * @param str the string to be examined - * @return true if str is null or zero length - */ - public static boolean isEmpty(CharSequence str) { - if (str == null || str.length() == 0) - return true; - else - return false; - } - - /** - * Returns the length that the specified CharSequence would have if - * spaces and control characters were trimmed from the start and end, - * as by {@link String#trim}. - */ - public static int getTrimmedLength(CharSequence s) { - int len = s.length(); - - int start = 0; - while (start < len && s.charAt(start) <= ' ') { - start++; - } - - int end = len; - while (end > start && s.charAt(end - 1) <= ' ') { - end--; - } - - return end - start; - } - - /** - * Returns true if a and b are equal, including if they are both null. - * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if - * both the arguments were instances of String.</i></p> - * @param a first CharSequence to check - * @param b second CharSequence to check - * @return true if a and b are equal - */ - public static boolean equals(CharSequence a, CharSequence b) { - if (a == b) return true; - int length; - if (a != null && b != null && (length = a.length()) == b.length()) { - if (a instanceof String && b instanceof String) { - return a.equals(b); - } else { - for (int i = 0; i < length; i++) { - if (a.charAt(i) != b.charAt(i)) return false; - } - return true; - } - } - return false; - } - - // XXX currently this only reverses chars, not spans - public static CharSequence getReverse(CharSequence source, - int start, int end) { - return new Reverser(source, start, end); - } - - private static class Reverser - implements CharSequence, GetChars - { - public Reverser(CharSequence source, int start, int end) { - mSource = source; - mStart = start; - mEnd = end; - } - - public int length() { - return mEnd - mStart; - } - - public CharSequence subSequence(int start, int end) { - char[] buf = new char[end - start]; - - getChars(start, end, buf, 0); - return new String(buf); - } - - public String toString() { - return subSequence(0, length()).toString(); - } - - public char charAt(int off) { - return AndroidCharacter.getMirror(mSource.charAt(mEnd - 1 - off)); - } - - public void getChars(int start, int end, char[] dest, int destoff) { - TextUtils.getChars(mSource, start + mStart, end + mStart, - dest, destoff); - AndroidCharacter.mirror(dest, 0, end - start); - - int len = end - start; - int n = (end - start) / 2; - for (int i = 0; i < n; i++) { - char tmp = dest[destoff + i]; - - dest[destoff + i] = dest[destoff + len - i - 1]; - dest[destoff + len - i - 1] = tmp; - } - } - - private CharSequence mSource; - private int mStart; - private int mEnd; - } - - /** @hide */ - public static final int ALIGNMENT_SPAN = 1; - /** @hide */ - public static final int FOREGROUND_COLOR_SPAN = 2; - /** @hide */ - public static final int RELATIVE_SIZE_SPAN = 3; - /** @hide */ - public static final int SCALE_X_SPAN = 4; - /** @hide */ - public static final int STRIKETHROUGH_SPAN = 5; - /** @hide */ - public static final int UNDERLINE_SPAN = 6; - /** @hide */ - public static final int STYLE_SPAN = 7; - /** @hide */ - public static final int BULLET_SPAN = 8; - /** @hide */ - public static final int QUOTE_SPAN = 9; - /** @hide */ - public static final int LEADING_MARGIN_SPAN = 10; - /** @hide */ - public static final int URL_SPAN = 11; - /** @hide */ - public static final int BACKGROUND_COLOR_SPAN = 12; - /** @hide */ - public static final int TYPEFACE_SPAN = 13; - /** @hide */ - public static final int SUPERSCRIPT_SPAN = 14; - /** @hide */ - public static final int SUBSCRIPT_SPAN = 15; - /** @hide */ - public static final int ABSOLUTE_SIZE_SPAN = 16; - /** @hide */ - public static final int TEXT_APPEARANCE_SPAN = 17; - /** @hide */ - public static final int ANNOTATION = 18; - - /** - * Flatten a CharSequence and whatever styles can be copied across processes - * into the parcel. - */ - public static void writeToParcel(CharSequence cs, Parcel p, - int parcelableFlags) { - if (cs instanceof Spanned) { - p.writeInt(0); - p.writeString(cs.toString()); - - Spanned sp = (Spanned) cs; - Object[] os = sp.getSpans(0, cs.length(), Object.class); - - // note to people adding to this: check more specific types - // before more generic types. also notice that it uses - // "if" instead of "else if" where there are interfaces - // so one object can be several. - - for (int i = 0; i < os.length; i++) { - Object o = os[i]; - Object prop = os[i]; - - if (prop instanceof CharacterStyle) { - prop = ((CharacterStyle) prop).getUnderlying(); - } - - if (prop instanceof ParcelableSpan) { - ParcelableSpan ps = (ParcelableSpan)prop; - p.writeInt(ps.getSpanTypeId()); - ps.writeToParcel(p, parcelableFlags); - writeWhere(p, sp, o); - } - } - - p.writeInt(0); - } else { - p.writeInt(1); - if (cs != null) { - p.writeString(cs.toString()); - } else { - p.writeString(null); - } - } - } - - private static void writeWhere(Parcel p, Spanned sp, Object o) { - p.writeInt(sp.getSpanStart(o)); - p.writeInt(sp.getSpanEnd(o)); - p.writeInt(sp.getSpanFlags(o)); - } - - public static final Parcelable.Creator<CharSequence> CHAR_SEQUENCE_CREATOR - = new Parcelable.Creator<CharSequence>() { - /** - * Read and return a new CharSequence, possibly with styles, - * from the parcel. - */ - public CharSequence createFromParcel(Parcel p) { - int kind = p.readInt(); - - if (kind == 1) - return p.readString(); - - SpannableString sp = new SpannableString(p.readString()); - - while (true) { - kind = p.readInt(); - - if (kind == 0) - break; - - switch (kind) { - case ALIGNMENT_SPAN: - readSpan(p, sp, new AlignmentSpan.Standard(p)); - break; - - case FOREGROUND_COLOR_SPAN: - readSpan(p, sp, new ForegroundColorSpan(p)); - break; - - case RELATIVE_SIZE_SPAN: - readSpan(p, sp, new RelativeSizeSpan(p)); - break; - - case SCALE_X_SPAN: - readSpan(p, sp, new ScaleXSpan(p)); - break; - - case STRIKETHROUGH_SPAN: - readSpan(p, sp, new StrikethroughSpan(p)); - break; - - case UNDERLINE_SPAN: - readSpan(p, sp, new UnderlineSpan(p)); - break; - - case STYLE_SPAN: - readSpan(p, sp, new StyleSpan(p)); - break; - - case BULLET_SPAN: - readSpan(p, sp, new BulletSpan(p)); - break; - - case QUOTE_SPAN: - readSpan(p, sp, new QuoteSpan(p)); - break; - - case LEADING_MARGIN_SPAN: - readSpan(p, sp, new LeadingMarginSpan.Standard(p)); - break; - - case URL_SPAN: - readSpan(p, sp, new URLSpan(p)); - break; - - case BACKGROUND_COLOR_SPAN: - readSpan(p, sp, new BackgroundColorSpan(p)); - break; - - case TYPEFACE_SPAN: - readSpan(p, sp, new TypefaceSpan(p)); - break; - - case SUPERSCRIPT_SPAN: - readSpan(p, sp, new SuperscriptSpan(p)); - break; - - case SUBSCRIPT_SPAN: - readSpan(p, sp, new SubscriptSpan(p)); - break; - - case ABSOLUTE_SIZE_SPAN: - readSpan(p, sp, new AbsoluteSizeSpan(p)); - break; - - case TEXT_APPEARANCE_SPAN: - readSpan(p, sp, new TextAppearanceSpan(p)); - break; - - case ANNOTATION: - readSpan(p, sp, new Annotation(p)); - break; - - default: - throw new RuntimeException("bogus span encoding " + kind); - } - } - - return sp; - } - - public CharSequence[] newArray(int size) - { - return new CharSequence[size]; - } - }; - - /** - * Debugging tool to print the spans in a CharSequence. The output will - * be printed one span per line. If the CharSequence is not a Spanned, - * then the entire string will be printed on a single line. - */ - public static void dumpSpans(CharSequence cs, Printer printer, String prefix) { - if (cs instanceof Spanned) { - Spanned sp = (Spanned) cs; - Object[] os = sp.getSpans(0, cs.length(), Object.class); - - for (int i = 0; i < os.length; i++) { - Object o = os[i]; - printer.println(prefix + cs.subSequence(sp.getSpanStart(o), - sp.getSpanEnd(o)) + ": " - + Integer.toHexString(System.identityHashCode(o)) - + " " + o.getClass().getCanonicalName() - + " (" + sp.getSpanStart(o) + "-" + sp.getSpanEnd(o) - + ") fl=#" + sp.getSpanFlags(o)); - } - } else { - printer.println(prefix + cs + ": (no spans)"); - } - } - - /** - * Return a new CharSequence in which each of the source strings is - * replaced by the corresponding element of the destinations. - */ - public static CharSequence replace(CharSequence template, - String[] sources, - CharSequence[] destinations) { - SpannableStringBuilder tb = new SpannableStringBuilder(template); - - for (int i = 0; i < sources.length; i++) { - int where = indexOf(tb, sources[i]); - - if (where >= 0) - tb.setSpan(sources[i], where, where + sources[i].length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - for (int i = 0; i < sources.length; i++) { - int start = tb.getSpanStart(sources[i]); - int end = tb.getSpanEnd(sources[i]); - - if (start >= 0) { - tb.replace(start, end, destinations[i]); - } - } - - return tb; - } - - /** - * Replace instances of "^1", "^2", etc. in the - * <code>template</code> CharSequence with the corresponding - * <code>values</code>. "^^" is used to produce a single caret in - * the output. Only up to 9 replacement values are supported, - * "^10" will be produce the first replacement value followed by a - * '0'. - * - * @param template the input text containing "^1"-style - * placeholder values. This object is not modified; a copy is - * returned. - * - * @param values CharSequences substituted into the template. The - * first is substituted for "^1", the second for "^2", and so on. - * - * @return the new CharSequence produced by doing the replacement - * - * @throws IllegalArgumentException if the template requests a - * value that was not provided, or if more than 9 values are - * provided. - */ - public static CharSequence expandTemplate(CharSequence template, - CharSequence... values) { - if (values.length > 9) { - throw new IllegalArgumentException("max of 9 values are supported"); - } - - SpannableStringBuilder ssb = new SpannableStringBuilder(template); - - try { - int i = 0; - while (i < ssb.length()) { - if (ssb.charAt(i) == '^') { - char next = ssb.charAt(i+1); - if (next == '^') { - ssb.delete(i+1, i+2); - ++i; - continue; - } else if (Character.isDigit(next)) { - int which = Character.getNumericValue(next) - 1; - if (which < 0) { - throw new IllegalArgumentException( - "template requests value ^" + (which+1)); - } - if (which >= values.length) { - throw new IllegalArgumentException( - "template requests value ^" + (which+1) + - "; only " + values.length + " provided"); - } - ssb.replace(i, i+2, values[which]); - i += values[which].length(); - continue; - } - } - ++i; - } - } catch (IndexOutOfBoundsException ignore) { - // happens when ^ is the last character in the string. - } - return ssb; - } - - public static int getOffsetBefore(CharSequence text, int offset) { - if (offset == 0) - return 0; - if (offset == 1) - return 0; - - char c = text.charAt(offset - 1); - - if (c >= '\uDC00' && c <= '\uDFFF') { - char c1 = text.charAt(offset - 2); - - if (c1 >= '\uD800' && c1 <= '\uDBFF') - offset -= 2; - else - offset -= 1; - } else { - offset -= 1; - } - - if (text instanceof Spanned) { - ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, - ReplacementSpan.class); - - for (int i = 0; i < spans.length; i++) { - int start = ((Spanned) text).getSpanStart(spans[i]); - int end = ((Spanned) text).getSpanEnd(spans[i]); - - if (start < offset && end > offset) - offset = start; - } - } - - return offset; - } - - public static int getOffsetAfter(CharSequence text, int offset) { - int len = text.length(); - - if (offset == len) - return len; - if (offset == len - 1) - return len; - - char c = text.charAt(offset); - - if (c >= '\uD800' && c <= '\uDBFF') { - char c1 = text.charAt(offset + 1); - - if (c1 >= '\uDC00' && c1 <= '\uDFFF') - offset += 2; - else - offset += 1; - } else { - offset += 1; - } - - if (text instanceof Spanned) { - ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, - ReplacementSpan.class); - - for (int i = 0; i < spans.length; i++) { - int start = ((Spanned) text).getSpanStart(spans[i]); - int end = ((Spanned) text).getSpanEnd(spans[i]); - - if (start < offset && end > offset) - offset = end; - } - } - - return offset; - } - - private static void readSpan(Parcel p, Spannable sp, Object o) { - sp.setSpan(o, p.readInt(), p.readInt(), p.readInt()); - } - - public static void copySpansFrom(Spanned source, int start, int end, - Class kind, - Spannable dest, int destoff) { - if (kind == null) { - kind = Object.class; - } - - Object[] spans = source.getSpans(start, end, kind); - - for (int i = 0; i < spans.length; i++) { - int st = source.getSpanStart(spans[i]); - int en = source.getSpanEnd(spans[i]); - int fl = source.getSpanFlags(spans[i]); - - if (st < start) - st = start; - if (en > end) - en = end; - - dest.setSpan(spans[i], st - start + destoff, en - start + destoff, - fl); - } - } - - public enum TruncateAt { - START, - MIDDLE, - END, - MARQUEE, - } - - public interface EllipsizeCallback { - /** - * This method is called to report that the specified region of - * text was ellipsized away by a call to {@link #ellipsize}. - */ - public void ellipsized(int start, int end); - } - - private static String sEllipsis = null; - - /** - * Returns the original text if it fits in the specified width - * given the properties of the specified Paint, - * or, if it does not fit, a truncated - * copy with ellipsis character added at the specified edge or center. - */ - public static CharSequence ellipsize(CharSequence text, - TextPaint p, - float avail, TruncateAt where) { - return ellipsize(text, p, avail, where, false, null); - } - - /** - * Returns the original text if it fits in the specified width - * given the properties of the specified Paint, - * or, if it does not fit, a copy with ellipsis character added - * at the specified edge or center. - * If <code>preserveLength</code> is specified, the returned copy - * will be padded with zero-width spaces to preserve the original - * length and offsets instead of truncating. - * If <code>callback</code> is non-null, it will be called to - * report the start and end of the ellipsized range. - */ - public static CharSequence ellipsize(CharSequence text, - TextPaint p, - float avail, TruncateAt where, - boolean preserveLength, - EllipsizeCallback callback) { - if (sEllipsis == null) { - Resources r = Resources.getSystem(); - sEllipsis = r.getString(R.string.ellipsis); - } - - int len = text.length(); - - // Use Paint.breakText() for the non-Spanned case to avoid having - // to allocate memory and accumulate the character widths ourselves. - - if (!(text instanceof Spanned)) { - float wid = p.measureText(text, 0, len); - - if (wid <= avail) { - if (callback != null) { - callback.ellipsized(0, 0); - } - - return text; - } - - float ellipsiswid = p.measureText(sEllipsis); - - if (ellipsiswid > avail) { - if (callback != null) { - callback.ellipsized(0, len); - } - - if (preserveLength) { - char[] buf = obtain(len); - for (int i = 0; i < len; i++) { - buf[i] = '\uFEFF'; - } - String ret = new String(buf, 0, len); - recycle(buf); - return ret; - } else { - return ""; - } - } - - if (where == TruncateAt.START) { - int fit = p.breakText(text, 0, len, false, - avail - ellipsiswid, null); - - if (callback != null) { - callback.ellipsized(0, len - fit); - } - - if (preserveLength) { - return blank(text, 0, len - fit); - } else { - return sEllipsis + text.toString().substring(len - fit, len); - } - } else if (where == TruncateAt.END) { - int fit = p.breakText(text, 0, len, true, - avail - ellipsiswid, null); - - if (callback != null) { - callback.ellipsized(fit, len); - } - - if (preserveLength) { - return blank(text, fit, len); - } else { - return text.toString().substring(0, fit) + sEllipsis; - } - } else /* where == TruncateAt.MIDDLE */ { - int right = p.breakText(text, 0, len, false, - (avail - ellipsiswid) / 2, null); - float used = p.measureText(text, len - right, len); - int left = p.breakText(text, 0, len - right, true, - avail - ellipsiswid - used, null); - - if (callback != null) { - callback.ellipsized(left, len - right); - } - - if (preserveLength) { - return blank(text, left, len - right); - } else { - String s = text.toString(); - return s.substring(0, left) + sEllipsis + - s.substring(len - right, len); - } - } - } - - // But do the Spanned cases by hand, because it's such a pain - // to iterate the span transitions backwards and getTextWidths() - // will give us the information we need. - - // getTextWidths() always writes into the start of the array, - // so measure each span into the first half and then copy the - // results into the second half to use later. - - float[] wid = new float[len * 2]; - TextPaint temppaint = new TextPaint(); - Spanned sp = (Spanned) text; - - int next; - for (int i = 0; i < len; i = next) { - next = sp.nextSpanTransition(i, len, MetricAffectingSpan.class); - - Styled.getTextWidths(p, temppaint, sp, i, next, wid, null); - System.arraycopy(wid, 0, wid, len + i, next - i); - } - - float sum = 0; - for (int i = 0; i < len; i++) { - sum += wid[len + i]; - } - - if (sum <= avail) { - if (callback != null) { - callback.ellipsized(0, 0); - } - - return text; - } - - float ellipsiswid = p.measureText(sEllipsis); - - if (ellipsiswid > avail) { - if (callback != null) { - callback.ellipsized(0, len); - } - - if (preserveLength) { - char[] buf = obtain(len); - for (int i = 0; i < len; i++) { - buf[i] = '\uFEFF'; - } - SpannableString ss = new SpannableString(new String(buf, 0, len)); - recycle(buf); - copySpansFrom(sp, 0, len, Object.class, ss, 0); - return ss; - } else { - return ""; - } - } - - if (where == TruncateAt.START) { - sum = 0; - int i; - - for (i = len; i >= 0; i--) { - float w = wid[len + i - 1]; - - if (w + sum + ellipsiswid > avail) { - break; - } - - sum += w; - } - - if (callback != null) { - callback.ellipsized(0, i); - } - - if (preserveLength) { - SpannableString ss = new SpannableString(blank(text, 0, i)); - copySpansFrom(sp, 0, len, Object.class, ss, 0); - return ss; - } else { - SpannableStringBuilder out = new SpannableStringBuilder(sEllipsis); - out.insert(1, text, i, len); - - return out; - } - } else if (where == TruncateAt.END) { - sum = 0; - int i; - - for (i = 0; i < len; i++) { - float w = wid[len + i]; - - if (w + sum + ellipsiswid > avail) { - break; - } - - sum += w; - } - - if (callback != null) { - callback.ellipsized(i, len); - } - - if (preserveLength) { - SpannableString ss = new SpannableString(blank(text, i, len)); - copySpansFrom(sp, 0, len, Object.class, ss, 0); - return ss; - } else { - SpannableStringBuilder out = new SpannableStringBuilder(sEllipsis); - out.insert(0, text, 0, i); - - return out; - } - } else /* where = TruncateAt.MIDDLE */ { - float lsum = 0, rsum = 0; - int left = 0, right = len; - - float ravail = (avail - ellipsiswid) / 2; - for (right = len; right >= 0; right--) { - float w = wid[len + right - 1]; - - if (w + rsum > ravail) { - break; - } - - rsum += w; - } - - float lavail = avail - ellipsiswid - rsum; - for (left = 0; left < right; left++) { - float w = wid[len + left]; - - if (w + lsum > lavail) { - break; - } - - lsum += w; - } - - if (callback != null) { - callback.ellipsized(left, right); - } - - if (preserveLength) { - SpannableString ss = new SpannableString(blank(text, left, right)); - copySpansFrom(sp, 0, len, Object.class, ss, 0); - return ss; - } else { - SpannableStringBuilder out = new SpannableStringBuilder(sEllipsis); - out.insert(0, text, 0, left); - out.insert(out.length(), text, right, len); - - return out; - } - } - } - - private static String blank(CharSequence source, int start, int end) { - int len = source.length(); - char[] buf = obtain(len); - - if (start != 0) { - getChars(source, 0, start, buf, 0); - } - if (end != len) { - getChars(source, end, len, buf, end); - } - - if (start != end) { - buf[start] = '\u2026'; - - for (int i = start + 1; i < end; i++) { - buf[i] = '\uFEFF'; - } - } - - String ret = new String(buf, 0, len); - recycle(buf); - - return ret; - } - - /** - * Converts a CharSequence of the comma-separated form "Andy, Bob, - * Charles, David" that is too wide to fit into the specified width - * into one like "Andy, Bob, 2 more". - * - * @param text the text to truncate - * @param p the Paint with which to measure the text - * @param avail the horizontal width available for the text - * @param oneMore the string for "1 more" in the current locale - * @param more the string for "%d more" in the current locale - */ - public static CharSequence commaEllipsize(CharSequence text, - TextPaint p, float avail, - String oneMore, - String more) { - int len = text.length(); - char[] buf = new char[len]; - TextUtils.getChars(text, 0, len, buf, 0); - - int commaCount = 0; - for (int i = 0; i < len; i++) { - if (buf[i] == ',') { - commaCount++; - } - } - - float[] wid; - - if (text instanceof Spanned) { - Spanned sp = (Spanned) text; - TextPaint temppaint = new TextPaint(); - wid = new float[len * 2]; - - int next; - for (int i = 0; i < len; i = next) { - next = sp.nextSpanTransition(i, len, MetricAffectingSpan.class); - - Styled.getTextWidths(p, temppaint, sp, i, next, wid, null); - System.arraycopy(wid, 0, wid, len + i, next - i); - } - - System.arraycopy(wid, len, wid, 0, len); - } else { - wid = new float[len]; - p.getTextWidths(text, 0, len, wid); - } - - int ok = 0; - int okRemaining = commaCount + 1; - String okFormat = ""; - - int w = 0; - int count = 0; - - for (int i = 0; i < len; i++) { - w += wid[i]; - - if (buf[i] == ',') { - count++; - - int remaining = commaCount - count + 1; - float moreWid; - String format; - - if (remaining == 1) { - format = " " + oneMore; - } else { - format = " " + String.format(more, remaining); - } - - moreWid = p.measureText(format); - - if (w + moreWid <= avail) { - ok = i + 1; - okRemaining = remaining; - okFormat = format; - } - } - } - - if (w <= avail) { - return text; - } else { - SpannableStringBuilder out = new SpannableStringBuilder(okFormat); - out.insert(0, text, 0, ok); - return out; - } - } - - /* package */ static char[] obtain(int len) { - char[] buf; - - synchronized (sLock) { - buf = sTemp; - sTemp = null; - } - - if (buf == null || buf.length < len) - buf = new char[ArrayUtils.idealCharArraySize(len)]; - - return buf; - } - - /* package */ static void recycle(char[] temp) { - if (temp.length > 1000) - return; - - synchronized (sLock) { - sTemp = temp; - } - } - - /** - * Html-encode the string. - * @param s the string to be encoded - * @return the encoded string - */ - public static String htmlEncode(String s) { - StringBuilder sb = new StringBuilder(); - char c; - for (int i = 0; i < s.length(); i++) { - c = s.charAt(i); - switch (c) { - case '<': - sb.append("<"); //$NON-NLS-1$ - break; - case '>': - sb.append(">"); //$NON-NLS-1$ - break; - case '&': - sb.append("&"); //$NON-NLS-1$ - break; - case '\'': - sb.append("'"); //$NON-NLS-1$ - break; - case '"': - sb.append("""); //$NON-NLS-1$ - break; - default: - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Returns a CharSequence concatenating the specified CharSequences, - * retaining their spans if any. - */ - public static CharSequence concat(CharSequence... text) { - if (text.length == 0) { - return ""; - } - - if (text.length == 1) { - return text[0]; - } - - boolean spanned = false; - for (int i = 0; i < text.length; i++) { - if (text[i] instanceof Spanned) { - spanned = true; - break; - } - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < text.length; i++) { - sb.append(text[i]); - } - - if (!spanned) { - return sb.toString(); - } - - SpannableString ss = new SpannableString(sb); - int off = 0; - for (int i = 0; i < text.length; i++) { - int len = text[i].length(); - - if (text[i] instanceof Spanned) { - copySpansFrom((Spanned) text[i], 0, len, Object.class, ss, off); - } - - off += len; - } - - return new SpannedString(ss); - } - - /** - * Returns whether the given CharSequence contains any printable characters. - */ - public static boolean isGraphic(CharSequence str) { - final int len = str.length(); - for (int i=0; i<len; i++) { - int gc = Character.getType(str.charAt(i)); - if (gc != Character.CONTROL - && gc != Character.FORMAT - && gc != Character.SURROGATE - && gc != Character.UNASSIGNED - && gc != Character.LINE_SEPARATOR - && gc != Character.PARAGRAPH_SEPARATOR - && gc != Character.SPACE_SEPARATOR) { - return true; - } - } - return false; - } - - /** - * Returns whether this character is a printable character. - */ - public static boolean isGraphic(char c) { - int gc = Character.getType(c); - return gc != Character.CONTROL - && gc != Character.FORMAT - && gc != Character.SURROGATE - && gc != Character.UNASSIGNED - && gc != Character.LINE_SEPARATOR - && gc != Character.PARAGRAPH_SEPARATOR - && gc != Character.SPACE_SEPARATOR; - } - - /** - * Returns whether the given CharSequence contains only digits. - */ - public static boolean isDigitsOnly(CharSequence str) { - final int len = str.length(); - for (int i = 0; i < len; i++) { - if (!Character.isDigit(str.charAt(i))) { - return false; - } - } - return true; - } - - /** - * Capitalization mode for {@link #getCapsMode}: capitalize all - * characters. This value is explicitly defined to be the same as - * {@link InputType#TYPE_TEXT_FLAG_CAP_CHARACTERS}. - */ - public static final int CAP_MODE_CHARACTERS - = InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; - - /** - * Capitalization mode for {@link #getCapsMode}: capitalize the first - * character of all words. This value is explicitly defined to be the same as - * {@link InputType#TYPE_TEXT_FLAG_CAP_WORDS}. - */ - public static final int CAP_MODE_WORDS - = InputType.TYPE_TEXT_FLAG_CAP_WORDS; - - /** - * Capitalization mode for {@link #getCapsMode}: capitalize the first - * character of each sentence. This value is explicitly defined to be the same as - * {@link InputType#TYPE_TEXT_FLAG_CAP_SENTENCES}. - */ - public static final int CAP_MODE_SENTENCES - = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; - - /** - * Determine what caps mode should be in effect at the current offset in - * the text. Only the mode bits set in <var>reqModes</var> will be - * checked. Note that the caps mode flags here are explicitly defined - * to match those in {@link InputType}. - * - * @param cs The text that should be checked for caps modes. - * @param off Location in the text at which to check. - * @param reqModes The modes to be checked: may be any combination of - * {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and - * {@link #CAP_MODE_SENTENCES}. - * - * @return Returns the actual capitalization modes that can be in effect - * at the current position, which is any combination of - * {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and - * {@link #CAP_MODE_SENTENCES}. - */ - public static int getCapsMode(CharSequence cs, int off, int reqModes) { - int i; - char c; - int mode = 0; - - if ((reqModes&CAP_MODE_CHARACTERS) != 0) { - mode |= CAP_MODE_CHARACTERS; - } - if ((reqModes&(CAP_MODE_WORDS|CAP_MODE_SENTENCES)) == 0) { - return mode; - } - - // Back over allowed opening punctuation. - - for (i = off; i > 0; i--) { - c = cs.charAt(i - 1); - - if (c != '"' && c != '\'' && - Character.getType(c) != Character.START_PUNCTUATION) { - break; - } - } - - // Start of paragraph, with optional whitespace. - - int j = i; - while (j > 0 && ((c = cs.charAt(j - 1)) == ' ' || c == '\t')) { - j--; - } - if (j == 0 || cs.charAt(j - 1) == '\n') { - return mode | CAP_MODE_WORDS; - } - - // Or start of word if we are that style. - - if ((reqModes&CAP_MODE_SENTENCES) == 0) { - if (i != j) mode |= CAP_MODE_WORDS; - return mode; - } - - // There must be a space if not the start of paragraph. - - if (i == j) { - return mode; - } - - // Back over allowed closing punctuation. - - for (; j > 0; j--) { - c = cs.charAt(j - 1); - - if (c != '"' && c != '\'' && - Character.getType(c) != Character.END_PUNCTUATION) { - break; - } - } - - if (j > 0) { - c = cs.charAt(j - 1); - - if (c == '.' || c == '?' || c == '!') { - // Do not capitalize if the word ends with a period but - // also contains a period, in which case it is an abbreviation. - - if (c == '.') { - for (int k = j - 2; k >= 0; k--) { - c = cs.charAt(k); - - if (c == '.') { - return mode; - } - - if (!Character.isLetter(c)) { - break; - } - } - } - - return mode | CAP_MODE_SENTENCES; - } - } - - return mode; - } - - private static Object sLock = new Object(); - private static char[] sTemp = null; -} diff --git a/core/java/android/text/TextWatcher.java b/core/java/android/text/TextWatcher.java deleted file mode 100644 index bad09f2..0000000 --- a/core/java/android/text/TextWatcher.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -/** - * When an object of a type is attached to an Editable, its methods will - * be called when the text is changed. - */ -public interface TextWatcher extends NoCopySpan { - /** - * This method is called to notify you that, within <code>s</code>, - * the <code>count</code> characters beginning at <code>start</code> - * are about to be replaced by new text with length <code>after</code>. - * It is an error to attempt to make changes to <code>s</code> from - * this callback. - */ - public void beforeTextChanged(CharSequence s, int start, - int count, int after); - /** - * This method is called to notify you that, within <code>s</code>, - * the <code>count</code> characters beginning at <code>start</code> - * have just replaced old text that had length <code>before</code>. - * It is an error to attempt to make changes to <code>s</code> from - * this callback. - */ - public void onTextChanged(CharSequence s, int start, int before, int count); - - /** - * This method is called to notify you that, somewhere within - * <code>s</code>, the text has been changed. - * It is legitimate to make further changes to <code>s</code> from - * this callback, but be careful not to get yourself into an infinite - * loop, because any changes you make will cause this method to be - * called again recursively. - * (You are not told where the change took place because other - * afterTextChanged() methods may already have made other changes - * and invalidated the offsets. But if you need to know here, - * you can use {@link Spannable#setSpan} in {@link #onTextChanged} - * to mark your place and then look up from here where the span - * ended up. - */ - public void afterTextChanged(Editable s); -} diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java deleted file mode 100644 index 0dc96c3..0000000 --- a/core/java/android/text/format/DateFormat.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.format; - -import android.content.Context; -import android.provider.Settings; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.SpannedString; - -import com.android.internal.R; - -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Locale; -import java.util.TimeZone; -import java.text.SimpleDateFormat; - -/** - Utility class for producing strings with formatted date/time. - - <p> - This class takes as inputs a format string and a representation of a date/time. - The format string controls how the output is generated. - </p> - <p> - Formatting characters may be repeated in order to get more detailed representations - of that field. For instance, the format character 'M' is used to - represent the month. Depending on how many times that character is repeated - you get a different representation. - </p> - <p> - For the month of September:<br/> - M -> 9<br/> - MM -> 09<br/> - MMM -> Sep<br/> - MMMM -> September - </p> - <p> - The effects of the duplication vary depending on the nature of the field. - See the notes on the individual field formatters for details. For purely numeric - fields such as <code>HOUR</code> adding more copies of the designator will - zero-pad the value to that number of characters. - </p> - <p> - For 7 minutes past the hour:<br/> - m -> 7<br/> - mm -> 07<br/> - mmm -> 007<br/> - mmmm -> 0007 - </p> - <p> - Examples for April 6, 1970 at 3:23am:<br/> - "MM/dd/yy h:mmaa" -> "04/06/70 3:23am"<br/> - "MMM dd, yyyy h:mmaa" -> "Apr 6, 1970 3:23am"<br/> - "MMMM dd, yyyy h:mmaa" -> "April 6, 1970 3:23am"<br/> - "E, MMMM dd, yyyy h:mmaa" -> "Mon, April 6, 1970 3:23am&<br/> - "EEEE, MMMM dd, yyyy h:mmaa" -> "Monday, April 6, 1970 3:23am"<br/> - "'Noteworthy day: 'M/d/yy" -> "Noteworthy day: 4/6/70" - */ - -public class DateFormat { - /** - Text in the format string that should be copied verbatim rather that - interpreted as formatting codes must be surrounded by the <code>QUOTE</code> - character. If you need to embed a literal <code>QUOTE</code> character in - the output text then use two in a row. - */ - public static final char QUOTE = '\''; - - /** - This designator indicates whether the <code>HOUR</code> field is before - or after noon. The output is lower-case. - - Examples: - a -> a or p - aa -> am or pm - */ - public static final char AM_PM = 'a'; - - /** - This designator indicates whether the <code>HOUR</code> field is before - or after noon. The output is capitalized. - - Examples: - A -> A or P - AA -> AM or PM - */ - public static final char CAPITAL_AM_PM = 'A'; - - /** - This designator indicates the day of the month. - - Examples for the 9th of the month: - d -> 9 - dd -> 09 - */ - public static final char DATE = 'd'; - - /** - This designator indicates the name of the day of the week. - - Examples for Sunday: - E -> Sun - EEEE -> Sunday - */ - public static final char DAY = 'E'; - - /** - This designator indicates the hour of the day in 12 hour format. - - Examples for 3pm: - h -> 3 - hh -> 03 - */ - public static final char HOUR = 'h'; - - /** - This designator indicates the hour of the day in 24 hour format. - - Example for 3pm: - k -> 15 - - Examples for midnight: - k -> 0 - kk -> 00 - */ - public static final char HOUR_OF_DAY = 'k'; - - /** - This designator indicates the minute of the hour. - - Examples for 7 minutes past the hour: - m -> 7 - mm -> 07 - */ - public static final char MINUTE = 'm'; - - /** - This designator indicates the month of the year - - Examples for September: - M -> 9 - MM -> 09 - MMM -> Sep - MMMM -> September - */ - public static final char MONTH = 'M'; - - /** - This designator indicates the seconds of the minute. - - Examples for 7 seconds past the minute: - s -> 7 - ss -> 07 - */ - public static final char SECONDS = 's'; - - /** - This designator indicates the offset of the timezone from GMT. - - Example for US/Pacific timezone: - z -> -0800 - zz -> PST - */ - public static final char TIME_ZONE = 'z'; - - /** - This designator indicates the year. - - Examples for 2006 - y -> 06 - yyyy -> 2006 - */ - public static final char YEAR = 'y'; - - - private static final Object sLocaleLock = new Object(); - private static Locale sIs24HourLocale; - private static boolean sIs24Hour; - - - /** - * Returns true if user preference is set to 24-hour format. - * @param context the context to use for the content resolver - * @return true if 24 hour time format is selected, false otherwise. - */ - public static boolean is24HourFormat(Context context) { - String value = Settings.System.getString(context.getContentResolver(), - Settings.System.TIME_12_24); - - if (value == null) { - Locale locale = context.getResources().getConfiguration().locale; - - synchronized (sLocaleLock) { - if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) { - return sIs24Hour; - } - } - - java.text.DateFormat natural = - java.text.DateFormat.getTimeInstance( - java.text.DateFormat.LONG, locale); - - if (natural instanceof SimpleDateFormat) { - SimpleDateFormat sdf = (SimpleDateFormat) natural; - String pattern = sdf.toPattern(); - - if (pattern.indexOf('H') >= 0) { - value = "24"; - } else { - value = "12"; - } - } else { - value = "12"; - } - - synchronized (sLocaleLock) { - sIs24HourLocale = locale; - sIs24Hour = !value.equals("12"); - } - } - - boolean b24 = !(value == null || value.equals("12")); - return b24; - } - - /** - * Returns a {@link java.text.DateFormat} object that can format the time according - * to the current user preference. - * @param context the application context - * @return the {@link java.text.DateFormat} object that properly formats the time. - */ - public static final java.text.DateFormat getTimeFormat(Context context) { - boolean b24 = is24HourFormat(context); - int res; - - if (b24) { - res = R.string.twenty_four_hour_time_format; - } else { - res = R.string.twelve_hour_time_format; - } - - return new java.text.SimpleDateFormat(context.getString(res)); - } - - /** - * Returns a {@link java.text.DateFormat} object that can format the date according - * to the current user preference. - * @param context the application context - * @return the {@link java.text.DateFormat} object that properly formats the date. - */ - public static final java.text.DateFormat getDateFormat(Context context) { - String value = getDateFormatString(context); - return new java.text.SimpleDateFormat(value); - } - - /** - * Returns a {@link java.text.DateFormat} object that can format the date - * in long form (such as December 31, 1999) based on user preference. - * @param context the application context - * @return the {@link java.text.DateFormat} object that formats the date in long form. - */ - public static final java.text.DateFormat getLongDateFormat(Context context) { - String value = getDateFormatString(context); - if (value.indexOf('M') < value.indexOf('d')) { - value = context.getString(R.string.full_date_month_first); - } else { - value = context.getString(R.string.full_date_day_first); - } - return new java.text.SimpleDateFormat(value); - } - - /** - * Returns a {@link java.text.DateFormat} object that can format the date - * in medium form (such as Dec. 31, 1999) based on user preference. - * @param context the application context - * @return the {@link java.text.DateFormat} object that formats the date in long form. - */ - public static final java.text.DateFormat getMediumDateFormat(Context context) { - String value = getDateFormatString(context); - if (value.indexOf('M') < value.indexOf('d')) { - value = context.getString(R.string.medium_date_month_first); - } else { - value = context.getString(R.string.medium_date_day_first); - } - return new java.text.SimpleDateFormat(value); - } - - /** - * Gets the current date format stored as a char array. The array will contain - * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order - * preferred by the user. - */ - public static final char[] getDateFormatOrder(Context context) { - char[] order = new char[] {DATE, MONTH, YEAR}; - String value = getDateFormatString(context); - int index = 0; - boolean foundDate = false; - boolean foundMonth = false; - boolean foundYear = false; - - for (char c : value.toCharArray()) { - if (!foundDate && (c == DATE)) { - foundDate = true; - order[index] = DATE; - index++; - } - - if (!foundMonth && (c == MONTH)) { - foundMonth = true; - order[index] = MONTH; - index++; - } - - if (!foundYear && (c == YEAR)) { - foundYear = true; - order[index] = YEAR; - index++; - } - } - return order; - } - - private static String getDateFormatString(Context context) { - String value = Settings.System.getString(context.getContentResolver(), - Settings.System.DATE_FORMAT); - if (value == null || value.length() < 6) { - /* - * No need to localize -- this is an emergency fallback in case - * the setting is missing, but it should always be set. - */ - value = "MM-dd-yyyy"; - } - return value; - } - - /** - * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a - * CharSequence containing the requested date. - * @param inFormat the format string, as described in {@link android.text.format.DateFormat} - * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT - * @return a {@link CharSequence} containing the requested text - */ - public static final CharSequence format(CharSequence inFormat, long inTimeInMillis) { - return format(inFormat, new Date(inTimeInMillis)); - } - - /** - * Given a format string and a {@link java.util.Date} object, returns a CharSequence containing - * the requested date. - * @param inFormat the format string, as described in {@link android.text.format.DateFormat} - * @param inDate the date to format - * @return a {@link CharSequence} containing the requested text - */ - public static final CharSequence format(CharSequence inFormat, Date inDate) { - Calendar c = new GregorianCalendar(); - - c.setTime(inDate); - - return format(inFormat, c); - } - - /** - * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence - * containing the requested date. - * @param inFormat the format string, as described in {@link android.text.format.DateFormat} - * @param inDate the date to format - * @return a {@link CharSequence} containing the requested text - */ - public static final CharSequence format(CharSequence inFormat, Calendar inDate) { - SpannableStringBuilder s = new SpannableStringBuilder(inFormat); - int c; - int count; - - int len = inFormat.length(); - - for (int i = 0; i < len; i += count) { - int temp; - - count = 1; - c = s.charAt(i); - - if (c == QUOTE) { - count = appendQuotedText(s, i, len); - len = s.length(); - continue; - } - - while ((i + count < len) && (s.charAt(i + count) == c)) { - count++; - } - - String replacement; - - switch (c) { - case AM_PM: - replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM)); - break; - - case CAPITAL_AM_PM: - //FIXME: this is the same as AM_PM? no capital? - replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM)); - break; - - case DATE: - replacement = zeroPad(inDate.get(Calendar.DATE), count); - break; - - case DAY: - temp = inDate.get(Calendar.DAY_OF_WEEK); - replacement = DateUtils.getDayOfWeekString(temp, - count < 4 ? - DateUtils.LENGTH_MEDIUM : - DateUtils.LENGTH_LONG); - break; - - case HOUR: - temp = inDate.get(Calendar.HOUR); - - if (0 == temp) - temp = 12; - - replacement = zeroPad(temp, count); - break; - - case HOUR_OF_DAY: - replacement = zeroPad(inDate.get(Calendar.HOUR_OF_DAY), count); - break; - - case MINUTE: - replacement = zeroPad(inDate.get(Calendar.MINUTE), count); - break; - - case MONTH: - replacement = getMonthString(inDate, count); - break; - - case SECONDS: - replacement = zeroPad(inDate.get(Calendar.SECOND), count); - break; - - case TIME_ZONE: - replacement = getTimeZoneString(inDate, count); - break; - - case YEAR: - replacement = getYearString(inDate, count); - break; - - default: - replacement = null; - break; - } - - if (replacement != null) { - s.replace(i, i + count, replacement); - count = replacement.length(); // CARE: count is used in the for loop above - len = s.length(); - } - } - - if (inFormat instanceof Spanned) - return new SpannedString(s); - else - return s.toString(); - } - - private static final String getMonthString(Calendar inDate, int count) { - int month = inDate.get(Calendar.MONTH); - - if (count >= 4) - return DateUtils.getMonthString(month, DateUtils.LENGTH_LONG); - else if (count == 3) - return DateUtils.getMonthString(month, DateUtils.LENGTH_MEDIUM); - else { - // Calendar.JANUARY == 0, so add 1 to month. - return zeroPad(month+1, count); - } - } - - private static final String getTimeZoneString(Calendar inDate, int count) { - TimeZone tz = inDate.getTimeZone(); - - if (count < 2) { // FIXME: shouldn't this be <= 2 ? - return formatZoneOffset(inDate.get(Calendar.DST_OFFSET) + - inDate.get(Calendar.ZONE_OFFSET), - count); - } else { - boolean dst = inDate.get(Calendar.DST_OFFSET) != 0; - return tz.getDisplayName(dst, TimeZone.SHORT); - } - } - - private static final String formatZoneOffset(int offset, int count) { - offset /= 1000; // milliseconds to seconds - StringBuilder tb = new StringBuilder(); - - if (offset < 0) { - tb.insert(0, "-"); - offset = -offset; - } else { - tb.insert(0, "+"); - } - - int hours = offset / 3600; - int minutes = (offset % 3600) / 60; - - tb.append(zeroPad(hours, 2)); - tb.append(zeroPad(minutes, 2)); - return tb.toString(); - } - - private static final String getYearString(Calendar inDate, int count) { - int year = inDate.get(Calendar.YEAR); - return (count <= 2) ? zeroPad(year % 100, 2) : String.valueOf(year); - } - - private static final int appendQuotedText(SpannableStringBuilder s, int i, int len) { - if (i + 1 < len && s.charAt(i + 1) == QUOTE) { - s.delete(i, i + 1); - return 1; - } - - int count = 0; - - // delete leading quote - s.delete(i, i + 1); - len--; - - while (i < len) { - char c = s.charAt(i); - - if (c == QUOTE) { - // QUOTEQUOTE -> QUOTE - if (i + 1 < len && s.charAt(i + 1) == QUOTE) { - - s.delete(i, i + 1); - len--; - count++; - i++; - } else { - // Closing QUOTE ends quoted text copying - s.delete(i, i + 1); - break; - } - } else { - i++; - count++; - } - } - - return count; - } - - private static final String zeroPad(int inValue, int inMinDigits) { - String val = String.valueOf(inValue); - - if (val.length() < inMinDigits) { - char[] buf = new char[inMinDigits]; - - for (int i = 0; i < inMinDigits; i++) - buf[i] = '0'; - - val.getChars(0, val.length(), buf, inMinDigits - val.length()); - val = new String(buf); - } - return val; - } -} diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java deleted file mode 100644 index feae6cf..0000000 --- a/core/java/android/text/format/DateUtils.java +++ /dev/null @@ -1,1581 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.format; - -import com.android.internal.R; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.pim.DateException; - -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; - -/** - * This class contains various date-related utilities for creating text for things like - * elapsed time and date ranges, strings for days of the week and months, and AM/PM text etc. - */ -public class DateUtils -{ - private static final Object sLock = new Object(); - private static final int[] sDaysLong = new int[] { - com.android.internal.R.string.day_of_week_long_sunday, - com.android.internal.R.string.day_of_week_long_monday, - com.android.internal.R.string.day_of_week_long_tuesday, - com.android.internal.R.string.day_of_week_long_wednesday, - com.android.internal.R.string.day_of_week_long_thursday, - com.android.internal.R.string.day_of_week_long_friday, - com.android.internal.R.string.day_of_week_long_saturday, - }; - private static final int[] sDaysMedium = new int[] { - com.android.internal.R.string.day_of_week_medium_sunday, - com.android.internal.R.string.day_of_week_medium_monday, - com.android.internal.R.string.day_of_week_medium_tuesday, - com.android.internal.R.string.day_of_week_medium_wednesday, - com.android.internal.R.string.day_of_week_medium_thursday, - com.android.internal.R.string.day_of_week_medium_friday, - com.android.internal.R.string.day_of_week_medium_saturday, - }; - private static final int[] sDaysShort = new int[] { - com.android.internal.R.string.day_of_week_short_sunday, - com.android.internal.R.string.day_of_week_short_monday, - com.android.internal.R.string.day_of_week_short_tuesday, - com.android.internal.R.string.day_of_week_short_wednesday, - com.android.internal.R.string.day_of_week_short_thursday, - com.android.internal.R.string.day_of_week_short_friday, - com.android.internal.R.string.day_of_week_short_saturday, - }; - private static final int[] sDaysShorter = new int[] { - com.android.internal.R.string.day_of_week_shorter_sunday, - com.android.internal.R.string.day_of_week_shorter_monday, - com.android.internal.R.string.day_of_week_shorter_tuesday, - com.android.internal.R.string.day_of_week_shorter_wednesday, - com.android.internal.R.string.day_of_week_shorter_thursday, - com.android.internal.R.string.day_of_week_shorter_friday, - com.android.internal.R.string.day_of_week_shorter_saturday, - }; - private static final int[] sDaysShortest = new int[] { - com.android.internal.R.string.day_of_week_shortest_sunday, - com.android.internal.R.string.day_of_week_shortest_monday, - com.android.internal.R.string.day_of_week_shortest_tuesday, - com.android.internal.R.string.day_of_week_shortest_wednesday, - com.android.internal.R.string.day_of_week_shortest_thursday, - com.android.internal.R.string.day_of_week_shortest_friday, - com.android.internal.R.string.day_of_week_shortest_saturday, - }; - private static final int[] sMonthsLong = new int [] { - com.android.internal.R.string.month_long_january, - com.android.internal.R.string.month_long_february, - com.android.internal.R.string.month_long_march, - com.android.internal.R.string.month_long_april, - com.android.internal.R.string.month_long_may, - com.android.internal.R.string.month_long_june, - com.android.internal.R.string.month_long_july, - com.android.internal.R.string.month_long_august, - com.android.internal.R.string.month_long_september, - com.android.internal.R.string.month_long_october, - com.android.internal.R.string.month_long_november, - com.android.internal.R.string.month_long_december, - }; - private static final int[] sMonthsMedium = new int [] { - com.android.internal.R.string.month_medium_january, - com.android.internal.R.string.month_medium_february, - com.android.internal.R.string.month_medium_march, - com.android.internal.R.string.month_medium_april, - com.android.internal.R.string.month_medium_may, - com.android.internal.R.string.month_medium_june, - com.android.internal.R.string.month_medium_july, - com.android.internal.R.string.month_medium_august, - com.android.internal.R.string.month_medium_september, - com.android.internal.R.string.month_medium_october, - com.android.internal.R.string.month_medium_november, - com.android.internal.R.string.month_medium_december, - }; - private static final int[] sMonthsShortest = new int [] { - com.android.internal.R.string.month_shortest_january, - com.android.internal.R.string.month_shortest_february, - com.android.internal.R.string.month_shortest_march, - com.android.internal.R.string.month_shortest_april, - com.android.internal.R.string.month_shortest_may, - com.android.internal.R.string.month_shortest_june, - com.android.internal.R.string.month_shortest_july, - com.android.internal.R.string.month_shortest_august, - com.android.internal.R.string.month_shortest_september, - com.android.internal.R.string.month_shortest_october, - com.android.internal.R.string.month_shortest_november, - com.android.internal.R.string.month_shortest_december, - }; - private static final int[] sAmPm = new int[] { - com.android.internal.R.string.am, - com.android.internal.R.string.pm, - }; - private static Configuration sLastConfig; - private static String sStatusTimeFormat; - private static String sElapsedFormatMMSS; - private static String sElapsedFormatHMMSS; - - private static final String FAST_FORMAT_HMMSS = "%1$d:%2$02d:%3$02d"; - private static final String FAST_FORMAT_MMSS = "%1$02d:%2$02d"; - private static final char TIME_PADDING = '0'; - private static final char TIME_SEPARATOR = ':'; - - - public static final long SECOND_IN_MILLIS = 1000; - public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60; - public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60; - public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24; - public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7; - public static final long YEAR_IN_MILLIS = WEEK_IN_MILLIS * 52; - - // The following FORMAT_* symbols are used for specifying the format of - // dates and times in the formatDateRange method. - public static final int FORMAT_SHOW_TIME = 0x00001; - public static final int FORMAT_SHOW_WEEKDAY = 0x00002; - public static final int FORMAT_SHOW_YEAR = 0x00004; - public static final int FORMAT_NO_YEAR = 0x00008; - public static final int FORMAT_SHOW_DATE = 0x00010; - public static final int FORMAT_NO_MONTH_DAY = 0x00020; - public static final int FORMAT_12HOUR = 0x00040; - public static final int FORMAT_24HOUR = 0x00080; - public static final int FORMAT_CAP_AMPM = 0x00100; - public static final int FORMAT_NO_NOON = 0x00200; - public static final int FORMAT_CAP_NOON = 0x00400; - public static final int FORMAT_NO_MIDNIGHT = 0x00800; - public static final int FORMAT_CAP_MIDNIGHT = 0x01000; - public static final int FORMAT_UTC = 0x02000; - public static final int FORMAT_ABBREV_TIME = 0x04000; - public static final int FORMAT_ABBREV_WEEKDAY = 0x08000; - public static final int FORMAT_ABBREV_MONTH = 0x10000; - public static final int FORMAT_NUMERIC_DATE = 0x20000; - public static final int FORMAT_ABBREV_RELATIVE = 0x40000; - public static final int FORMAT_ABBREV_ALL = 0x80000; - public static final int FORMAT_CAP_NOON_MIDNIGHT = (FORMAT_CAP_NOON | FORMAT_CAP_MIDNIGHT); - public static final int FORMAT_NO_NOON_MIDNIGHT = (FORMAT_NO_NOON | FORMAT_NO_MIDNIGHT); - - // Date and time format strings that are constant and don't need to be - // translated. - public static final String HOUR_MINUTE_24 = "%H:%M"; - public static final String MONTH_FORMAT = "%B"; - public static final String ABBREV_MONTH_FORMAT = "%b"; - public static final String NUMERIC_MONTH_FORMAT = "%m"; - public static final String MONTH_DAY_FORMAT = "%-d"; - public static final String YEAR_FORMAT = "%Y"; - public static final String YEAR_FORMAT_TWO_DIGITS = "%g"; - public static final String WEEKDAY_FORMAT = "%A"; - public static final String ABBREV_WEEKDAY_FORMAT = "%a"; - - // This table is used to lookup the resource string id of a format string - // used for formatting a start and end date that fall in the same year. - // The index is constructed from a bit-wise OR of the boolean values: - // {showTime, showYear, showWeekDay}. For example, if showYear and - // showWeekDay are both true, then the index would be 3. - public static final int sameYearTable[] = { - com.android.internal.R.string.same_year_md1_md2, - com.android.internal.R.string.same_year_wday1_md1_wday2_md2, - com.android.internal.R.string.same_year_mdy1_mdy2, - com.android.internal.R.string.same_year_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.same_year_md1_time1_md2_time2, - com.android.internal.R.string.same_year_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.same_year_mdy1_time1_mdy2_time2, - com.android.internal.R.string.same_year_wday1_mdy1_time1_wday2_mdy2_time2, - - // Numeric date strings - com.android.internal.R.string.numeric_md1_md2, - com.android.internal.R.string.numeric_wday1_md1_wday2_md2, - com.android.internal.R.string.numeric_mdy1_mdy2, - com.android.internal.R.string.numeric_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.numeric_md1_time1_md2_time2, - com.android.internal.R.string.numeric_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.numeric_mdy1_time1_mdy2_time2, - com.android.internal.R.string.numeric_wday1_mdy1_time1_wday2_mdy2_time2, - }; - - // This table is used to lookup the resource string id of a format string - // used for formatting a start and end date that fall in the same month. - // The index is constructed from a bit-wise OR of the boolean values: - // {showTime, showYear, showWeekDay}. For example, if showYear and - // showWeekDay are both true, then the index would be 3. - public static final int sameMonthTable[] = { - com.android.internal.R.string.same_month_md1_md2, - com.android.internal.R.string.same_month_wday1_md1_wday2_md2, - com.android.internal.R.string.same_month_mdy1_mdy2, - com.android.internal.R.string.same_month_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.same_month_md1_time1_md2_time2, - com.android.internal.R.string.same_month_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.same_month_mdy1_time1_mdy2_time2, - com.android.internal.R.string.same_month_wday1_mdy1_time1_wday2_mdy2_time2, - - com.android.internal.R.string.numeric_md1_md2, - com.android.internal.R.string.numeric_wday1_md1_wday2_md2, - com.android.internal.R.string.numeric_mdy1_mdy2, - com.android.internal.R.string.numeric_wday1_mdy1_wday2_mdy2, - com.android.internal.R.string.numeric_md1_time1_md2_time2, - com.android.internal.R.string.numeric_wday1_md1_time1_wday2_md2_time2, - com.android.internal.R.string.numeric_mdy1_time1_mdy2_time2, - com.android.internal.R.string.numeric_wday1_mdy1_time1_wday2_mdy2_time2, - }; - - /** - * Request the full spelled-out name. For use with the 'abbrev' parameter of - * {@link #getDayOfWeekString} and {@link #getMonthString}. - * - * @more <p> - * e.g. "Sunday" or "January" - */ - public static final int LENGTH_LONG = 10; - - /** - * Request an abbreviated version of the name. For use with the 'abbrev' - * parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. - * - * @more <p> - * e.g. "Sun" or "Jan" - */ - public static final int LENGTH_MEDIUM = 20; - - /** - * Request a shorter abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. - * @more - * <p>e.g. "Su" or "Jan" - * <p>In some languages, the results returned for LENGTH_SHORT may be the same as - * return for {@link #LENGTH_MEDIUM}. - */ - public static final int LENGTH_SHORT = 30; - - /** - * Request an even shorter abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. - * @more - * <p>e.g. "M", "Tu", "Th" or "J" - * <p>In some languages, the results returned for LENGTH_SHORTEST may be the same as - * return for {@link #LENGTH_SHORTER}. - */ - public static final int LENGTH_SHORTER = 40; - - /** - * Request an even shorter abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. - * @more - * <p>e.g. "S", "T", "T" or "J" - * <p>In some languages, the results returned for LENGTH_SHORTEST may be the same as - * return for {@link #LENGTH_SHORTER}. - */ - public static final int LENGTH_SHORTEST = 50; - - /** - * Return a string for the day of the week. - * @param dayOfWeek One of {@link Calendar#SUNDAY Calendar.SUNDAY}, - * {@link Calendar#MONDAY Calendar.MONDAY}, etc. - * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_SHORT}, {@link #LENGTH_SHORTER} - * or {@link #LENGTH_SHORTEST}. For forward compatibility, anything else - * will return the same as {#LENGTH_MEDIUM}. - * @throws IndexOutOfBoundsException if the dayOfWeek is out of bounds. - */ - public static String getDayOfWeekString(int dayOfWeek, int abbrev) { - int[] list; - switch (abbrev) { - case LENGTH_LONG: list = sDaysLong; break; - case LENGTH_MEDIUM: list = sDaysMedium; break; - case LENGTH_SHORT: list = sDaysShort; break; - case LENGTH_SHORTER: list = sDaysShorter; break; - case LENGTH_SHORTEST: list = sDaysShortest; break; - default: list = sDaysMedium; break; - } - - Resources r = Resources.getSystem(); - return r.getString(list[dayOfWeek - Calendar.SUNDAY]); - } - - /** - * Return a localized string for AM or PM. - * @param ampm Either {@link Calendar#AM Calendar.AM} or {@link Calendar#PM Calendar.PM}. - * @throws IndexOutOfBoundsException if the ampm is out of bounds. - * @return Localized version of "AM" or "PM". - */ - public static String getAMPMString(int ampm) { - Resources r = Resources.getSystem(); - return r.getString(sAmPm[ampm - Calendar.AM]); - } - - /** - * Return a localized string for the day of the week. - * @param month One of {@link Calendar#JANUARY Calendar.JANUARY}, - * {@link Calendar#FEBRUARY Calendar.FEBRUARY}, etc. - * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_SHORT}, {@link #LENGTH_SHORTER} - * or {@link #LENGTH_SHORTEST}. For forward compatibility, anything else - * will return the same as {#LENGTH_MEDIUM}. - * @return Localized day of the week. - */ - public static String getMonthString(int month, int abbrev) { - // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER. - // This is a shortcut to not spam the translators with too many variations - // of the same string. If we find that in a language the distinction - // is necessary, we can can add more without changing this API. - int[] list; - switch (abbrev) { - case LENGTH_LONG: list = sMonthsLong; break; - case LENGTH_MEDIUM: list = sMonthsMedium; break; - case LENGTH_SHORT: list = sMonthsMedium; break; - case LENGTH_SHORTER: list = sMonthsMedium; break; - case LENGTH_SHORTEST: list = sMonthsShortest; break; - default: list = sMonthsMedium; break; - } - - Resources r = Resources.getSystem(); - return r.getString(list[month - Calendar.JANUARY]); - } - - /** - * Returns a string describing the elapsed time since startTime. - * @param startTime some time in the past. - * @return a String object containing the elapsed time. - * @see #getRelativeTimeSpanString(long, long, long) - */ - public static CharSequence getRelativeTimeSpanString(long startTime) { - return getRelativeTimeSpanString(startTime, System.currentTimeMillis(), MINUTE_IN_MILLIS); - } - - /** - * Returns a string describing 'time' as a time relative to 'now'. - * <p> - * Time spans in the past are formatted like "42 minutes ago". - * Time spans in the future are formatted like "in 42 minutes". - * - * @param time the time to describe, in milliseconds - * @param now the current time in milliseconds - * @param minResolution the minimum timespan to report. For example, a time 3 seconds in the - * past will be reported as "0 minutes ago" if this is set to MINUTE_IN_MILLIS. Pass one of - * 0, MINUTE_IN_MILLIS, HOUR_IN_MILLIS, DAY_IN_MILLIS, WEEK_IN_MILLIS - */ - public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) { - int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH; - return getRelativeTimeSpanString(time, now, minResolution, flags); - } - - /** - * Returns a string describing 'time' as a time relative to 'now'. - * <p> - * Time spans in the past are formatted like "42 minutes ago". Time spans in - * the future are formatted like "in 42 minutes". - * <p> - * Can use {@link #FORMAT_ABBREV_RELATIVE} flag to use abbreviated relative - * times, like "42 mins ago". - * - * @param time the time to describe, in milliseconds - * @param now the current time in milliseconds - * @param minResolution the minimum timespan to report. For example, a time - * 3 seconds in the past will be reported as "0 minutes ago" if - * this is set to MINUTE_IN_MILLIS. Pass one of 0, - * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, DAY_IN_MILLIS, - * WEEK_IN_MILLIS - * @param flags a bit mask of formatting options, such as - * {@link #FORMAT_NUMERIC_DATE} or - * {@link #FORMAT_ABBREV_RELATIVE} - */ - public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, - int flags) { - Resources r = Resources.getSystem(); - boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0; - - boolean past = (now >= time); - long duration = Math.abs(now - time); - - int resId; - long count; - if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) { - count = duration / SECOND_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_seconds_ago; - } else { - resId = com.android.internal.R.plurals.num_seconds_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_seconds; - } else { - resId = com.android.internal.R.plurals.in_num_seconds; - } - } - } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { - count = duration / MINUTE_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_minutes_ago; - } else { - resId = com.android.internal.R.plurals.num_minutes_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_minutes; - } else { - resId = com.android.internal.R.plurals.in_num_minutes; - } - } - } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { - count = duration / HOUR_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_hours_ago; - } else { - resId = com.android.internal.R.plurals.num_hours_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_hours; - } else { - resId = com.android.internal.R.plurals.in_num_hours; - } - } - } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) { - count = duration / DAY_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_days_ago; - } else { - resId = com.android.internal.R.plurals.num_days_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_days; - } else { - resId = com.android.internal.R.plurals.in_num_days; - } - } - } else { - // We know that we won't be showing the time, so it is safe to pass - // in a null context. - return formatDateRange(null, time, time, flags); - } - - String format = r.getQuantityString(resId, (int) count); - return String.format(format, count); - } - - /** - * Return string describing the elapsed time since startTime formatted like - * "[relative time/date], [time]". - * <p> - * Example output strings for the US date format. - * <ul> - * <li>3 mins ago, 10:15 AM</li> - * <li>yesterday, 12:20 PM</li> - * <li>Dec 12, 4:12 AM</li> - * <li>11/14/2007, 8:20 AM</li> - * </ul> - * - * @param time some time in the past. - * @param minResolution the minimum elapsed time (in milliseconds) to report - * when showing relative times. For example, a time 3 seconds in - * the past will be reported as "0 minutes ago" if this is set to - * {@link #MINUTE_IN_MILLIS}. - * @param transitionResolution the elapsed time (in milliseconds) at which - * to stop reporting relative measurements. Elapsed times greater - * than this resolution will default to normal date formatting. - * For example, will transition from "6 days ago" to "Dec 12" - * when using {@link #WEEK_IN_MILLIS}. - */ - public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, - long transitionResolution, int flags) { - Resources r = Resources.getSystem(); - - long now = System.currentTimeMillis(); - long duration = Math.abs(now - time); - - // getRelativeTimeSpanString() doesn't correctly format relative dates - // above a week or exact dates below a day, so clamp - // transitionResolution as needed. - if (transitionResolution > WEEK_IN_MILLIS) { - transitionResolution = WEEK_IN_MILLIS; - } else if (transitionResolution < DAY_IN_MILLIS) { - transitionResolution = DAY_IN_MILLIS; - } - - CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME); - - String result; - if (duration < transitionResolution) { - CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags); - result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause); - } else { - CharSequence dateClause = getRelativeTimeSpanString(c, time, false); - result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause); - } - - return result; - } - - /** - * Returns a string describing a day relative to the current day. For example if the day is - * today this function returns "Today", if the day was a week ago it returns "7 days ago", and - * if the day is in 2 weeks it returns "in 14 days". - * - * @param r the resources to get the strings from - * @param day the relative day to describe in UTC milliseconds - * @param today the current time in UTC milliseconds - * @return a formatting string - */ - private static final String getRelativeDayString(Resources r, long day, long today) { - Time startTime = new Time(); - startTime.set(day); - Time currentTime = new Time(); - currentTime.set(today); - - int startDay = Time.getJulianDay(day, startTime.gmtoff); - int currentDay = Time.getJulianDay(today, currentTime.gmtoff); - - int days = Math.abs(currentDay - startDay); - boolean past = (today > day); - - if (days == 1) { - if (past) { - return r.getString(com.android.internal.R.string.yesterday); - } else { - return r.getString(com.android.internal.R.string.tomorrow); - } - } else if (days == 0) { - return r.getString(com.android.internal.R.string.today); - } - - int resId; - if (past) { - resId = com.android.internal.R.plurals.num_days_ago; - } else { - resId = com.android.internal.R.plurals.in_num_days; - } - - String format = r.getQuantityString(resId, days); - return String.format(format, days); - } - - private static void initFormatStrings() { - synchronized (sLock) { - Resources r = Resources.getSystem(); - Configuration cfg = r.getConfiguration(); - if (sLastConfig == null || !sLastConfig.equals(cfg)) { - sLastConfig = cfg; - sStatusTimeFormat = r.getString(com.android.internal.R.string.status_bar_time_format); - sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss); - sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss); - } - } - } - - /** - * Format a time so it appears like it would in the status bar clock. - * @deprecated use {@link #DateFormat.getTimeFormat(Context)} instead. - * @hide - */ - public static final CharSequence timeString(long millis) { - initFormatStrings(); - return DateFormat.format(sStatusTimeFormat, millis); - } - - /** - * Formats an elapsed time in the form "MM:SS" or "H:MM:SS" - * for display on the call-in-progress screen. - * @param elapsedSeconds the elapsed time in seconds. - */ - public static String formatElapsedTime(long elapsedSeconds) { - initFormatStrings(); - - long hours = 0; - long minutes = 0; - long seconds = 0; - - if (elapsedSeconds >= 3600) { - hours = elapsedSeconds / 3600; - elapsedSeconds -= hours * 3600; - } - if (elapsedSeconds >= 60) { - minutes = elapsedSeconds / 60; - elapsedSeconds -= minutes * 60; - } - seconds = elapsedSeconds; - - String result; - if (hours > 0) { - return formatElapsedTime(sElapsedFormatHMMSS, hours, minutes, seconds); - } else { - return formatElapsedTime(sElapsedFormatMMSS, minutes, seconds); - } - } - - /** - * Fast formatting of h:mm:ss - */ - private static String formatElapsedTime(String format, long hours, long minutes, long seconds) { - if (FAST_FORMAT_HMMSS.equals(format)) { - StringBuffer sb = new StringBuffer(16); - sb.append(hours); - sb.append(TIME_SEPARATOR); - if (minutes < 10) { - sb.append(TIME_PADDING); - } else { - sb.append(toDigitChar(minutes / 10)); - } - sb.append(toDigitChar(minutes % 10)); - sb.append(TIME_SEPARATOR); - if (seconds < 10) { - sb.append(TIME_PADDING); - } else { - sb.append(toDigitChar(seconds / 10)); - } - sb.append(toDigitChar(seconds % 10)); - return sb.toString(); - } else { - return String.format(format, hours, minutes, seconds); - } - } - - /** - * Fast formatting of m:ss - */ - private static String formatElapsedTime(String format, long minutes, long seconds) { - if (FAST_FORMAT_MMSS.equals(format)) { - StringBuffer sb = new StringBuffer(16); - if (minutes < 10) { - sb.append(TIME_PADDING); - } else { - sb.append(toDigitChar(minutes / 10)); - } - sb.append(toDigitChar(minutes % 10)); - sb.append(TIME_SEPARATOR); - if (seconds < 10) { - sb.append(TIME_PADDING); - } else { - sb.append(toDigitChar(seconds / 10)); - } - sb.append(toDigitChar(seconds % 10)); - return sb.toString(); - } else { - return String.format(format, minutes, seconds); - } - } - - private static char toDigitChar(long digit) { - return (char) (digit + '0'); - } - - /** - * Format a date / time such that if the then is on the same day as now, it shows - * just the time and if it's a different day, it shows just the date. - * - * <p>The parameters dateFormat and timeFormat should each be one of - * {@link java.text.DateFormat#DEFAULT}, - * {@link java.text.DateFormat#FULL}, - * {@link java.text.DateFormat#LONG}, - * {@link java.text.DateFormat#MEDIUM} - * or - * {@link java.text.DateFormat#SHORT} - * - * @param then the date to format - * @param now the base time - * @param dateStyle how to format the date portion. - * @param timeStyle how to format the time portion. - */ - public static final CharSequence formatSameDayTime(long then, long now, - int dateStyle, int timeStyle) { - Calendar thenCal = new GregorianCalendar(); - thenCal.setTimeInMillis(then); - Date thenDate = thenCal.getTime(); - Calendar nowCal = new GregorianCalendar(); - nowCal.setTimeInMillis(now); - - java.text.DateFormat f; - - if (thenCal.get(Calendar.YEAR) == nowCal.get(Calendar.YEAR) - && thenCal.get(Calendar.MONTH) == nowCal.get(Calendar.MONTH) - && thenCal.get(Calendar.DAY_OF_MONTH) == nowCal.get(Calendar.DAY_OF_MONTH)) { - f = java.text.DateFormat.getTimeInstance(timeStyle); - } else { - f = java.text.DateFormat.getDateInstance(dateStyle); - } - return f.format(thenDate); - } - - /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static Calendar newCalendar(boolean zulu) - { - if (zulu) - return Calendar.getInstance(TimeZone.getTimeZone("GMT")); - - return Calendar.getInstance(); - } - - /** - * @return true if the supplied when is today else false - */ - public static boolean isToday(long when) { - Time time = new Time(); - time.set(when); - - int thenYear = time.year; - int thenMonth = time.month; - int thenMonthDay = time.monthDay; - - time.set(System.currentTimeMillis()); - return (thenYear == time.year) - && (thenMonth == time.month) - && (thenMonthDay == time.monthDay); - } - - /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - private static final int ctoi(String str, int index) - throws DateException - { - char c = str.charAt(index); - if (c >= '0' && c <= '9') { - return (int)(c - '0'); - } - throw new DateException("Expected numeric character. Got '" + - c + "'"); - } - - /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - private static final int check(int lowerBound, int upperBound, int value) - throws DateException - { - if (value >= lowerBound && value <= upperBound) { - return value; - } - throw new DateException("field out of bounds. max=" + upperBound - + " value=" + value); - } - - /** - * @hide - * @deprecated use {@link android.text.format.Time} - * Return true if this date string is local time - */ - public static boolean isUTC(String s) - { - if (s.length() == 16 && s.charAt(15) == 'Z') { - return true; - } - if (s.length() == 9 && s.charAt(8) == 'Z') { - // XXX not sure if this case possible/valid - return true; - } - return false; - } - - - // note that month in Calendar is 0 based and in all other human - // representations, it's 1 based. - // Returns if the Z was present, meaning that the time is in UTC - /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static boolean parseDateTime(String str, Calendar cal) - throws DateException - { - int len = str.length(); - boolean dateTime = (len == 15 || len == 16) && str.charAt(8) == 'T'; - boolean justDate = len == 8; - if (dateTime || justDate) { - cal.clear(); - cal.set(Calendar.YEAR, - ctoi(str, 0)*1000 + ctoi(str, 1)*100 - + ctoi(str, 2)*10 + ctoi(str, 3)); - cal.set(Calendar.MONTH, - check(0, 11, ctoi(str, 4)*10 + ctoi(str, 5) - 1)); - cal.set(Calendar.DAY_OF_MONTH, - check(1, 31, ctoi(str, 6)*10 + ctoi(str, 7))); - if (dateTime) { - cal.set(Calendar.HOUR_OF_DAY, - check(0, 23, ctoi(str, 9)*10 + ctoi(str, 10))); - cal.set(Calendar.MINUTE, - check(0, 59, ctoi(str, 11)*10 + ctoi(str, 12))); - cal.set(Calendar.SECOND, - check(0, 59, ctoi(str, 13)*10 + ctoi(str, 14))); - } - if (justDate) { - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - return true; - } - if (len == 15) { - return false; - } - if (str.charAt(15) == 'Z') { - return true; - } - } - throw new DateException("Invalid time (expected " - + "YYYYMMDDThhmmssZ? got '" + str + "')."); - } - - /** - * Given a timezone string which can be null, and a dateTime string, - * set that time into a calendar. - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static void parseDateTime(String tz, String dateTime, Calendar out) - throws DateException - { - TimeZone timezone; - if (DateUtils.isUTC(dateTime)) { - timezone = TimeZone.getTimeZone("UTC"); - } - else if (tz == null) { - timezone = TimeZone.getDefault(); - } - else { - timezone = TimeZone.getTimeZone(tz); - } - - Calendar local = new GregorianCalendar(timezone); - DateUtils.parseDateTime(dateTime, local); - - out.setTimeInMillis(local.getTimeInMillis()); - } - - - /** - * Return a string containing the date and time in RFC2445 format. - * Ensures that the time is written in UTC. The Calendar class doesn't - * really help out with this, so this is slower than it ought to be. - * - * @param cal the date and time to write - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static String writeDateTime(Calendar cal) - { - TimeZone tz = TimeZone.getTimeZone("GMT"); - GregorianCalendar c = new GregorianCalendar(tz); - c.setTimeInMillis(cal.getTimeInMillis()); - return writeDateTime(c, true); - } - - /** - * Return a string containing the date and time in RFC2445 format. - * - * @param cal the date and time to write - * @param zulu If the calendar is in UTC, pass true, and a Z will - * be written at the end as per RFC2445. Otherwise, the time is - * considered in localtime. - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static String writeDateTime(Calendar cal, boolean zulu) - { - StringBuilder sb = new StringBuilder(); - sb.ensureCapacity(16); - if (zulu) { - sb.setLength(16); - sb.setCharAt(15, 'Z'); - } else { - sb.setLength(15); - } - return writeDateTime(cal, sb); - } - - /** - * Return a string containing the date and time in RFC2445 format. - * - * @param cal the date and time to write - * @param sb a StringBuilder to use. It is assumed that setLength - * has already been called on sb to the appropriate length - * which is sb.setLength(zulu ? 16 : 15) - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static String writeDateTime(Calendar cal, StringBuilder sb) - { - int n; - - n = cal.get(Calendar.YEAR); - sb.setCharAt(3, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(2, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(1, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(0, (char)('0'+n%10)); - - n = cal.get(Calendar.MONTH) + 1; - sb.setCharAt(5, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(4, (char)('0'+n%10)); - - n = cal.get(Calendar.DAY_OF_MONTH); - sb.setCharAt(7, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(6, (char)('0'+n%10)); - - sb.setCharAt(8, 'T'); - - n = cal.get(Calendar.HOUR_OF_DAY); - sb.setCharAt(10, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(9, (char)('0'+n%10)); - - n = cal.get(Calendar.MINUTE); - sb.setCharAt(12, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(11, (char)('0'+n%10)); - - n = cal.get(Calendar.SECOND); - sb.setCharAt(14, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(13, (char)('0'+n%10)); - - return sb.toString(); - } - - /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static void assign(Calendar lval, Calendar rval) - { - // there should be a faster way. - lval.clear(); - lval.setTimeInMillis(rval.getTimeInMillis()); - } - - /** - * Formats a date or a time range according to the local conventions. - * - * <p> - * Example output strings (date formats in these examples are shown using - * the US date format convention but that may change depending on the - * local settings): - * <ul> - * <li>10:15am</li> - * <li>3:00pm - 4:00pm</li> - * <li>3pm - 4pm</li> - * <li>3PM - 4PM</li> - * <li>08:00 - 17:00</li> - * <li>Oct 9</li> - * <li>Tue, Oct 9</li> - * <li>October 9, 2007</li> - * <li>Oct 9 - 10</li> - * <li>Oct 9 - 10, 2007</li> - * <li>Oct 28 - Nov 3, 2007</li> - * <li>Dec 31, 2007 - Jan 1, 2008</li> - * <li>Oct 9, 8:00am - Oct 10, 5:00pm</li> - * <li>12/31/2007 - 01/01/2008</li> - * </ul> - * - * <p> - * The flags argument is a bitmask of options from the following list: - * - * <ul> - * <li>FORMAT_SHOW_TIME</li> - * <li>FORMAT_SHOW_WEEKDAY</li> - * <li>FORMAT_SHOW_YEAR</li> - * <li>FORMAT_NO_YEAR</li> - * <li>FORMAT_SHOW_DATE</li> - * <li>FORMAT_NO_MONTH_DAY</li> - * <li>FORMAT_12HOUR</li> - * <li>FORMAT_24HOUR</li> - * <li>FORMAT_CAP_AMPM</li> - * <li>FORMAT_NO_NOON</li> - * <li>FORMAT_CAP_NOON</li> - * <li>FORMAT_NO_MIDNIGHT</li> - * <li>FORMAT_CAP_MIDNIGHT</li> - * <li>FORMAT_UTC</li> - * <li>FORMAT_ABBREV_TIME</li> - * <li>FORMAT_ABBREV_WEEKDAY</li> - * <li>FORMAT_ABBREV_MONTH</li> - * <li>FORMAT_ABBREV_ALL</li> - * <li>FORMAT_NUMERIC_DATE</li> - * </ul> - * - * <p> - * If FORMAT_SHOW_TIME is set, the time is shown as part of the date range. - * If the start and end time are the same, then just the start time is - * shown. - * - * <p> - * If FORMAT_SHOW_WEEKDAY is set, then the weekday is shown. - * - * <p> - * If FORMAT_SHOW_YEAR is set, then the year is always shown. - * If FORMAT_NO_YEAR is set, then the year is not shown. - * If neither FORMAT_SHOW_YEAR nor FORMAT_NO_YEAR are set, then the year - * is shown only if it is different from the current year, or if the start - * and end dates fall on different years. - * - * <p> - * Normally the date is shown unless the start and end day are the same. - * If FORMAT_SHOW_DATE is set, then the date is always shown, even for - * same day ranges. - * - * <p> - * If FORMAT_NO_MONTH_DAY is set, then if the date is shown, just the - * month name will be shown, not the day of the month. For example, - * "January, 2008" instead of "January 6 - 12, 2008". - * - * <p> - * If FORMAT_CAP_AMPM is set and 12-hour time is used, then the "AM" - * and "PM" are capitalized. - * - * <p> - * If FORMAT_NO_NOON is set and 12-hour time is used, then "12pm" is - * shown instead of "noon". - * - * <p> - * If FORMAT_CAP_NOON is set and 12-hour time is used, then "Noon" is - * shown instead of "noon". - * - * <p> - * If FORMAT_NO_MIDNIGHT is set and 12-hour time is used, then "12am" is - * shown instead of "midnight". - * - * <p> - * If FORMAT_CAP_NOON is set and 12-hour time is used, then "Midnight" is - * shown instead of "midnight". - * - * <p> - * If FORMAT_12HOUR is set and the time is shown, then the time is - * shown in the 12-hour time format. You should not normally set this. - * Instead, let the time format be chosen automatically according to the - * system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then - * FORMAT_24HOUR takes precedence. - * - * <p> - * If FORMAT_24HOUR is set and the time is shown, then the time is - * shown in the 24-hour time format. You should not normally set this. - * Instead, let the time format be chosen automatically according to the - * system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then - * FORMAT_24HOUR takes precedence. - * - * <p> - * If FORMAT_UTC is set, then the UTC timezone is used for the start - * and end milliseconds. - * - * <p> - * If FORMAT_ABBREV_TIME is set and 12-hour time format is used, then the - * start and end times (if shown) are abbreviated by not showing the minutes - * if they are zero. For example, instead of "3:00pm" the time would be - * abbreviated to "3pm". - * - * <p> - * If FORMAT_ABBREV_WEEKDAY is set, then the weekday (if shown) is - * abbreviated to a 3-letter string. - * - * <p> - * If FORMAT_ABBREV_MONTH is set, then the month (if shown) is abbreviated - * to a 3-letter string. - * - * <p> - * If FORMAT_ABBREV_ALL is set, then the weekday and the month (if shown) - * are abbreviated to 3-letter strings. - * - * <p> - * If FORMAT_NUMERIC_DATE is set, then the date is shown in numeric format - * instead of using the name of the month. For example, "12/31/2008" - * instead of "December 31, 2008". - * - * @param context the context is required only if the time is shown - * @param startMillis the start time in UTC milliseconds - * @param endMillis the end time in UTC milliseconds - * @param flags a bit mask of options - * - * @return a string containing the formatted date/time range. - */ - public static String formatDateRange(Context context, long startMillis, - long endMillis, int flags) { - Resources res = Resources.getSystem(); - boolean showTime = (flags & FORMAT_SHOW_TIME) != 0; - boolean showWeekDay = (flags & FORMAT_SHOW_WEEKDAY) != 0; - boolean showYear = (flags & FORMAT_SHOW_YEAR) != 0; - boolean noYear = (flags & FORMAT_NO_YEAR) != 0; - boolean useUTC = (flags & FORMAT_UTC) != 0; - boolean abbrevWeekDay = (flags & (FORMAT_ABBREV_WEEKDAY | FORMAT_ABBREV_ALL)) != 0; - boolean abbrevMonth = (flags & (FORMAT_ABBREV_MONTH | FORMAT_ABBREV_ALL)) != 0; - boolean noMonthDay = (flags & FORMAT_NO_MONTH_DAY) != 0; - boolean numericDate = (flags & FORMAT_NUMERIC_DATE) != 0; - - Time startDate; - Time endDate; - - if (useUTC) { - startDate = new Time(Time.TIMEZONE_UTC); - endDate = new Time(Time.TIMEZONE_UTC); - } else { - startDate = new Time(); - endDate = new Time(); - } - - startDate.set(startMillis); - endDate.set(endMillis); - int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff); - int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff); - int dayDistance = endJulianDay - startJulianDay; - - // If the end date ends at 12am at the beginning of a day, - // then modify it to make it look like it ends at midnight on - // the previous day. This will allow us to display "8pm - midnight", - // for example, instead of "Nov 10, 8pm - Nov 11, 12am". But we only do - // this if it is midnight of the same day as the start date because - // for multiple-day events, an end time of "midnight on Nov 11" is - // ambiguous and confusing (is that midnight the start of Nov 11, or - // the end of Nov 11?). - // If we are not showing the time then also adjust the end date - // for multiple-day events. This is to allow us to display, for - // example, "Nov 10 -11" for an event with a start date of Nov 10 - // and an end date of Nov 12 at 00:00. - // If the start and end time are the same, then skip this and don't - // adjust the date. - if ((endDate.hour | endDate.minute | endDate.second) == 0 - && (!showTime || dayDistance <= 1) && (startMillis != endMillis)) { - endDate.monthDay -= 1; - endDate.normalize(true /* ignore isDst */); - } - - int startDay = startDate.monthDay; - int startMonthNum = startDate.month; - int startYear = startDate.year; - - int endDay = endDate.monthDay; - int endMonthNum = endDate.month; - int endYear = endDate.year; - - String startWeekDayString = ""; - String endWeekDayString = ""; - if (showWeekDay) { - String weekDayFormat = ""; - if (abbrevWeekDay) { - weekDayFormat = ABBREV_WEEKDAY_FORMAT; - } else { - weekDayFormat = WEEKDAY_FORMAT; - } - startWeekDayString = startDate.format(weekDayFormat); - endWeekDayString = endDate.format(weekDayFormat); - } - - String startTimeString = ""; - String endTimeString = ""; - if (showTime) { - String startTimeFormat = ""; - String endTimeFormat = ""; - boolean force24Hour = (flags & FORMAT_24HOUR) != 0; - boolean force12Hour = (flags & FORMAT_12HOUR) != 0; - boolean use24Hour; - if (force24Hour) { - use24Hour = true; - } else if (force12Hour) { - use24Hour = false; - } else { - use24Hour = DateFormat.is24HourFormat(context); - } - if (use24Hour) { - startTimeFormat = HOUR_MINUTE_24; - endTimeFormat = HOUR_MINUTE_24; - } else { - boolean abbrevTime = (flags & (FORMAT_ABBREV_TIME | FORMAT_ABBREV_ALL)) != 0; - boolean capAMPM = (flags & FORMAT_CAP_AMPM) != 0; - boolean noNoon = (flags & FORMAT_NO_NOON) != 0; - boolean capNoon = (flags & FORMAT_CAP_NOON) != 0; - boolean noMidnight = (flags & FORMAT_NO_MIDNIGHT) != 0; - boolean capMidnight = (flags & FORMAT_CAP_MIDNIGHT) != 0; - - boolean startOnTheHour = startDate.minute == 0 && startDate.second == 0; - boolean endOnTheHour = endDate.minute == 0 && endDate.second == 0; - if (abbrevTime && startOnTheHour) { - if (capAMPM) { - startTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); - } else { - startTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); - } - } else { - if (capAMPM) { - startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); - } else { - startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); - } - } - if (abbrevTime && endOnTheHour) { - if (capAMPM) { - endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); - } - } else { - if (capAMPM) { - endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); - } - } - - if (startDate.hour == 12 && startOnTheHour && !noNoon) { - if (capNoon) { - startTimeFormat = res.getString(com.android.internal.R.string.Noon); - } else { - startTimeFormat = res.getString(com.android.internal.R.string.noon); - } - // Don't show the start time starting at midnight. Show - // 12am instead. - } - - if (endDate.hour == 12 && endOnTheHour && !noNoon) { - if (capNoon) { - endTimeFormat = res.getString(com.android.internal.R.string.Noon); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.noon); - } - } else if (endDate.hour == 0 && endOnTheHour && !noMidnight) { - if (capMidnight) { - endTimeFormat = res.getString(com.android.internal.R.string.Midnight); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.midnight); - } - } - } - startTimeString = startDate.format(startTimeFormat); - endTimeString = endDate.format(endTimeFormat); - } - - // Get the current year - long millis = System.currentTimeMillis(); - Time time = new Time(); - time.set(millis); - int currentYear = time.year; - - // Show the year if the user specified FORMAT_SHOW_YEAR or if - // the starting and end years are different from each other - // or from the current year. But don't show the year if the - // user specified FORMAT_NO_YEAR; - showYear = showYear || (!noYear && (startYear != endYear || startYear != currentYear)); - - String defaultDateFormat, fullFormat, dateRange; - if (numericDate) { - defaultDateFormat = res.getString(com.android.internal.R.string.numeric_date); - } else if (showYear) { - if (abbrevMonth) { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month_year); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month_day_year); - } - } else { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.month_year); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.month_day_year); - } - } - } else { - if (abbrevMonth) { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.abbrev_month_day); - } - } else { - if (noMonthDay) { - defaultDateFormat = res.getString(com.android.internal.R.string.month); - } else { - defaultDateFormat = res.getString(com.android.internal.R.string.month_day); - } - } - } - - if (showWeekDay) { - if (showTime) { - fullFormat = res.getString(com.android.internal.R.string.wday1_date1_time1_wday2_date2_time2); - } else { - fullFormat = res.getString(com.android.internal.R.string.wday1_date1_wday2_date2); - } - } else { - if (showTime) { - fullFormat = res.getString(com.android.internal.R.string.date1_time1_date2_time2); - } else { - fullFormat = res.getString(com.android.internal.R.string.date1_date2); - } - } - - if (noMonthDay && startMonthNum == endMonthNum) { - // Example: "January, 2008" - String startDateString = startDate.format(defaultDateFormat); - return startDateString; - } - - if (startYear != endYear || noMonthDay) { - // Different year or we are not showing the month day number. - // Example: "December 31, 2007 - January 1, 2008" - // Or: "January - February, 2008" - String startDateString = startDate.format(defaultDateFormat); - String endDateString = endDate.format(defaultDateFormat); - - // The values that are used in a fullFormat string are specified - // by position. - dateRange = String.format(fullFormat, - startWeekDayString, startDateString, startTimeString, - endWeekDayString, endDateString, endTimeString); - return dateRange; - } - - // Get the month, day, and year strings for the start and end dates - String monthFormat; - if (numericDate) { - monthFormat = NUMERIC_MONTH_FORMAT; - } else if (abbrevMonth) { - monthFormat = ABBREV_MONTH_FORMAT; - } else { - monthFormat = MONTH_FORMAT; - } - String startMonthString = startDate.format(monthFormat); - String startMonthDayString = startDate.format(MONTH_DAY_FORMAT); - String startYearString = startDate.format(YEAR_FORMAT); - String endMonthString = endDate.format(monthFormat); - String endMonthDayString = endDate.format(MONTH_DAY_FORMAT); - String endYearString = endDate.format(YEAR_FORMAT); - - if (startMonthNum != endMonthNum) { - // Same year, different month. - // Example: "October 28 - November 3" - // or: "Wed, Oct 31 - Sat, Nov 3, 2007" - // or: "Oct 31, 8am - Sat, Nov 3, 2007, 5pm" - - int index = 0; - if (showWeekDay) index = 1; - if (showYear) index += 2; - if (showTime) index += 4; - if (numericDate) index += 8; - int resId = sameYearTable[index]; - fullFormat = res.getString(resId); - - // The values that are used in a fullFormat string are specified - // by position. - dateRange = String.format(fullFormat, - startWeekDayString, startMonthString, startMonthDayString, - startYearString, startTimeString, - endWeekDayString, endMonthString, endMonthDayString, - endYearString, endTimeString); - return dateRange; - } - - if (startDay != endDay) { - // Same month, different day. - int index = 0; - if (showWeekDay) index = 1; - if (showYear) index += 2; - if (showTime) index += 4; - if (numericDate) index += 8; - int resId = sameMonthTable[index]; - fullFormat = res.getString(resId); - - // The values that are used in a fullFormat string are specified - // by position. - dateRange = String.format(fullFormat, - startWeekDayString, startMonthString, startMonthDayString, - startYearString, startTimeString, - endWeekDayString, endMonthString, endMonthDayString, - endYearString, endTimeString); - return dateRange; - } - - // Same start and end day - boolean showDate = (flags & FORMAT_SHOW_DATE) != 0; - - // If nothing was specified, then show the date. - if (!showTime && !showDate && !showWeekDay) showDate = true; - - // Compute the time string (example: "10:00 - 11:00 am") - String timeString = ""; - if (showTime) { - // If the start and end time are the same, then just show the - // start time. - if (startMillis == endMillis) { - // Same start and end time. - // Example: "10:15 AM" - timeString = startTimeString; - } else { - // Example: "10:00 - 11:00 am" - String timeFormat = res.getString(com.android.internal.R.string.time1_time2); - timeString = String.format(timeFormat, startTimeString, endTimeString); - } - } - - // Figure out which full format to use. - fullFormat = ""; - String dateString = ""; - if (showDate) { - dateString = startDate.format(defaultDateFormat); - if (showWeekDay) { - if (showTime) { - // Example: "10:00 - 11:00 am, Tue, Oct 9" - fullFormat = res.getString(com.android.internal.R.string.time_wday_date); - } else { - // Example: "Tue, Oct 9" - fullFormat = res.getString(com.android.internal.R.string.wday_date); - } - } else { - if (showTime) { - // Example: "10:00 - 11:00 am, Oct 9" - fullFormat = res.getString(com.android.internal.R.string.time_date); - } else { - // Example: "Oct 9" - return dateString; - } - } - } else if (showWeekDay) { - if (showTime) { - // Example: "10:00 - 11:00 am, Tue" - fullFormat = res.getString(com.android.internal.R.string.time_wday); - } else { - // Example: "Tue" - return startWeekDayString; - } - } else if (showTime) { - return timeString; - } - - // The values that are used in a fullFormat string are specified - // by position. - dateRange = String.format(fullFormat, timeString, startWeekDayString, dateString); - return dateRange; - } - - /** - * Formats a date or a time according to the local conventions. There are - * lots of options that allow the caller to control, for example, if the - * time is shown, if the day of the week is shown, if the month name is - * abbreviated, if noon is shown instead of 12pm, and so on. For the - * complete list of options, see the documentation for - * {@link #formatDateRange}. - * <p> - * Example output strings (date formats in these examples are shown using - * the US date format convention but that may change depending on the - * local settings): - * <ul> - * <li>10:15am</li> - * <li>3:00pm</li> - * <li>3pm</li> - * <li>3PM</li> - * <li>08:00</li> - * <li>17:00</li> - * <li>noon</li> - * <li>Noon</li> - * <li>midnight</li> - * <li>Midnight</li> - * <li>Oct 31</li> - * <li>Oct 31, 2007</li> - * <li>October 31, 2007</li> - * <li>10am, Oct 31</li> - * <li>17:00, Oct 31</li> - * <li>Wed</li> - * <li>Wednesday</li> - * <li>10am, Wed, Oct 31</li> - * <li>Wed, Oct 31</li> - * <li>Wednesday, Oct 31</li> - * <li>Wed, Oct 31, 2007</li> - * <li>Wed, October 31</li> - * <li>10/31/2007</li> - * </ul> - * - * @param context the context is required only if the time is shown - * @param millis a point in time in UTC milliseconds - * @param flags a bit mask of formatting options - * @return a string containing the formatted date/time. - */ - public static String formatDateTime(Context context, long millis, int flags) { - return formatDateRange(context, millis, millis, flags); - } - - /** - * @return a relative time string to display the time expressed by millis. Times - * are counted starting at midnight, which means that assuming that the current - * time is March 31st, 0:30: - * <ul> - * <li>"millis=0:10 today" will be displayed as "0:10"</li> - * <li>"millis=11:30pm the day before" will be displayed as "Mar 30"</li> - * </ul> - * If the given millis is in a different year, then the full date is - * returned in numeric format (e.g., "10/12/2008"). - * - * @param withPreposition If true, the string returned will include the correct - * preposition ("at 9:20am", "on 10/12/2008" or "on May 29"). - */ - public static CharSequence getRelativeTimeSpanString(Context c, long millis, - boolean withPreposition) { - - long now = System.currentTimeMillis(); - long span = now - millis; - - if (sNowTime == null) { - sNowTime = new Time(); - sThenTime = new Time(); - } - - sNowTime.set(now); - sThenTime.set(millis); - - String result; - int prepositionId; - if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) { - // Same day - int flags = FORMAT_SHOW_TIME; - result = formatDateRange(c, millis, millis, flags); - prepositionId = R.string.preposition_for_time; - } else if (sNowTime.year != sThenTime.year) { - // Different years - int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE; - result = formatDateRange(c, millis, millis, flags); - - // This is a date (like "10/31/2008" so use the date preposition) - prepositionId = R.string.preposition_for_date; - } else { - // Default - int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH; - result = formatDateRange(c, millis, millis, flags); - prepositionId = R.string.preposition_for_date; - } - if (withPreposition) { - Resources res = c.getResources(); - result = res.getString(prepositionId, result); - } - return result; - } - - /** - * Convenience function to return relative time string without preposition. - * @param c context for resources - * @param millis time in milliseconds - * @return {@link CharSequence} containing relative time. - * @see #getRelativeTimeSpanString(Context, long, boolean) - */ - public static CharSequence getRelativeTimeSpanString(Context c, long millis) { - return getRelativeTimeSpanString(c, millis, false /* no preposition */); - } - - private static Time sNowTime; - private static Time sThenTime; -} diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java deleted file mode 100644 index 1b30aa0..0000000 --- a/core/java/android/text/format/Formatter.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.format; - -import android.content.Context; - -/** - * Utility class to aid in formatting common values that are not covered - * by the standard java.util.Formatter. - */ -public final class Formatter { - - /** - * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc - * - * @param context Context to use to load the localized units - * @param number size value to be formated - * @return formated string with the number - */ - public static String formatFileSize(Context context, long number) { - if (context == null) { - return ""; - } - - float result = number; - int suffix = com.android.internal.R.string.byteShort; - if (result > 900) { - suffix = com.android.internal.R.string.kilobyteShort; - result = result / 1024; - } - if (result > 900) { - suffix = com.android.internal.R.string.megabyteShort; - result = result / 1024; - } - if (result > 900) { - suffix = com.android.internal.R.string.gigabyteShort; - result = result / 1024; - } - if (result > 900) { - suffix = com.android.internal.R.string.terabyteShort; - result = result / 1024; - } - if (result > 900) { - suffix = com.android.internal.R.string.petabyteShort; - result = result / 1024; - } - if (result < 100) { - return String.format("%.2f%s", result, context.getText(suffix).toString()); - } - return String.format("%.0f%s", result, context.getText(suffix).toString()); - } - - /** - * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing - * the IP address. The IP address is expected to be in little-endian format (LSB first). That - * is, 0x01020304 will return "4.3.2.1". - * - * @param addr the IP address as a packed integer with LSB first. - * @return string with canonical IP address format. - */ - public static String formatIpAddress(int addr) { - StringBuffer buf = new StringBuffer(); - buf.append(addr & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff); - return buf.toString(); - } -} diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java deleted file mode 100644 index daa99c2..0000000 --- a/core/java/android/text/format/Time.java +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.format; - -import android.content.res.Resources; - -import java.util.Locale; -import java.util.TimeZone; - -/** - * The Time class is a faster replacement for the java.util.Calendar and - * java.util.GregorianCalendar classes. An instance of the Time class represents - * a moment in time, specified with second precision. It is modelled after - * struct tm, and in fact, uses struct tm to implement most of the - * functionality. - */ -public class Time { - private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000"; - private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z"; - private static final String Y_M_D = "%Y-%m-%d"; - - public static final String TIMEZONE_UTC = "UTC"; - - /** - * The Julian day of the epoch, that is, January 1, 1970 on the Gregorian - * calendar. - */ - public static final int EPOCH_JULIAN_DAY = 2440588; - - /** - * True if this is an allDay event. The hour, minute, second fields are - * all zero, and the date is displayed the same in all time zones. - */ - public boolean allDay; - - /** - * Seconds [0-61] (2 leap seconds allowed) - */ - public int second; - - /** - * Minute [0-59] - */ - public int minute; - - /** - * Hour of day [0-23] - */ - public int hour; - - /** - * Day of month [1-31] - */ - public int monthDay; - - /** - * Month [0-11] - */ - public int month; - - /** - * Year. TBD. Is this years since 1900 like in struct tm? - */ - public int year; - - /** - * Day of week [0-6] - */ - public int weekDay; - - /** - * Day of year [0-365] - */ - public int yearDay; - - /** - * This time is in daylight savings time. One of: - * <ul> - * <li><b>positive</b> - in dst</li> - * <li><b>0</b> - not in dst</li> - * <li><b>negative</b> - unknown</li> - * </ul> - */ - public int isDst; - - /** - * Offset from UTC (in seconds). - */ - public long gmtoff; - - /** - * The timezone for this Time. Should not be null. - */ - public String timezone; - - /* - * Define symbolic constants for accessing the fields in this class. Used in - * getActualMaximum(). - */ - public static final int SECOND = 1; - public static final int MINUTE = 2; - public static final int HOUR = 3; - public static final int MONTH_DAY = 4; - public static final int MONTH = 5; - public static final int YEAR = 6; - public static final int WEEK_DAY = 7; - public static final int YEAR_DAY = 8; - public static final int WEEK_NUM = 9; - - public static final int SUNDAY = 0; - public static final int MONDAY = 1; - public static final int TUESDAY = 2; - public static final int WEDNESDAY = 3; - public static final int THURSDAY = 4; - public static final int FRIDAY = 5; - public static final int SATURDAY = 6; - - /* - * The Locale for which date formatting strings have been loaded. - */ - private static Locale sLocale; - private static String[] sShortMonths; - private static String[] sLongMonths; - private static String[] sShortWeekdays; - private static String[] sLongWeekdays; - private static String sTimeOnlyFormat; - private static String sDateOnlyFormat; - private static String sDateTimeFormat; - private static String sAm; - private static String sPm; - private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y"; - - /** - * Construct a Time object in the timezone named by the string - * argument "timezone". The time is initialized to Jan 1, 1970. - * @param timezone string containing the timezone to use. - * @see TimeZone - */ - public Time(String timezone) { - if (timezone == null) { - throw new NullPointerException("timezone is null!"); - } - this.timezone = timezone; - this.year = 1970; - this.monthDay = 1; - // Set the daylight-saving indicator to the unknown value -1 so that - // it will be recomputed. - this.isDst = -1; - } - - /** - * Construct a Time object in the default timezone. The time is initialized to - * Jan 1, 1970. - */ - public Time() { - this(TimeZone.getDefault().getID()); - } - - /** - * A copy constructor. Construct a Time object by copying the given - * Time object. No normalization occurs. - * - * @param other - */ - public Time(Time other) { - set(other); - } - - /** - * Ensures the values in each field are in range. For example if the - * current value of this calendar is March 32, normalize() will convert it - * to April 1. It also fills in weekDay, yearDay, isDst and gmtoff. - * - * <p> - * If "ignoreDst" is true, then this method sets the "isDst" field to -1 - * (the "unknown" value) before normalizing. It then computes the - * correct value for "isDst". - * - * <p> - * See {@link #toMillis(boolean)} for more information about when to - * use <tt>true</tt> or <tt>false</tt> for "ignoreDst". - * - * @return the UTC milliseconds since the epoch - */ - native public long normalize(boolean ignoreDst); - - /** - * Convert this time object so the time represented remains the same, but is - * instead located in a different timezone. This method automatically calls - * normalize() in some cases - */ - native public void switchTimezone(String timezone); - - private static final int[] DAYS_PER_MONTH = { 31, 28, 31, 30, 31, 30, 31, - 31, 30, 31, 30, 31 }; - - /** - * Return the maximum possible value for the given field given the value of - * the other fields. Requires that it be normalized for MONTH_DAY and - * YEAR_DAY. - * @param field one of the constants for HOUR, MINUTE, SECOND, etc. - * @return the maximum value for the field. - */ - public int getActualMaximum(int field) { - switch (field) { - case SECOND: - return 59; // leap seconds, bah humbug - case MINUTE: - return 59; - case HOUR: - return 23; - case MONTH_DAY: { - int n = DAYS_PER_MONTH[this.month]; - if (n != 28) { - return n; - } else { - int y = this.year; - return ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) ? 29 : 28; - } - } - case MONTH: - return 11; - case YEAR: - return 2037; - case WEEK_DAY: - return 6; - case YEAR_DAY: { - int y = this.year; - // Year days are numbered from 0, so the last one is usually 364. - return ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) ? 365 : 364; - } - case WEEK_NUM: - throw new RuntimeException("WEEK_NUM not implemented"); - default: - throw new RuntimeException("bad field=" + field); - } - } - - /** - * Clears all values, setting the timezone to the given timezone. Sets isDst - * to a negative value to mean "unknown". - * @param timezone the timezone to use. - */ - public void clear(String timezone) { - if (timezone == null) { - throw new NullPointerException("timezone is null!"); - } - this.timezone = timezone; - this.allDay = false; - this.second = 0; - this.minute = 0; - this.hour = 0; - this.monthDay = 0; - this.month = 0; - this.year = 0; - this.weekDay = 0; - this.yearDay = 0; - this.gmtoff = 0; - this.isDst = -1; - } - - /** - * return a negative number if a is less than b, a positive number if a is - * greater than b, and 0 if they are equal. - */ - native public static int compare(Time a, Time b); - - /** - * Print the current value given the format string provided. See man - * strftime for what means what. The final string must be less than 256 - * characters. - * @param format a string containing the desired format. - * @return a String containing the current time expressed in the current locale. - */ - public String format(String format) { - synchronized (Time.class) { - Locale locale = Locale.getDefault(); - - if (sLocale == null || locale == null || !(locale.equals(sLocale))) { - Resources r = Resources.getSystem(); - - sShortMonths = new String[] { - r.getString(com.android.internal.R.string.month_medium_january), - r.getString(com.android.internal.R.string.month_medium_february), - r.getString(com.android.internal.R.string.month_medium_march), - r.getString(com.android.internal.R.string.month_medium_april), - r.getString(com.android.internal.R.string.month_medium_may), - r.getString(com.android.internal.R.string.month_medium_june), - r.getString(com.android.internal.R.string.month_medium_july), - r.getString(com.android.internal.R.string.month_medium_august), - r.getString(com.android.internal.R.string.month_medium_september), - r.getString(com.android.internal.R.string.month_medium_october), - r.getString(com.android.internal.R.string.month_medium_november), - r.getString(com.android.internal.R.string.month_medium_december), - }; - sLongMonths = new String[] { - r.getString(com.android.internal.R.string.month_long_january), - r.getString(com.android.internal.R.string.month_long_february), - r.getString(com.android.internal.R.string.month_long_march), - r.getString(com.android.internal.R.string.month_long_april), - r.getString(com.android.internal.R.string.month_long_may), - r.getString(com.android.internal.R.string.month_long_june), - r.getString(com.android.internal.R.string.month_long_july), - r.getString(com.android.internal.R.string.month_long_august), - r.getString(com.android.internal.R.string.month_long_september), - r.getString(com.android.internal.R.string.month_long_october), - r.getString(com.android.internal.R.string.month_long_november), - r.getString(com.android.internal.R.string.month_long_december), - }; - sShortWeekdays = new String[] { - r.getString(com.android.internal.R.string.day_of_week_medium_sunday), - r.getString(com.android.internal.R.string.day_of_week_medium_monday), - r.getString(com.android.internal.R.string.day_of_week_medium_tuesday), - r.getString(com.android.internal.R.string.day_of_week_medium_wednesday), - r.getString(com.android.internal.R.string.day_of_week_medium_thursday), - r.getString(com.android.internal.R.string.day_of_week_medium_friday), - r.getString(com.android.internal.R.string.day_of_week_medium_saturday), - }; - sLongWeekdays = new String[] { - r.getString(com.android.internal.R.string.day_of_week_long_sunday), - r.getString(com.android.internal.R.string.day_of_week_long_monday), - r.getString(com.android.internal.R.string.day_of_week_long_tuesday), - r.getString(com.android.internal.R.string.day_of_week_long_wednesday), - r.getString(com.android.internal.R.string.day_of_week_long_thursday), - r.getString(com.android.internal.R.string.day_of_week_long_friday), - r.getString(com.android.internal.R.string.day_of_week_long_saturday), - }; - sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day); - sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year); - sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time); - sAm = r.getString(com.android.internal.R.string.am); - sPm = r.getString(com.android.internal.R.string.pm); - - sLocale = locale; - } - - return format1(format); - } - } - - native private String format1(String format); - - /** - * Return the current time in YYYYMMDDTHHMMSS<tz> format - */ - @Override - native public String toString(); - - /** - * Parses a date-time string in either the RFC 2445 format or an abbreviated - * format that does not include the "time" field. For example, all of the - * following strings are valid: - * - * <ul> - * <li>"20081013T160000Z"</li> - * <li>"20081013T160000"</li> - * <li>"20081013"</li> - * </ul> - * - * Returns whether or not the time is in UTC (ends with Z). If the string - * ends with "Z" then the timezone is set to UTC. If the date-time string - * included only a date and no time field, then the <code>allDay</code> - * field of this Time class is set to true and the <code>hour</code>, - * <code>minute</code>, and <code>second</code> fields are set to zero; - * otherwise (a time field was included in the date-time string) - * <code>allDay</code> is set to false. The fields <code>weekDay</code>, - * <code>yearDay</code>, and <code>gmtoff</code> are always set to zero, - * and the field <code>isDst</code> is set to -1 (unknown). To set those - * fields, call {@link #normalize(boolean)} after parsing. - * - * To parse a date-time string and convert it to UTC milliseconds, do - * something like this: - * - * <pre> - * Time time = new Time(); - * String date = "20081013T160000Z"; - * time.parse(date); - * long millis = time.normalize(false); - * </pre> - * - * @param s the string to parse - * @return true if the resulting time value is in UTC time - * @throws android.util.TimeFormatException if s cannot be parsed. - */ - public boolean parse(String s) { - if (nativeParse(s)) { - timezone = TIMEZONE_UTC; - return true; - } - return false; - } - - /** - * Parse a time in the current zone in YYYYMMDDTHHMMSS format. - */ - native private boolean nativeParse(String s); - - /** - * Parse a time in RFC 3339 format. This method also parses simple dates - * (that is, strings that contain no time or time offset). For example, - * all of the following strings are valid: - * - * <ul> - * <li>"2008-10-13T16:00:00.000Z"</li> - * <li>"2008-10-13T16:00:00.000+07:00"</li> - * <li>"2008-10-13T16:00:00.000-07:00"</li> - * <li>"2008-10-13"</li> - * </ul> - * - * <p> - * If the string contains a time and time offset, then the time offset will - * be used to convert the time value to UTC. - * </p> - * - * <p> - * If the given string contains just a date (with no time field), then - * the {@link #allDay} field is set to true and the {@link #hour}, - * {@link #minute}, and {@link #second} fields are set to zero. - * </p> - * - * <p> - * Returns true if the resulting time value is in UTC time. - * </p> - * - * @param s the string to parse - * @return true if the resulting time value is in UTC time - */ - public boolean parse3339(String s) { - if (nativeParse3339(s)) { - timezone = TIMEZONE_UTC; - return true; - } - return false; - } - - native private boolean nativeParse3339(String s); - - /** - * Returns the timezone string that is currently set for the device. - */ - public static String getCurrentTimezone() { - return TimeZone.getDefault().getID(); - } - - /** - * Sets the time of the given Time object to the current time. - */ - native public void setToNow(); - - /** - * Converts this time to milliseconds. Suitable for interacting with the - * standard java libraries. The time is in UTC milliseconds since the epoch. - * This does an implicit normalization to compute the milliseconds but does - * <em>not</em> change any of the fields in this Time object. If you want - * to normalize the fields in this Time object and also get the milliseconds - * then use {@link #normalize(boolean)}. - * - * <p> - * If "ignoreDst" is false, then this method uses the current setting of the - * "isDst" field and will adjust the returned time if the "isDst" field is - * wrong for the given time. See the sample code below for an example of - * this. - * - * <p> - * If "ignoreDst" is true, then this method ignores the current setting of - * the "isDst" field in this Time object and will instead figure out the - * correct value of "isDst" (as best it can) from the fields in this - * Time object. The only case where this method cannot figure out the - * correct value of the "isDst" field is when the time is inherently - * ambiguous because it falls in the hour that is repeated when switching - * from Daylight-Saving Time to Standard Time. - * - * <p> - * Here is an example where <tt>toMillis(true)</tt> adjusts the time, - * assuming that DST changes at 2am on Sunday, Nov 4, 2007. - * - * <pre> - * Time time = new Time(); - * time.set(2007, 10, 4); // set the date to Nov 4, 2007, 12am - * time.normalize(); // this sets isDst = 1 - * time.monthDay += 1; // changes the date to Nov 5, 2007, 12am - * millis = time.toMillis(false); // millis is Nov 4, 2007, 11pm - * millis = time.toMillis(true); // millis is Nov 5, 2007, 12am - * </pre> - * - * <p> - * To avoid this problem, use <tt>toMillis(true)</tt> - * after adding or subtracting days or explicitly setting the "monthDay" - * field. On the other hand, if you are adding - * or subtracting hours or minutes, then you should use - * <tt>toMillis(false)</tt>. - * - * <p> - * You should also use <tt>toMillis(false)</tt> if you want - * to read back the same milliseconds that you set with {@link #set(long)} - * or {@link #set(Time)} or after parsing a date string. - */ - native public long toMillis(boolean ignoreDst); - - /** - * Sets the fields in this Time object given the UTC milliseconds. After - * this method returns, all the fields are normalized. - * This also sets the "isDst" field to the correct value. - * - * @param millis the time in UTC milliseconds since the epoch. - */ - native public void set(long millis); - - /** - * Format according to RFC 2445 DATETIME type. - * - * <p> - * The same as format("%Y%m%dT%H%M%S"). - */ - native public String format2445(); - - /** - * Copy the value of that to this Time object. No normalization happens. - */ - public void set(Time that) { - this.timezone = that.timezone; - this.allDay = that.allDay; - this.second = that.second; - this.minute = that.minute; - this.hour = that.hour; - this.monthDay = that.monthDay; - this.month = that.month; - this.year = that.year; - this.weekDay = that.weekDay; - this.yearDay = that.yearDay; - this.isDst = that.isDst; - this.gmtoff = that.gmtoff; - } - - /** - * Sets the fields. Sets weekDay, yearDay and gmtoff to 0, and isDst to -1. - * Call {@link #normalize(boolean)} if you need those. - */ - public void set(int second, int minute, int hour, int monthDay, int month, int year) { - this.allDay = false; - this.second = second; - this.minute = minute; - this.hour = hour; - this.monthDay = monthDay; - this.month = month; - this.year = year; - this.weekDay = 0; - this.yearDay = 0; - this.isDst = -1; - this.gmtoff = 0; - } - - /** - * Sets the date from the given fields. Also sets allDay to true. - * Sets weekDay, yearDay and gmtoff to 0, and isDst to -1. - * Call {@link #normalize(boolean)} if you need those. - * - * @param monthDay the day of the month (in the range [1,31]) - * @param month the zero-based month number (in the range [0,11]) - * @param year the year - */ - public void set(int monthDay, int month, int year) { - this.allDay = true; - this.second = 0; - this.minute = 0; - this.hour = 0; - this.monthDay = monthDay; - this.month = month; - this.year = year; - this.weekDay = 0; - this.yearDay = 0; - this.isDst = -1; - this.gmtoff = 0; - } - - /** - * Returns true if the time represented by this Time object occurs before - * the given time. - * - * @param that a given Time object to compare against - * @return true if this time is less than the given time - */ - public boolean before(Time that) { - return Time.compare(this, that) < 0; - } - - - /** - * Returns true if the time represented by this Time object occurs after - * the given time. - * - * @param that a given Time object to compare against - * @return true if this time is greater than the given time - */ - public boolean after(Time that) { - return Time.compare(this, that) > 0; - } - - /** - * This array is indexed by the weekDay field (SUNDAY=0, MONDAY=1, etc.) - * and gives a number that can be added to the yearDay to give the - * closest Thursday yearDay. - */ - private static final int[] sThursdayOffset = { -3, 3, 2, 1, 0, -1, -2 }; - - /** - * Computes the week number according to ISO 8601. The current Time - * object must already be normalized because this method uses the - * yearDay and weekDay fields. - * - * <p> - * In IS0 8601, weeks start on Monday. - * The first week of the year (week 1) is defined by ISO 8601 as the - * first week with four or more of its days in the starting year. - * Or equivalently, the week containing January 4. Or equivalently, - * the week with the year's first Thursday in it. - * </p> - * - * <p> - * The week number can be calculated by counting Thursdays. Week N - * contains the Nth Thursday of the year. - * </p> - * - * @return the ISO week number. - */ - public int getWeekNumber() { - // Get the year day for the closest Thursday - int closestThursday = yearDay + sThursdayOffset[weekDay]; - - // Year days start at 0 - if (closestThursday >= 0 && closestThursday <= 364) { - return closestThursday / 7 + 1; - } - - // The week crosses a year boundary. - Time temp = new Time(this); - temp.monthDay += sThursdayOffset[weekDay]; - temp.normalize(true /* ignore isDst */); - return temp.yearDay / 7 + 1; - } - - /** - * Return a string in the RFC 3339 format. - * <p> - * If allDay is true, expresses the time as Y-M-D</p> - * <p> - * Otherwise, if the timezone is UTC, expresses the time as Y-M-D-T-H-M-S UTC</p> - * <p> - * Otherwise the time is expressed the time as Y-M-D-T-H-M-S +- GMT</p> - * @param allDay - * @return string in the RFC 3339 format. - */ - public String format3339(boolean allDay) { - if (allDay) { - return format(Y_M_D); - } else if (TIMEZONE_UTC.equals(timezone)) { - return format(Y_M_D_T_H_M_S_000_Z); - } else { - String base = format(Y_M_D_T_H_M_S_000); - String sign = (gmtoff < 0) ? "-" : "+"; - int offset = (int)Math.abs(gmtoff); - int minutes = (offset % 3600) / 60; - int hours = offset / 3600; - - return String.format("%s%s%02d:%02d", base, sign, hours, minutes); - } - } - - /** - * Returns true if the day of the given time is the epoch on the Julian Calendar - * (January 1, 1970 on the Gregorian calendar). - * - * @param time the time to test - * @return true if epoch. - */ - public static boolean isEpoch(Time time) { - long millis = time.toMillis(true); - return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY; - } - - /** - * Computes the Julian day number, given the UTC milliseconds - * and the offset (in seconds) from UTC. The Julian day for a given - * date will be the same for every timezone. For example, the Julian - * day for July 1, 2008 is 2454649. This is the same value no matter - * what timezone is being used. The Julian day is useful for testing - * if two events occur on the same day and for determining the relative - * time of an event from the present ("yesterday", "3 days ago", etc.). - * - * <p> - * Use {@link #toMillis(boolean)} to get the milliseconds. - * - * @param millis the time in UTC milliseconds - * @param gmtoff the offset from UTC in seconds - * @return the Julian day - */ - public static int getJulianDay(long millis, long gmtoff) { - long offsetMillis = gmtoff * 1000; - long julianDay = (millis + offsetMillis) / DateUtils.DAY_IN_MILLIS; - return (int) julianDay + EPOCH_JULIAN_DAY; - } - - /** - * <p>Sets the time from the given Julian day number, which must be based on - * the same timezone that is set in this Time object. The "gmtoff" field - * need not be initialized because the given Julian day may have a different - * GMT offset than whatever is currently stored in this Time object anyway. - * After this method returns all the fields will be normalized and the time - * will be set to 12am at the beginning of the given Julian day. - * </p> - * - * <p> - * The only exception to this is if 12am does not exist for that day because - * of daylight saving time. For example, Cairo, Eqypt moves time ahead one - * hour at 12am on April 25, 2008 and there are a few other places that - * also change daylight saving time at 12am. In those cases, the time - * will be set to 1am. - * </p> - * - * @param julianDay the Julian day in the timezone for this Time object - * @return the UTC milliseconds for the beginning of the Julian day - */ - public long setJulianDay(int julianDay) { - // Don't bother with the GMT offset since we don't know the correct - // value for the given Julian day. Just get close and then adjust - // the day. - long millis = (julianDay - EPOCH_JULIAN_DAY) * DateUtils.DAY_IN_MILLIS; - set(millis); - - // Figure out how close we are to the requested Julian day. - // We can't be off by more than a day. - int approximateDay = getJulianDay(millis, gmtoff); - int diff = julianDay - approximateDay; - monthDay += diff; - - // Set the time to 12am and re-normalize. - hour = 0; - minute = 0; - second = 0; - millis = normalize(true); - return millis; - } -} diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java deleted file mode 100644 index 6df0b35..0000000 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.util.Log; -import android.view.KeyEvent; -import android.text.*; -import android.widget.TextView; -import android.view.View; -import android.view.MotionEvent; - -// XXX this doesn't extend MetaKeyKeyListener because the signatures -// don't match. Need to figure that out. Meanwhile the meta keys -// won't work in fields that don't take input. - -public class -ArrowKeyMovementMethod -implements MovementMethod -{ - private boolean up(TextView widget, Spannable buffer) { - boolean cap = (MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_SHIFT_ON) == 1) || - (MetaKeyKeyListener.getMetaState(buffer, - MetaKeyKeyListener.META_SELECTING) != 0); - boolean alt = MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_ALT_ON) == 1; - Layout layout = widget.getLayout(); - - if (cap) { - if (alt) { - Selection.extendSelection(buffer, 0); - return true; - } else { - return Selection.extendUp(buffer, layout); - } - } else { - if (alt) { - Selection.setSelection(buffer, 0); - return true; - } else { - return Selection.moveUp(buffer, layout); - } - } - } - - private boolean down(TextView widget, Spannable buffer) { - boolean cap = (MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_SHIFT_ON) == 1) || - (MetaKeyKeyListener.getMetaState(buffer, - MetaKeyKeyListener.META_SELECTING) != 0); - boolean alt = MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_ALT_ON) == 1; - Layout layout = widget.getLayout(); - - if (cap) { - if (alt) { - Selection.extendSelection(buffer, buffer.length()); - return true; - } else { - return Selection.extendDown(buffer, layout); - } - } else { - if (alt) { - Selection.setSelection(buffer, buffer.length()); - return true; - } else { - return Selection.moveDown(buffer, layout); - } - } - } - - private boolean left(TextView widget, Spannable buffer) { - boolean cap = (MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_SHIFT_ON) == 1) || - (MetaKeyKeyListener.getMetaState(buffer, - MetaKeyKeyListener.META_SELECTING) != 0); - boolean alt = MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_ALT_ON) == 1; - Layout layout = widget.getLayout(); - - if (cap) { - if (alt) { - return Selection.extendToLeftEdge(buffer, layout); - } else { - return Selection.extendLeft(buffer, layout); - } - } else { - if (alt) { - return Selection.moveToLeftEdge(buffer, layout); - } else { - return Selection.moveLeft(buffer, layout); - } - } - } - - private boolean right(TextView widget, Spannable buffer) { - boolean cap = (MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_SHIFT_ON) == 1) || - (MetaKeyKeyListener.getMetaState(buffer, - MetaKeyKeyListener.META_SELECTING) != 0); - boolean alt = MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_ALT_ON) == 1; - Layout layout = widget.getLayout(); - - if (cap) { - if (alt) { - return Selection.extendToRightEdge(buffer, layout); - } else { - return Selection.extendRight(buffer, layout); - } - } else { - if (alt) { - return Selection.moveToRightEdge(buffer, layout); - } else { - return Selection.moveRight(buffer, layout); - } - } - } - - public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { - if (executeDown(widget, buffer, keyCode)) { - MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); - MetaKeyKeyListener.resetLockedMeta(buffer); - return true; - } - - return false; - } - - private boolean executeDown(TextView widget, Spannable buffer, int keyCode) { - boolean handled = false; - - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - handled |= up(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_DOWN: - handled |= down(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_LEFT: - handled |= left(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_RIGHT: - handled |= right(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_CENTER: - if (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0) { - if (widget.showContextMenu()) { - handled = true; - } - } - } - - if (handled) { - MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); - MetaKeyKeyListener.resetLockedMeta(buffer); - } - - return handled; - } - - public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { - return false; - } - - public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) { - int code = event.getKeyCode(); - if (code != KeyEvent.KEYCODE_UNKNOWN - && event.getAction() == KeyEvent.ACTION_MULTIPLE) { - int repeat = event.getRepeatCount(); - boolean handled = false; - while ((--repeat) > 0) { - handled |= executeDown(view, text, code); - } - return handled; - } - return false; - } - - public boolean onTrackballEvent(TextView widget, Spannable text, - MotionEvent event) { - return false; - } - - public boolean onTouchEvent(TextView widget, Spannable buffer, - MotionEvent event) { - boolean handled = Touch.onTouchEvent(widget, buffer, event); - - if (widget.isFocused()) { - if (event.getAction() == MotionEvent.ACTION_UP) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - boolean cap = (MetaKeyKeyListener.getMetaState(buffer, - KeyEvent.META_SHIFT_ON) == 1) || - (MetaKeyKeyListener.getMetaState(buffer, - MetaKeyKeyListener.META_SELECTING) != 0); - - if (cap) { - Selection.extendSelection(buffer, off); - } else { - Selection.setSelection(buffer, off); - } - - MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); - MetaKeyKeyListener.resetLockedMeta(buffer); - - return true; - } - } - - return handled; - } - - public boolean canSelectArbitrarily() { - return true; - } - - public void initialize(TextView widget, Spannable text) { - Selection.setSelection(text, 0); - } - - public void onTakeFocus(TextView view, Spannable text, int dir) { - if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) { - Layout layout = view.getLayout(); - - if (layout == null) { - /* - * This shouldn't be null, but do something sensible if it is. - */ - Selection.setSelection(text, text.length()); - } else { - /* - * Put the cursor at the end of the first line, which is - * either the last offset if there is only one line, or the - * offset before the first character of the second line - * if there is more than one line. - */ - if (layout.getLineCount() == 1) { - Selection.setSelection(text, text.length()); - } else { - Selection.setSelection(text, layout.getLineStart(1) - 1); - } - } - } else { - Selection.setSelection(text, text.length()); - } - } - - public static MovementMethod getInstance() { - if (sInstance == null) - sInstance = new ArrowKeyMovementMethod(); - - return sInstance; - } - - private static ArrowKeyMovementMethod sInstance; -} diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java deleted file mode 100644 index 6df6a3a..0000000 --- a/core/java/android/text/method/BaseKeyListener.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.view.View; -import android.text.*; -import android.text.method.TextKeyListener.Capitalize; -import android.widget.TextView; - -public abstract class BaseKeyListener -extends MetaKeyKeyListener -implements KeyListener { - /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete(); - - /** - * Performs the action that happens when you press the DEL key in - * a TextView. If there is a selection, deletes the selection; - * otherwise, DEL alone deletes the character before the cursor, - * if any; - * ALT+DEL deletes everything on the line the cursor is on. - * - * @return true if anything was deleted; false otherwise. - */ - public boolean backspace(View view, Editable content, int keyCode, - KeyEvent event) { - int selStart, selEnd; - boolean result = true; - - { - int a = Selection.getSelectionStart(content); - int b = Selection.getSelectionEnd(content); - - selStart = Math.min(a, b); - selEnd = Math.max(a, b); - } - - if (selStart != selEnd) { - content.delete(selStart, selEnd); - } else if (altBackspace(view, content, keyCode, event)) { - result = true; - } else { - int to = TextUtils.getOffsetBefore(content, selEnd); - - if (to != selEnd) { - content.delete(Math.min(to, selEnd), Math.max(to, selEnd)); - } - else { - result = false; - } - } - - if (result) - adjustMetaAfterKeypress(content); - - return result; - } - - private boolean altBackspace(View view, Editable content, int keyCode, - KeyEvent event) { - if (getMetaState(content, META_ALT_ON) != 1) { - return false; - } - - if (!(view instanceof TextView)) { - return false; - } - - Layout layout = ((TextView) view).getLayout(); - - if (layout == null) { - return false; - } - - int l = layout.getLineForOffset(Selection.getSelectionStart(content)); - int start = layout.getLineStart(l); - int end = layout.getLineEnd(l); - - if (end == start) { - return false; - } - - content.delete(start, end); - return true; - } - - static int makeTextContentType(Capitalize caps, boolean autoText) { - int contentType = InputType.TYPE_CLASS_TEXT; - switch (caps) { - case CHARACTERS: - contentType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; - break; - case WORDS: - contentType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS; - break; - case SENTENCES: - contentType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; - break; - } - if (autoText) { - contentType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; - } - return contentType; - } - - public boolean onKeyDown(View view, Editable content, - int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DEL) { - backspace(view, content, keyCode, event); - return true; - } - - return super.onKeyDown(view, content, keyCode, event); - } - - /** - * Base implementation handles ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting - * the event's text into the content. - */ - public boolean onKeyOther(View view, Editable content, KeyEvent event) { - if (event.getAction() != KeyEvent.ACTION_MULTIPLE - || event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) { - // Not something we are interested in. - return false; - } - - int selStart, selEnd; - - { - int a = Selection.getSelectionStart(content); - int b = Selection.getSelectionEnd(content); - - selStart = Math.min(a, b); - selEnd = Math.max(a, b); - } - - CharSequence text = event.getCharacters(); - if (text == null) { - return false; - } - - content.replace(selStart, selEnd, text); - return true; - } -} - diff --git a/core/java/android/text/method/CharacterPickerDialog.java b/core/java/android/text/method/CharacterPickerDialog.java deleted file mode 100644 index 3c406751..0000000 --- a/core/java/android/text/method/CharacterPickerDialog.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import com.android.internal.R; - -import android.app.Dialog; -import android.content.Context; -import android.os.Bundle; -import android.text.*; -import android.view.LayoutInflater; -import android.view.View.OnClickListener; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.Button; -import android.widget.GridView; -import android.widget.TextView; - -/** - * Dialog for choosing accented characters related to a base character. - */ -public class CharacterPickerDialog extends Dialog - implements OnItemClickListener, OnClickListener { - private View mView; - private Editable mText; - private String mOptions; - private boolean mInsert; - private LayoutInflater mInflater; - - /** - * Creates a new CharacterPickerDialog that presents the specified - * <code>options</code> for insertion or replacement (depending on - * the sense of <code>insert</code>) into <code>text</code>. - */ - public CharacterPickerDialog(Context context, View view, - Editable text, String options, - boolean insert) { - super(context); - - mView = view; - mText = text; - mOptions = options; - mInsert = insert; - mInflater = LayoutInflater.from(context); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - WindowManager.LayoutParams params = getWindow().getAttributes(); - params.token = mView.getApplicationWindowToken(); - params.type = params.TYPE_APPLICATION_ATTACHED_DIALOG; - - setTitle(R.string.select_character); - setContentView(R.layout.character_picker); - - GridView grid = (GridView) findViewById(R.id.characterPicker); - grid.setAdapter(new OptionsAdapter(getContext())); - grid.setOnItemClickListener(this); - - findViewById(R.id.cancel).setOnClickListener(this); - } - - /** - * Handles clicks on the character buttons. - */ - public void onItemClick(AdapterView parent, View view, int position, long id) { - int selEnd = Selection.getSelectionEnd(mText); - String result = String.valueOf(mOptions.charAt(position)); - - if (mInsert || selEnd == 0) { - mText.insert(selEnd, result); - } else { - mText.replace(selEnd - 1, selEnd, result); - } - - dismiss(); - } - - /** - * Handles clicks on the Cancel button. - */ - public void onClick(View v) { - dismiss(); - } - - private class OptionsAdapter extends BaseAdapter { - private Context mContext; - - public OptionsAdapter(Context context) { - super(); - mContext = context; - } - - public View getView(int position, View convertView, ViewGroup parent) { - Button b = (Button) - mInflater.inflate(R.layout.character_picker_button, null); - b.setText(String.valueOf(mOptions.charAt(position))); - return b; - } - - public final int getCount() { - return mOptions.length(); - } - - public final Object getItem(int position) { - return String.valueOf(mOptions.charAt(position)); - } - - public final long getItemId(int position) { - return position; - } - } -} diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java deleted file mode 100644 index 7c11434..0000000 --- a/core/java/android/text/method/DateKeyListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.text.InputType; - -/** - * For entering dates in a text field. - */ -public class DateKeyListener extends NumberKeyListener -{ - public int getInputType() { - return InputType.TYPE_CLASS_DATETIME - | InputType.TYPE_DATETIME_VARIATION_DATE; - } - - @Override - protected char[] getAcceptedChars() - { - return CHARACTERS; - } - - public static DateKeyListener getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new DateKeyListener(); - return sInstance; - } - - /** - * The characters that are used. - * - * @see KeyEvent#getMatch - * @see #getAcceptedChars - */ - public static final char[] CHARACTERS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '/', '-', '.' - }; - - private static DateKeyListener sInstance; -} diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java deleted file mode 100644 index f8ebc40..0000000 --- a/core/java/android/text/method/DateTimeKeyListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.text.InputType; -import android.view.KeyEvent; - -/** - * For entering dates and times in the same text field. - */ -public class DateTimeKeyListener extends NumberKeyListener -{ - public int getInputType() { - return InputType.TYPE_CLASS_DATETIME - | InputType.TYPE_DATETIME_VARIATION_NORMAL; - } - - @Override - protected char[] getAcceptedChars() - { - return CHARACTERS; - } - - public static DateTimeKeyListener getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new DateTimeKeyListener(); - return sInstance; - } - - /** - * The characters that are used. - * - * @see KeyEvent#getMatch - * @see #getAcceptedChars - */ - public static final char[] CHARACTERS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'm', - 'p', ':', '/', '-', ' ' - }; - - private static DateTimeKeyListener sInstance; -} diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java deleted file mode 100644 index b121e60..0000000 --- a/core/java/android/text/method/DialerKeyListener.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.view.KeyCharacterMap.KeyData; -import android.text.InputType; -import android.text.Spannable; - -/** - * For dialing-only text entry - */ -public class DialerKeyListener extends NumberKeyListener -{ - @Override - protected char[] getAcceptedChars() - { - return CHARACTERS; - } - - public static DialerKeyListener getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new DialerKeyListener(); - return sInstance; - } - - public int getInputType() { - return InputType.TYPE_CLASS_PHONE; - } - - /** - * Overrides the superclass's lookup method to prefer the number field - * from the KeyEvent. - */ - protected int lookup(KeyEvent event, Spannable content) { - int meta = getMetaState(content); - int number = event.getNumber(); - - /* - * Prefer number if no meta key is active, or if it produces something - * valid and the meta lookup does not. - */ - if ((meta & (KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)) == 0) { - if (number != 0) { - return number; - } - } - - int match = super.lookup(event, content); - - if (match != 0) { - return match; - } else { - /* - * If a meta key is active but the lookup with the meta key - * did not produce anything, try some other meta keys, because - * the user might have pressed SHIFT when they meant ALT, - * or vice versa. - */ - - if (meta != 0) { - KeyData kd = new KeyData(); - char[] accepted = getAcceptedChars(); - - if (event.getKeyData(kd)) { - for (int i = 1; i < kd.meta.length; i++) { - if (ok(accepted, kd.meta[i])) { - return kd.meta[i]; - } - } - } - } - - /* - * Otherwise, use the number associated with the key, since - * whatever they wanted to do with the meta key does not - * seem to be valid here. - */ - - return number; - } - } - - - /** - * The characters that are used. - * - * @see KeyEvent#getMatch - * @see #getAcceptedChars - */ - public static final char[] CHARACTERS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*', - '+', '-', '(', ')', ',', '/', 'N', '.', ' ' - }; - - private static DialerKeyListener sInstance; -} diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java deleted file mode 100644 index f0f072c..0000000 --- a/core/java/android/text/method/DigitsKeyListener.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.text.InputType; -import android.text.Spanned; -import android.text.SpannableStringBuilder; -import android.view.KeyEvent; - - -/** - * For digits-only text entry - */ -public class DigitsKeyListener extends NumberKeyListener -{ - private char[] mAccepted; - private boolean mSign; - private boolean mDecimal; - - private static final int SIGN = 1; - private static final int DECIMAL = 2; - - @Override - protected char[] getAcceptedChars() { - return mAccepted; - } - - /** - * The characters that are used. - * - * @see KeyEvent#getMatch - * @see #getAcceptedChars - */ - private static final char[][] CHARACTERS = new char[][] { - new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }, - new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' }, - new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.' }, - new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.' }, - }; - - /** - * Allocates a DigitsKeyListener that accepts the digits 0 through 9. - */ - public DigitsKeyListener() { - this(false, false); - } - - /** - * Allocates a DigitsKeyListener that accepts the digits 0 through 9, - * plus the minus sign (only at the beginning) and/or decimal point - * (only one per field) if specified. - */ - public DigitsKeyListener(boolean sign, boolean decimal) { - mSign = sign; - mDecimal = decimal; - - int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0); - mAccepted = CHARACTERS[kind]; - } - - /** - * Returns a DigitsKeyListener that accepts the digits 0 through 9. - */ - public static DigitsKeyListener getInstance() { - return getInstance(false, false); - } - - /** - * Returns a DigitsKeyListener that accepts the digits 0 through 9, - * plus the minus sign (only at the beginning) and/or decimal point - * (only one per field) if specified. - */ - public static DigitsKeyListener getInstance(boolean sign, boolean decimal) { - int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0); - - if (sInstance[kind] != null) - return sInstance[kind]; - - sInstance[kind] = new DigitsKeyListener(sign, decimal); - return sInstance[kind]; - } - - /** - * Returns a DigitsKeyListener that accepts only the characters - * that appear in the specified String. Note that not all characters - * may be available on every keyboard. - */ - public static DigitsKeyListener getInstance(String accepted) { - // TODO: do we need a cache of these to avoid allocating? - - DigitsKeyListener dim = new DigitsKeyListener(); - - dim.mAccepted = new char[accepted.length()]; - accepted.getChars(0, accepted.length(), dim.mAccepted, 0); - - return dim; - } - - public int getInputType() { - int contentType = InputType.TYPE_CLASS_NUMBER; - if (mSign) { - contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED; - } - if (mDecimal) { - contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL; - } - return contentType; - } - - @Override - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - CharSequence out = super.filter(source, start, end, dest, dstart, dend); - - if (mSign == false && mDecimal == false) { - return out; - } - - if (out != null) { - source = out; - start = 0; - end = out.length(); - } - - int sign = -1; - int decimal = -1; - int dlen = dest.length(); - - /* - * Find out if the existing text has '-' or '.' characters. - */ - - for (int i = 0; i < dstart; i++) { - char c = dest.charAt(i); - - if (c == '-') { - sign = i; - } else if (c == '.') { - decimal = i; - } - } - for (int i = dend; i < dlen; i++) { - char c = dest.charAt(i); - - if (c == '-') { - return ""; // Nothing can be inserted in front of a '-'. - } else if (c == '.') { - decimal = i; - } - } - - /* - * If it does, we must strip them out from the source. - * In addition, '-' must be the very first character, - * and nothing can be inserted before an existing '-'. - * Go in reverse order so the offsets are stable. - */ - - SpannableStringBuilder stripped = null; - - for (int i = end - 1; i >= start; i--) { - char c = source.charAt(i); - boolean strip = false; - - if (c == '-') { - if (i != start || dstart != 0) { - strip = true; - } else if (sign >= 0) { - strip = true; - } else { - sign = i; - } - } else if (c == '.') { - if (decimal >= 0) { - strip = true; - } else { - decimal = i; - } - } - - if (strip) { - if (end == start + 1) { - return ""; // Only one character, and it was stripped. - } - - if (stripped == null) { - stripped = new SpannableStringBuilder(source, start, end); - } - - stripped.delete(i - start, i + 1 - start); - } - } - - if (stripped != null) { - return stripped; - } else if (out != null) { - return out; - } else { - return null; - } - } - - private static DigitsKeyListener[] sInstance = new DigitsKeyListener[4]; -} diff --git a/core/java/android/text/method/HideReturnsTransformationMethod.java b/core/java/android/text/method/HideReturnsTransformationMethod.java deleted file mode 100644 index ce18692..0000000 --- a/core/java/android/text/method/HideReturnsTransformationMethod.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.graphics.Rect; -import android.text.GetChars; -import android.text.Spanned; -import android.text.SpannedString; -import android.text.TextUtils; -import android.view.View; - -/** - * This transformation method causes any carriage return characters (\r) - * to be hidden by displaying them as zero-width non-breaking space - * characters (\uFEFF). - */ -public class HideReturnsTransformationMethod -extends ReplacementTransformationMethod { - private static char[] ORIGINAL = new char[] { '\r' }; - private static char[] REPLACEMENT = new char[] { '\uFEFF' }; - - /** - * The character to be replaced is \r. - */ - protected char[] getOriginal() { - return ORIGINAL; - } - - /** - * The character that \r is replaced with is \uFEFF. - */ - protected char[] getReplacement() { - return REPLACEMENT; - } - - public static HideReturnsTransformationMethod getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new HideReturnsTransformationMethod(); - return sInstance; - } - - private static HideReturnsTransformationMethod sInstance; -} diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java deleted file mode 100644 index 8594852..0000000 --- a/core/java/android/text/method/KeyListener.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.text.Editable; -import android.view.KeyEvent; -import android.view.View; - -/** - * Interface for converting text key events into edit operations on an - * Editable class. Note that for must cases this interface has been - * superceded by general soft input methods as defined by - * {@link android.view.inputmethod.InputMethod}; it should only be used - * for cases where an application has its own on-screen keypad and also wants - * to process hard keyboard events to match it. - */ -public interface KeyListener { - /** - * Return the type of text that this key listener is manipulating, - * as per {@link android.text.InputType}. This is used to - * determine the mode of the soft keyboard that is shown for the editor. - * - * <p>If you return - * {@link android.text.InputType#TYPE_NULL} - * then <em>no</em> soft keyboard will provided. In other words, you - * must be providing your own key pad for on-screen input and the key - * listener will be used to handle input from a hard keyboard. - * - * <p>If you - * return any other value, a soft input method will be created when the - * user puts focus in the editor, which will provide a keypad and also - * consume hard key events. This means that the key listener will generally - * not be used, instead the soft input method will take care of managing - * key input as per the content type returned here. - */ - public int getInputType(); - - /** - * If the key listener wants to handle this key, return true, - * otherwise return false and the caller (i.e. the widget host) - * will handle the key. - */ - public boolean onKeyDown(View view, Editable text, - int keyCode, KeyEvent event); - - /** - * If the key listener wants to handle this key release, return true, - * otherwise return false and the caller (i.e. the widget host) - * will handle the key. - */ - public boolean onKeyUp(View view, Editable text, - int keyCode, KeyEvent event); - - /** - * If the key listener wants to other kinds of key events, return true, - * otherwise return false and the caller (i.e. the widget host) - * will handle the key. - */ - public boolean onKeyOther(View view, Editable text, KeyEvent event); - - /** - * Remove the given shift states from the edited text. - */ - public void clearMetaKeyState(View view, Editable content, int states); -} diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java deleted file mode 100644 index 22e9cc6..0000000 --- a/core/java/android/text/method/LinkMovementMethod.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.content.Intent; -import android.net.Uri; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.text.*; -import android.text.style.*; -import android.view.View; -import android.widget.TextView; - -public class -LinkMovementMethod -extends ScrollingMovementMethod -{ - private static final int CLICK = 1; - private static final int UP = 2; - private static final int DOWN = 3; - - @Override - public boolean onKeyDown(TextView widget, Spannable buffer, - int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: - if (event.getRepeatCount() == 0) { - if (action(CLICK, widget, buffer)) { - return true; - } - } - } - - return super.onKeyDown(widget, buffer, keyCode, event); - } - - @Override - protected boolean up(TextView widget, Spannable buffer) { - if (action(UP, widget, buffer)) { - return true; - } - - return super.up(widget, buffer); - } - - @Override - protected boolean down(TextView widget, Spannable buffer) { - if (action(DOWN, widget, buffer)) { - return true; - } - - return super.down(widget, buffer); - } - - @Override - protected boolean left(TextView widget, Spannable buffer) { - if (action(UP, widget, buffer)) { - return true; - } - - return super.left(widget, buffer); - } - - @Override - protected boolean right(TextView widget, Spannable buffer) { - if (action(DOWN, widget, buffer)) { - return true; - } - - return super.right(widget, buffer); - } - - private boolean action(int what, TextView widget, Spannable buffer) { - boolean handled = false; - - Layout layout = widget.getLayout(); - - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - int areatop = widget.getScrollY(); - int areabot = areatop + widget.getHeight() - padding; - - int linetop = layout.getLineForVertical(areatop); - int linebot = layout.getLineForVertical(areabot); - - int first = layout.getLineStart(linetop); - int last = layout.getLineEnd(linebot); - - ClickableSpan[] candidates = buffer.getSpans(first, last, ClickableSpan.class); - - int a = Selection.getSelectionStart(buffer); - int b = Selection.getSelectionEnd(buffer); - - int selStart = Math.min(a, b); - int selEnd = Math.max(a, b); - - if (selStart < 0) { - if (buffer.getSpanStart(FROM_BELOW) >= 0) { - selStart = selEnd = buffer.length(); - } - } - - if (selStart > last) - selStart = selEnd = Integer.MAX_VALUE; - if (selEnd < first) - selStart = selEnd = -1; - - switch (what) { - case CLICK: - if (selStart == selEnd) { - return false; - } - - ClickableSpan[] link = buffer.getSpans(selStart, selEnd, ClickableSpan.class); - - if (link.length != 1) - return false; - - link[0].onClick(widget); - break; - - case UP: - int beststart, bestend; - - beststart = -1; - bestend = -1; - - for (int i = 0; i < candidates.length; i++) { - int end = buffer.getSpanEnd(candidates[i]); - - if (end < selEnd || selStart == selEnd) { - if (end > bestend) { - beststart = buffer.getSpanStart(candidates[i]); - bestend = end; - } - } - } - - if (beststart >= 0) { - Selection.setSelection(buffer, bestend, beststart); - return true; - } - - break; - - case DOWN: - beststart = Integer.MAX_VALUE; - bestend = Integer.MAX_VALUE; - - for (int i = 0; i < candidates.length; i++) { - int start = buffer.getSpanStart(candidates[i]); - - if (start > selStart || selStart == selEnd) { - if (start < beststart) { - beststart = start; - bestend = buffer.getSpanEnd(candidates[i]); - } - } - } - - if (bestend < Integer.MAX_VALUE) { - Selection.setSelection(buffer, beststart, bestend); - return true; - } - - break; - } - - return false; - } - - public boolean onKeyUp(TextView widget, Spannable buffer, - int keyCode, KeyEvent event) { - return false; - } - - @Override - public boolean onTouchEvent(TextView widget, Spannable buffer, - MotionEvent event) { - int action = event.getAction(); - - if (action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - link[0].onClick(widget); - } else if (action == MotionEvent.ACTION_DOWN) { - Selection.setSelection(buffer, - buffer.getSpanStart(link[0]), - buffer.getSpanEnd(link[0])); - } - - return true; - } else { - Selection.removeSelection(buffer); - } - } - - return super.onTouchEvent(widget, buffer, event); - } - - public void initialize(TextView widget, Spannable text) { - Selection.removeSelection(text); - text.removeSpan(FROM_BELOW); - } - - public void onTakeFocus(TextView view, Spannable text, int dir) { - Selection.removeSelection(text); - - if ((dir & View.FOCUS_BACKWARD) != 0) { - text.setSpan(FROM_BELOW, 0, 0, Spannable.SPAN_POINT_POINT); - } else { - text.removeSpan(FROM_BELOW); - } - } - - public static MovementMethod getInstance() { - if (sInstance == null) - sInstance = new LinkMovementMethod(); - - return sInstance; - } - - private static LinkMovementMethod sInstance; - private static Object FROM_BELOW = new NoCopySpan.Concrete(); -} diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java deleted file mode 100644 index 39ad976..0000000 --- a/core/java/android/text/method/MetaKeyKeyListener.java +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.view.View; -import android.text.*; - -/** - * This base class encapsulates the behavior for handling the meta keys - * (shift and alt) and the pseudo-meta state of selecting text. - * Key listeners that care about meta state should - * inherit from it; you should not instantiate this class directly in a client. - */ - -public abstract class MetaKeyKeyListener { - public static final int META_SHIFT_ON = KeyEvent.META_SHIFT_ON; - public static final int META_ALT_ON = KeyEvent.META_ALT_ON; - public static final int META_SYM_ON = KeyEvent.META_SYM_ON; - - private static final int LOCKED_SHIFT = 8; - - public static final int META_CAP_LOCKED = KeyEvent.META_SHIFT_ON << LOCKED_SHIFT; - public static final int META_ALT_LOCKED = KeyEvent.META_ALT_ON << LOCKED_SHIFT; - public static final int META_SYM_LOCKED = KeyEvent.META_SYM_ON << LOCKED_SHIFT; - - /** - * @hide pending API review - */ - public static final int META_SELECTING = 1 << 16; - - private static final int USED_SHIFT = 24; - - private static final long META_CAP_USED = ((long)KeyEvent.META_SHIFT_ON) << USED_SHIFT; - private static final long META_ALT_USED = ((long)KeyEvent.META_ALT_ON) << USED_SHIFT; - private static final long META_SYM_USED = ((long)KeyEvent.META_SYM_ON) << USED_SHIFT; - - private static final int PRESSED_SHIFT = 32; - - private static final long META_CAP_PRESSED = ((long)KeyEvent.META_SHIFT_ON) << PRESSED_SHIFT; - private static final long META_ALT_PRESSED = ((long)KeyEvent.META_ALT_ON) << PRESSED_SHIFT; - private static final long META_SYM_PRESSED = ((long)KeyEvent.META_SYM_ON) << PRESSED_SHIFT; - - private static final int RELEASED_SHIFT = 40; - - private static final long META_CAP_RELEASED = ((long)KeyEvent.META_SHIFT_ON) << RELEASED_SHIFT; - private static final long META_ALT_RELEASED = ((long)KeyEvent.META_ALT_ON) << RELEASED_SHIFT; - private static final long META_SYM_RELEASED = ((long)KeyEvent.META_SYM_ON) << RELEASED_SHIFT; - - private static final long META_SHIFT_MASK = META_SHIFT_ON - | META_CAP_LOCKED | META_CAP_USED - | META_CAP_PRESSED | META_CAP_RELEASED; - private static final long META_ALT_MASK = META_ALT_ON - | META_ALT_LOCKED | META_ALT_USED - | META_ALT_PRESSED | META_ALT_RELEASED; - private static final long META_SYM_MASK = META_SYM_ON - | META_SYM_LOCKED | META_SYM_USED - | META_SYM_PRESSED | META_SYM_RELEASED; - - private static final Object CAP = new NoCopySpan.Concrete(); - private static final Object ALT = new NoCopySpan.Concrete(); - private static final Object SYM = new NoCopySpan.Concrete(); - private static final Object SELECTING = new NoCopySpan.Concrete(); - - /** - * Resets all meta state to inactive. - */ - public static void resetMetaState(Spannable text) { - text.removeSpan(CAP); - text.removeSpan(ALT); - text.removeSpan(SYM); - text.removeSpan(SELECTING); - } - - /** - * Gets the state of the meta keys. - * - * @param text the buffer in which the meta key would have been pressed. - * - * @return an integer in which each bit set to one represents a pressed - * or locked meta key. - */ - public static final int getMetaState(CharSequence text) { - return getActive(text, CAP, META_SHIFT_ON, META_CAP_LOCKED) | - getActive(text, ALT, META_ALT_ON, META_ALT_LOCKED) | - getActive(text, SYM, META_SYM_ON, META_SYM_LOCKED) | - getActive(text, SELECTING, META_SELECTING, META_SELECTING); - } - - /** - * Gets the state of a particular meta key. - * - * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON, or META_SELECTING - * @param text the buffer in which the meta key would have been pressed. - * - * @return 0 if inactive, 1 if active, 2 if locked. - */ - public static final int getMetaState(CharSequence text, int meta) { - switch (meta) { - case META_SHIFT_ON: - return getActive(text, CAP, 1, 2); - - case META_ALT_ON: - return getActive(text, ALT, 1, 2); - - case META_SYM_ON: - return getActive(text, SYM, 1, 2); - - case META_SELECTING: - return getActive(text, SELECTING, 1, 2); - - default: - return 0; - } - } - - private static int getActive(CharSequence text, Object meta, - int on, int lock) { - if (!(text instanceof Spanned)) { - return 0; - } - - Spanned sp = (Spanned) text; - int flag = sp.getSpanFlags(meta); - - if (flag == LOCKED) { - return lock; - } else if (flag != 0) { - return on; - } else { - return 0; - } - } - - /** - * Call this method after you handle a keypress so that the meta - * state will be reset to unshifted (if it is not still down) - * or primed to be reset to unshifted (once it is released). - */ - public static void adjustMetaAfterKeypress(Spannable content) { - adjust(content, CAP); - adjust(content, ALT); - adjust(content, SYM); - } - - /** - * Returns true if this object is one that this class would use to - * keep track of meta state in the specified text. - */ - public static boolean isMetaTracker(CharSequence text, Object what) { - return what == CAP || what == ALT || what == SYM || - what == SELECTING; - } - - private static void adjust(Spannable content, Object what) { - int current = content.getSpanFlags(what); - - if (current == PRESSED) - content.setSpan(what, 0, 0, USED); - else if (current == RELEASED) - content.removeSpan(what); - } - - /** - * Call this if you are a method that ignores the locked meta state - * (arrow keys, for example) and you handle a key. - */ - protected static void resetLockedMeta(Spannable content) { - resetLock(content, CAP); - resetLock(content, ALT); - resetLock(content, SYM); - resetLock(content, SELECTING); - } - - private static void resetLock(Spannable content, Object what) { - int current = content.getSpanFlags(what); - - if (current == LOCKED) - content.removeSpan(what); - } - - /** - * Handles presses of the meta keys. - */ - public boolean onKeyDown(View view, Editable content, - int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { - press(content, CAP); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT - || keyCode == KeyEvent.KEYCODE_NUM) { - press(content, ALT); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_SYM) { - press(content, SYM); - return true; - } - - return false; // no super to call through to - } - - private void press(Editable content, Object what) { - int state = content.getSpanFlags(what); - - if (state == PRESSED) - ; // repeat before use - else if (state == RELEASED) - content.setSpan(what, 0, 0, LOCKED); - else if (state == USED) - ; // repeat after use - else if (state == LOCKED) - content.removeSpan(what); - else - content.setSpan(what, 0, 0, PRESSED); - } - - /** - * Start selecting text. - * @hide pending API review - */ - public static void startSelecting(View view, Spannable content) { - content.setSpan(SELECTING, 0, 0, PRESSED); - } - - /** - * Stop selecting text. This does not actually collapse the selection; - * call {@link android.text.Selection#setSelection} too. - * @hide pending API review - */ - public static void stopSelecting(View view, Spannable content) { - content.removeSpan(SELECTING); - } - - /** - * Handles release of the meta keys. - */ - public boolean onKeyUp(View view, Editable content, int keyCode, - KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { - release(content, CAP); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT - || keyCode == KeyEvent.KEYCODE_NUM) { - release(content, ALT); - return true; - } - - if (keyCode == KeyEvent.KEYCODE_SYM) { - release(content, SYM); - return true; - } - - return false; // no super to call through to - } - - private void release(Editable content, Object what) { - int current = content.getSpanFlags(what); - - if (current == USED) - content.removeSpan(what); - else if (current == PRESSED) - content.setSpan(what, 0, 0, RELEASED); - } - - public void clearMetaKeyState(View view, Editable content, int states) { - clearMetaKeyState(content, states); - } - - public static void clearMetaKeyState(Editable content, int states) { - if ((states&META_SHIFT_ON) != 0) content.removeSpan(CAP); - if ((states&META_ALT_ON) != 0) content.removeSpan(ALT); - if ((states&META_SYM_ON) != 0) content.removeSpan(SYM); - if ((states&META_SELECTING) != 0) content.removeSpan(SELECTING); - } - - /** - * Call this if you are a method that ignores the locked meta state - * (arrow keys, for example) and you handle a key. - */ - public static long resetLockedMeta(long state) { - state = resetLock(state, META_SHIFT_ON, META_SHIFT_MASK); - state = resetLock(state, META_ALT_ON, META_ALT_MASK); - state = resetLock(state, META_SYM_ON, META_SYM_MASK); - return state; - } - - private static long resetLock(long state, int what, long mask) { - if ((state&(((long)what)<<LOCKED_SHIFT)) != 0) { - state &= ~mask; - } - return state; - } - - // --------------------------------------------------------------------- - // Version of API that operates on a state bit mask - // --------------------------------------------------------------------- - - /** - * Gets the state of the meta keys. - * - * @param state the current meta state bits. - * - * @return an integer in which each bit set to one represents a pressed - * or locked meta key. - */ - public static final int getMetaState(long state) { - return getActive(state, META_SHIFT_ON, META_SHIFT_ON, META_CAP_LOCKED) | - getActive(state, META_ALT_ON, META_ALT_ON, META_ALT_LOCKED) | - getActive(state, META_SYM_ON, META_SYM_ON, META_SYM_LOCKED); - } - - /** - * Gets the state of a particular meta key. - * - * @param state the current state bits. - * @param meta META_SHIFT_ON, META_ALT_ON, or META_SYM_ON - * - * @return 0 if inactive, 1 if active, 2 if locked. - */ - public static final int getMetaState(long state, int meta) { - switch (meta) { - case META_SHIFT_ON: - return getActive(state, meta, 1, 2); - - case META_ALT_ON: - return getActive(state, meta, 1, 2); - - case META_SYM_ON: - return getActive(state, meta, 1, 2); - - default: - return 0; - } - } - - private static int getActive(long state, int meta, int on, int lock) { - if ((state&(meta<<LOCKED_SHIFT)) != 0) { - return lock; - } else if ((state&meta) != 0) { - return on; - } else { - return 0; - } - } - - /** - * Call this method after you handle a keypress so that the meta - * state will be reset to unshifted (if it is not still down) - * or primed to be reset to unshifted (once it is released). Takes - * the current state, returns the new state. - */ - public static long adjustMetaAfterKeypress(long state) { - state = adjust(state, META_SHIFT_ON, META_SHIFT_MASK); - state = adjust(state, META_ALT_ON, META_ALT_MASK); - state = adjust(state, META_SYM_ON, META_SYM_MASK); - return state; - } - - private static long adjust(long state, int what, long mask) { - if ((state&(((long)what)<<PRESSED_SHIFT)) != 0) - return (state&~mask) | what | ((long)what)<<USED_SHIFT; - else if ((state&(((long)what)<<RELEASED_SHIFT)) != 0) - return state & ~mask; - return state; - } - - /** - * Handles presses of the meta keys. - */ - public static long handleKeyDown(long state, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { - return press(state, META_SHIFT_ON, META_SHIFT_MASK); - } - - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT - || keyCode == KeyEvent.KEYCODE_NUM) { - return press(state, META_ALT_ON, META_ALT_MASK); - } - - if (keyCode == KeyEvent.KEYCODE_SYM) { - return press(state, META_SYM_ON, META_SYM_MASK); - } - - return state; - } - - private static long press(long state, int what, long mask) { - if ((state&(((long)what)<<PRESSED_SHIFT)) != 0) - ; // repeat before use - else if ((state&(((long)what)<<RELEASED_SHIFT)) != 0) - state = (state&~mask) | what | (((long)what) << LOCKED_SHIFT); - else if ((state&(((long)what)<<USED_SHIFT)) != 0) - ; // repeat after use - else if ((state&(((long)what)<<LOCKED_SHIFT)) != 0) - state = state&~mask; - else - state = state | what | (((long)what)<<PRESSED_SHIFT); - return state; - } - - /** - * Handles release of the meta keys. - */ - public static long handleKeyUp(long state, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { - return release(state, META_SHIFT_ON, META_SHIFT_MASK); - } - - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT - || keyCode == KeyEvent.KEYCODE_NUM) { - return release(state, META_ALT_ON, META_ALT_MASK); - } - - if (keyCode == KeyEvent.KEYCODE_SYM) { - return release(state, META_SYM_ON, META_SYM_MASK); - } - - return state; - } - - private static long release(long state, int what, long mask) { - if ((state&(((long)what)<<USED_SHIFT)) != 0) - state = state&~mask; - else if ((state&(((long)what)<<PRESSED_SHIFT)) != 0) - state = state | what | (((long)what)<<RELEASED_SHIFT); - return state; - } - - public long clearMetaKeyState(long state, int which) { - if ((which&META_SHIFT_ON) != 0) - state = resetLock(state, META_SHIFT_ON, META_SHIFT_MASK); - if ((which&META_ALT_ON) != 0) - state = resetLock(state, META_ALT_ON, META_ALT_MASK); - if ((which&META_SYM_ON) != 0) - state = resetLock(state, META_SYM_ON, META_SYM_MASK); - return state; - } - - /** - * The meta key has been pressed but has not yet been used. - */ - private static final int PRESSED = - Spannable.SPAN_MARK_MARK | (1 << Spannable.SPAN_USER_SHIFT); - - /** - * The meta key has been pressed and released but has still - * not yet been used. - */ - private static final int RELEASED = - Spannable.SPAN_MARK_MARK | (2 << Spannable.SPAN_USER_SHIFT); - - /** - * The meta key has been pressed and used but has not yet been released. - */ - private static final int USED = - Spannable.SPAN_MARK_MARK | (3 << Spannable.SPAN_USER_SHIFT); - - /** - * The meta key has been pressed and released without use, and then - * pressed again; it may also have been released again. - */ - private static final int LOCKED = - Spannable.SPAN_MARK_MARK | (4 << Spannable.SPAN_USER_SHIFT); -} - diff --git a/core/java/android/text/method/MovementMethod.java b/core/java/android/text/method/MovementMethod.java deleted file mode 100644 index 29f67a1..0000000 --- a/core/java/android/text/method/MovementMethod.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.widget.TextView; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.text.*; - -public interface MovementMethod -{ - public void initialize(TextView widget, Spannable text); - public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event); - public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event); - - /** - * If the key listener wants to other kinds of key events, return true, - * otherwise return false and the caller (i.e. the widget host) - * will handle the key. - */ - public boolean onKeyOther(TextView view, Spannable text, KeyEvent event); - - public void onTakeFocus(TextView widget, Spannable text, int direction); - public boolean onTrackballEvent(TextView widget, Spannable text, - MotionEvent event); - public boolean onTouchEvent(TextView widget, Spannable text, - MotionEvent event); - - /** - * Returns true if this movement method allows arbitrary selection - * of any text; false if it has no selection (like a movement method - * that only scrolls) or a constrained selection (for example - * limited to links. The "Select All" menu item is disabled - * if arbitrary selection is not allowed. - */ - public boolean canSelectArbitrarily(); -} diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java deleted file mode 100644 index 6d94788..0000000 --- a/core/java/android/text/method/MultiTapKeyListener.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.view.View; -import android.os.Handler; -import android.os.SystemClock; -import android.text.*; -import android.text.method.TextKeyListener.Capitalize; -import android.util.SparseArray; - -/** - * This is the standard key listener for alphabetic input on 12-key - * keyboards. You should generally not need to instantiate this yourself; - * TextKeyListener will do it for you. - */ -public class MultiTapKeyListener extends BaseKeyListener - implements SpanWatcher { - private static MultiTapKeyListener[] sInstance = - new MultiTapKeyListener[Capitalize.values().length * 2]; - - private static final SparseArray<String> sRecs = new SparseArray<String>(); - - private Capitalize mCapitalize; - private boolean mAutoText; - - static { - sRecs.put(KeyEvent.KEYCODE_1, ".,1!@#$%^&*:/?'=()"); - sRecs.put(KeyEvent.KEYCODE_2, "abc2ABC"); - sRecs.put(KeyEvent.KEYCODE_3, "def3DEF"); - sRecs.put(KeyEvent.KEYCODE_4, "ghi4GHI"); - sRecs.put(KeyEvent.KEYCODE_5, "jkl5JKL"); - sRecs.put(KeyEvent.KEYCODE_6, "mno6MNO"); - sRecs.put(KeyEvent.KEYCODE_7, "pqrs7PQRS"); - sRecs.put(KeyEvent.KEYCODE_8, "tuv8TUV"); - sRecs.put(KeyEvent.KEYCODE_9, "wxyz9WXYZ"); - sRecs.put(KeyEvent.KEYCODE_0, "0+"); - sRecs.put(KeyEvent.KEYCODE_POUND, " "); - }; - - public MultiTapKeyListener(Capitalize cap, - boolean autotext) { - mCapitalize = cap; - mAutoText = autotext; - } - - /** - * Returns a new or existing instance with the specified capitalization - * and correction properties. - */ - public static MultiTapKeyListener getInstance(boolean autotext, - Capitalize cap) { - int off = cap.ordinal() * 2 + (autotext ? 1 : 0); - - if (sInstance[off] == null) { - sInstance[off] = new MultiTapKeyListener(cap, autotext); - } - - return sInstance[off]; - } - - public int getInputType() { - return makeTextContentType(mCapitalize, mAutoText); - } - - 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); - Timeout t = new Timeout(content); - - return true; - } - if (Character.isUpperCase(current)) { - content.replace(selStart, selEnd, - String.valueOf(current).toLowerCase()); - removeTimeouts(content); - Timeout t = new Timeout(content); - - 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); - Timeout t = new Timeout(content); - - 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); - Timeout t = new Timeout(content); - - // 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); - } - - public void onSpanChanged(Spannable buf, - Object what, int s, int e, int start, int stop) { - if (what == Selection.SELECTION_END) { - buf.removeSpan(TextKeyListener.ACTIVE); - removeTimeouts(buf); - } - } - - private static void removeTimeouts(Spannable buf) { - Timeout[] timeout = buf.getSpans(0, buf.length(), Timeout.class); - - for (int i = 0; i < timeout.length; i++) { - Timeout t = timeout[i]; - - t.removeCallbacks(t); - t.mBuffer = null; - buf.removeSpan(t); - } - } - - private class Timeout - extends Handler - implements Runnable - { - public Timeout(Editable buffer) { - mBuffer = buffer; - mBuffer.setSpan(Timeout.this, 0, mBuffer.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - - postAtTime(this, SystemClock.uptimeMillis() + 2000); - } - - public void run() { - Spannable buf = mBuffer; - - if (buf != null) { - int st = Selection.getSelectionStart(buf); - int en = Selection.getSelectionEnd(buf); - - int start = buf.getSpanStart(TextKeyListener.ACTIVE); - int end = buf.getSpanEnd(TextKeyListener.ACTIVE); - - if (st == start && en == end) { - Selection.setSelection(buf, Selection.getSelectionEnd(buf)); - } - - buf.removeSpan(Timeout.this); - } - } - - private Editable mBuffer; - } - - public void onSpanAdded(Spannable s, Object what, int start, int end) { } - public void onSpanRemoved(Spannable s, Object what, int start, int end) { } -} - diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java deleted file mode 100644 index e500fae..0000000 --- a/core/java/android/text/method/NumberKeyListener.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.view.View; -import android.text.Editable; -import android.text.InputFilter; -import android.text.Selection; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; - -/** - * For numeric text entry - */ -public abstract class NumberKeyListener extends BaseKeyListener - implements InputFilter -{ - /** - * You can say which characters you can accept. - */ - protected abstract char[] getAcceptedChars(); - - protected int lookup(KeyEvent event, Spannable content) { - return event.getMatch(getAcceptedChars(), getMetaState(content)); - } - - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - char[] accept = getAcceptedChars(); - boolean filter = false; - - int i; - for (i = start; i < end; i++) { - if (!ok(accept, source.charAt(i))) { - break; - } - } - - if (i == end) { - // It was all OK. - return null; - } - - if (end - start == 1) { - // It was not OK, and there is only one char, so nothing remains. - return ""; - } - - SpannableStringBuilder filtered = - new SpannableStringBuilder(source, start, end); - i -= start; - end -= start; - - int len = end - start; - // Only count down to i because the chars before that were all OK. - for (int j = end - 1; j >= i; j--) { - if (!ok(accept, source.charAt(j))) { - filtered.delete(j, j + 1); - } - } - - return filtered; - } - - protected static boolean ok(char[] accept, char c) { - for (int i = accept.length - 1; i >= 0; i--) { - if (accept[i] == c) { - return true; - } - } - - return false; - } - - @Override - public boolean onKeyDown(View view, Editable content, - int keyCode, KeyEvent event) { - int selStart, selEnd; - - { - int a = Selection.getSelectionStart(content); - int b = Selection.getSelectionEnd(content); - - selStart = Math.min(a, b); - selEnd = Math.max(a, b); - } - - int i = event != null ? lookup(event, content) : 0; - int repeatCount = event != null ? event.getRepeatCount() : 0; - if (repeatCount == 0) { - if (i != 0) { - if (selStart != selEnd) { - Selection.setSelection(content, selEnd); - } - - content.replace(selStart, selEnd, String.valueOf((char) i)); - - adjustMetaAfterKeypress(content); - return true; - } - } else if (i == '0' && repeatCount == 1) { - // Pretty hackish, it replaces the 0 with the + - - if (selStart == selEnd && selEnd > 0 && - content.charAt(selStart - 1) == '0') { - content.replace(selStart - 1, selEnd, String.valueOf('+')); - adjustMetaAfterKeypress(content); - return true; - } - } - - adjustMetaAfterKeypress(content); - return super.onKeyDown(view, content, keyCode, event); - } -} diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java deleted file mode 100644 index fad4f64..0000000 --- a/core/java/android/text/method/PasswordTransformationMethod.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.os.Handler; -import android.os.SystemClock; -import android.graphics.Rect; -import android.view.View; -import android.text.Editable; -import android.text.GetChars; -import android.text.NoCopySpan; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.text.Selection; -import android.text.Spanned; -import android.text.Spannable; -import android.text.style.UpdateLayout; - -import java.lang.ref.WeakReference; - -public class PasswordTransformationMethod -implements TransformationMethod, TextWatcher -{ - public CharSequence getTransformation(CharSequence source, View view) { - if (source instanceof Spannable) { - Spannable sp = (Spannable) source; - - /* - * Remove any references to other views that may still be - * attached. This will happen when you flip the screen - * while a password field is showing; there will still - * be references to the old EditText in the text. - */ - ViewReference[] vr = sp.getSpans(0, sp.length(), - ViewReference.class); - for (int i = 0; i < vr.length; i++) { - sp.removeSpan(vr[i]); - } - - sp.setSpan(new ViewReference(view), 0, 0, - Spannable.SPAN_POINT_POINT); - } - - return new PasswordCharSequence(source); - } - - public static PasswordTransformationMethod getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new PasswordTransformationMethod(); - return sInstance; - } - - public void beforeTextChanged(CharSequence s, int start, - int count, int after) { - // This callback isn't used. - } - - public void onTextChanged(CharSequence s, int start, - int before, int count) { - if (s instanceof Spannable) { - Spannable sp = (Spannable) s; - ViewReference[] vr = sp.getSpans(0, s.length(), - ViewReference.class); - if (vr.length == 0) { - return; - } - - /* - * There should generally only be one ViewReference in the text, - * but make sure to look through all of them if necessary in case - * something strange is going on. (We might still end up with - * multiple ViewReferences if someone moves text from one password - * field to another.) - */ - View v = null; - for (int i = 0; v == null && i < vr.length; i++) { - v = vr[i].get(); - } - - if (v == null) { - return; - } - - int pref = TextKeyListener.getInstance().getPrefs(v.getContext()); - if ((pref & TextKeyListener.SHOW_PASSWORD) != 0) { - if (count > 0) { - Visible[] old = sp.getSpans(0, sp.length(), Visible.class); - for (int i = 0; i < old.length; i++) { - sp.removeSpan(old[i]); - } - - if (count == 1) { - sp.setSpan(new Visible(sp, this), start, start + count, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - } - } - } - - public void afterTextChanged(Editable s) { - // This callback isn't used. - } - - public void onFocusChanged(View view, CharSequence sourceText, - boolean focused, int direction, - Rect previouslyFocusedRect) { - if (!focused) { - if (sourceText instanceof Spannable) { - Spannable sp = (Spannable) sourceText; - - Visible[] old = sp.getSpans(0, sp.length(), Visible.class); - for (int i = 0; i < old.length; i++) { - sp.removeSpan(old[i]); - } - } - } - } - - private static class PasswordCharSequence - implements CharSequence, GetChars - { - public PasswordCharSequence(CharSequence source) { - mSource = source; - } - - public int length() { - return mSource.length(); - } - - public char charAt(int i) { - if (mSource instanceof Spanned) { - Spanned sp = (Spanned) mSource; - - int st = sp.getSpanStart(TextKeyListener.ACTIVE); - int en = sp.getSpanEnd(TextKeyListener.ACTIVE); - - if (i >= st && i < en) { - return mSource.charAt(i); - } - - Visible[] visible = sp.getSpans(0, sp.length(), Visible.class); - - for (int a = 0; a < visible.length; a++) { - if (sp.getSpanStart(visible[a].mTransformer) >= 0) { - st = sp.getSpanStart(visible[a]); - en = sp.getSpanEnd(visible[a]); - - if (i >= st && i < en) { - return mSource.charAt(i); - } - } - } - } - - return DOT; - } - - public CharSequence subSequence(int start, int end) { - char[] buf = new char[end - start]; - - getChars(start, end, buf, 0); - return new String(buf); - } - - public String toString() { - return subSequence(0, length()).toString(); - } - - public void getChars(int start, int end, char[] dest, int off) { - TextUtils.getChars(mSource, start, end, dest, off); - - int st = -1, en = -1; - int nvisible = 0; - int[] starts = null, ends = null; - - if (mSource instanceof Spanned) { - Spanned sp = (Spanned) mSource; - - st = sp.getSpanStart(TextKeyListener.ACTIVE); - en = sp.getSpanEnd(TextKeyListener.ACTIVE); - - Visible[] visible = sp.getSpans(0, sp.length(), Visible.class); - nvisible = visible.length; - starts = new int[nvisible]; - ends = new int[nvisible]; - - for (int i = 0; i < nvisible; i++) { - if (sp.getSpanStart(visible[i].mTransformer) >= 0) { - starts[i] = sp.getSpanStart(visible[i]); - ends[i] = sp.getSpanEnd(visible[i]); - } - } - } - - for (int i = start; i < end; i++) { - if (! (i >= st && i < en)) { - boolean visible = false; - - for (int a = 0; a < nvisible; a++) { - if (i >= starts[a] && i < ends[a]) { - visible = true; - break; - } - } - - if (!visible) { - dest[i - start + off] = DOT; - } - } - } - } - - private CharSequence mSource; - } - - private static class Visible - extends Handler - implements UpdateLayout, Runnable - { - public Visible(Spannable sp, PasswordTransformationMethod ptm) { - mText = sp; - mTransformer = ptm; - postAtTime(this, SystemClock.uptimeMillis() + 1500); - } - - public void run() { - mText.removeSpan(this); - } - - private Spannable mText; - private PasswordTransformationMethod mTransformer; - } - - /** - * Used to stash a reference back to the View in the Editable so we - * can use it to check the settings. - */ - private static class ViewReference extends WeakReference<View> - implements NoCopySpan { - public ViewReference(View v) { - super(v); - } - } - - private static PasswordTransformationMethod sInstance; - private static char DOT = '\u2022'; -} diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java deleted file mode 100644 index 0b39517..0000000 --- a/core/java/android/text/method/QwertyKeyListener.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.text.*; -import android.text.method.TextKeyListener.Capitalize; -import android.util.SparseArray; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.View; - -/** - * This is the standard key listener for alphabetic input on qwerty - * keyboards. You should generally not need to instantiate this yourself; - * TextKeyListener will do it for you. - */ -public class QwertyKeyListener extends BaseKeyListener { - private static QwertyKeyListener[] sInstance = - new QwertyKeyListener[Capitalize.values().length * 2]; - - public QwertyKeyListener(Capitalize cap, boolean autotext) { - mAutoCap = cap; - mAutoText = autotext; - } - - /** - * Returns a new or existing instance with the specified capitalization - * and correction properties. - */ - public static QwertyKeyListener getInstance(boolean autotext, - Capitalize cap) { - int off = cap.ordinal() * 2 + (autotext ? 1 : 0); - - if (sInstance[off] == null) { - sInstance[off] = new QwertyKeyListener(cap, autotext); - } - - return sInstance[off]; - } - - public int getInputType() { - return makeTextContentType(mAutoCap, mAutoText); - } - - 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); - - if (selStart < 0 || selEnd < 0) { - selStart = selEnd = 0; - Selection.setSelection(content, 0, 0); - } - } - - int activeStart = content.getSpanStart(TextKeyListener.ACTIVE); - int activeEnd = content.getSpanEnd(TextKeyListener.ACTIVE); - - // QWERTY keyboard normal case - - int i = event.getUnicodeChar(getMetaState(content)); - - int count = event.getRepeatCount(); - if (count > 0 && selStart == selEnd && selStart > 0) { - char c = content.charAt(selStart - 1); - - if (c == i || c == Character.toUpperCase(i) && view != null) { - if (showCharacterPicker(view, content, c, false, count)) { - resetMetaState(content); - return true; - } - } - } - - if (i == KeyCharacterMap.PICKER_DIALOG_INPUT) { - if (view != null) { - showCharacterPicker(view, content, - KeyCharacterMap.PICKER_DIALOG_INPUT, true, 1); - } - resetMetaState(content); - return true; - } - - if (i == KeyCharacterMap.HEX_INPUT) { - int start; - - if (selStart == selEnd) { - start = selEnd; - - while (start > 0 && selEnd - start < 4 && - Character.digit(content.charAt(start - 1), 16) >= 0) { - start--; - } - } else { - start = selStart; - } - - int ch = -1; - try { - String hex = TextUtils.substring(content, start, selEnd); - ch = Integer.parseInt(hex, 16); - } catch (NumberFormatException nfe) { } - - if (ch >= 0) { - selStart = start; - Selection.setSelection(content, selStart, selEnd); - i = ch; - } else { - i = 0; - } - } - - if (i != 0) { - boolean dead = false; - - if ((i & KeyCharacterMap.COMBINING_ACCENT) != 0) { - dead = true; - i = i & KeyCharacterMap.COMBINING_ACCENT_MASK; - } - - if (activeStart == selStart && activeEnd == selEnd) { - boolean replace = false; - - if (selEnd - selStart - 1 == 0) { - char accent = content.charAt(selStart); - int composed = event.getDeadChar(accent, i); - - if (composed != 0) { - i = composed; - replace = true; - } - } - - if (!replace) { - Selection.setSelection(content, selEnd); - content.removeSpan(TextKeyListener.ACTIVE); - selStart = selEnd; - } - } - - if ((pref & TextKeyListener.AUTO_CAP) != 0 && - Character.isLowerCase(i) && - TextKeyListener.shouldCap(mAutoCap, content, selStart)) { - int where = content.getSpanEnd(TextKeyListener.CAPPED); - int flags = content.getSpanFlags(TextKeyListener.CAPPED); - - if (where == selStart && (((flags >> 16) & 0xFFFF) == i)) { - content.removeSpan(TextKeyListener.CAPPED); - } else { - flags = i << 16; - i = Character.toUpperCase(i); - - if (selStart == 0) - content.setSpan(TextKeyListener.CAPPED, 0, 0, - Spannable.SPAN_MARK_MARK | flags); - else - content.setSpan(TextKeyListener.CAPPED, - selStart - 1, selStart, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | - flags); - } - } - - if (selStart != selEnd) { - Selection.setSelection(content, selEnd); - } - content.setSpan(OLD_SEL_START, selStart, selStart, - Spannable.SPAN_MARK_MARK); - - content.replace(selStart, selEnd, String.valueOf((char) i)); - - int oldStart = content.getSpanStart(OLD_SEL_START); - selEnd = Selection.getSelectionEnd(content); - - if (oldStart < selEnd) { - content.setSpan(TextKeyListener.LAST_TYPED, - oldStart, selEnd, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - - if (dead) { - Selection.setSelection(content, oldStart, selEnd); - content.setSpan(TextKeyListener.ACTIVE, oldStart, selEnd, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } - - adjustMetaAfterKeypress(content); - - // potentially do autotext replacement if the character - // that was typed was an autotext terminator - - if ((pref & TextKeyListener.AUTO_TEXT) != 0 && mAutoText && - (i == ' ' || i == '\t' || i == '\n' || - i == ',' || i == '.' || i == '!' || i == '?' || - i == '"' || Character.getType(i) == Character.END_PUNCTUATION) && - content.getSpanEnd(TextKeyListener.INHIBIT_REPLACEMENT) - != oldStart) { - int x; - - for (x = oldStart; x > 0; x--) { - char c = content.charAt(x - 1); - if (c != '\'' && !Character.isLetter(c)) { - break; - } - } - - String rep = getReplacement(content, x, oldStart, view); - - if (rep != null) { - Replaced[] repl = content.getSpans(0, content.length(), - Replaced.class); - for (int a = 0; a < repl.length; a++) - content.removeSpan(repl[a]); - - char[] orig = new char[oldStart - x]; - TextUtils.getChars(content, x, oldStart, orig, 0); - - content.setSpan(new Replaced(orig), x, oldStart, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - content.replace(x, oldStart, rep); - } - } - - // Replace two spaces by a period and a space. - - if ((pref & TextKeyListener.AUTO_PERIOD) != 0 && mAutoText) { - selEnd = Selection.getSelectionEnd(content); - if (selEnd - 3 >= 0) { - if (content.charAt(selEnd - 1) == ' ' && - content.charAt(selEnd - 2) == ' ') { - char c = content.charAt(selEnd - 3); - - for (int j = selEnd - 3; j > 0; j--) { - if (c == '"' || - Character.getType(c) == Character.END_PUNCTUATION) { - c = content.charAt(j - 1); - } else { - break; - } - } - - if (Character.isLetter(c) || Character.isDigit(c)) { - content.replace(selEnd - 2, selEnd - 1, "."); - } - } - } - } - - return true; - } else if (keyCode == KeyEvent.KEYCODE_DEL && selStart == selEnd) { - // special backspace case for undoing autotext - - int consider = 1; - - // if backspacing over the last typed character, - // it undoes the autotext prior to that character - // (unless the character typed was newline, in which - // case this behavior would be confusing) - - if (content.getSpanEnd(TextKeyListener.LAST_TYPED) == selStart) { - if (content.charAt(selStart - 1) != '\n') - consider = 2; - } - - Replaced[] repl = content.getSpans(selStart - consider, selStart, - Replaced.class); - - if (repl.length > 0) { - int st = content.getSpanStart(repl[0]); - int en = content.getSpanEnd(repl[0]); - String old = new String(repl[0].mText); - - content.removeSpan(repl[0]); - content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT, - en, en, Spannable.SPAN_POINT_POINT); - content.replace(st, en, old); - - en = content.getSpanStart(TextKeyListener.INHIBIT_REPLACEMENT); - if (en - 1 >= 0) { - content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT, - en - 1, en, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } else { - content.removeSpan(TextKeyListener.INHIBIT_REPLACEMENT); - } - - adjustMetaAfterKeypress(content); - - return true; - } - } - - return super.onKeyDown(view, content, keyCode, event); - } - - private String getReplacement(CharSequence src, int start, int end, - View view) { - int len = end - start; - boolean changecase = false; - - String replacement = AutoText.get(src, start, end, view); - - if (replacement == null) { - String key = TextUtils.substring(src, start, end).toLowerCase(); - replacement = AutoText.get(key, 0, end - start, view); - changecase = true; - - if (replacement == null) - return null; - } - - int caps = 0; - - if (changecase) { - for (int j = start; j < end; j++) { - if (Character.isUpperCase(src.charAt(j))) - caps++; - } - } - - String out; - - if (caps == 0) - out = replacement; - else if (caps == 1) - out = toTitleCase(replacement); - else if (caps == len) - out = replacement.toUpperCase(); - else - out = toTitleCase(replacement); - - if (out.length() == len && - TextUtils.regionMatches(src, start, out, 0, len)) - return null; - - return out; - } - - /** - * Marks the specified region of <code>content</code> as having - * contained <code>original</code> prior to AutoText replacement. - * Call this method when you have done or are about to do an - * AutoText-style replacement on a region of text and want to let - * the same mechanism (the user pressing DEL immediately after the - * change) undo the replacement. - * - * @param content the Editable text where the replacement was made - * @param start the start of the replaced region - * @param end the end of the replaced region; the location of the cursor - * @param original the text to be restored if the user presses DEL - */ - public static void markAsReplaced(Spannable content, int start, int end, - String original) { - Replaced[] repl = content.getSpans(0, content.length(), Replaced.class); - for (int a = 0; a < repl.length; a++) { - content.removeSpan(repl[a]); - } - - int len = original.length(); - char[] orig = new char[len]; - original.getChars(0, len, orig, 0); - - content.setSpan(new Replaced(orig), start, end, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - private static SparseArray<String> PICKER_SETS = - new SparseArray<String>(); - static { - PICKER_SETS.put('!', "\u00A1"); - PICKER_SETS.put('<', "\u00AB"); - PICKER_SETS.put('>', "\u00BB"); - PICKER_SETS.put('?', "\u00BF"); - PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5"); - PICKER_SETS.put('C', "\u00C7"); - PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB"); - PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF"); - PICKER_SETS.put('N', "\u00D1"); - PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6"); - PICKER_SETS.put('U', "\u00D9\u00DA\u00DB\u00DC"); - PICKER_SETS.put('Y', "\u00DD\u0178"); - PICKER_SETS.put('a', "\u00E0\u00E1\u00E2\u00E4\u00E6\u00E3\u00E5"); - PICKER_SETS.put('c', "\u00E7"); - PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB"); - PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF"); - PICKER_SETS.put('n', "\u00F1"); - PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6"); - PICKER_SETS.put('s', "\u00A7\u00DF"); - PICKER_SETS.put('u', "\u00F9\u00FA\u00FB\u00FC"); - PICKER_SETS.put('y', "\u00FD\u00FF"); - PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT, - "\u2026\u00A5\u2022\u00AE\u00A9\u00B1"); - }; - - private boolean showCharacterPicker(View view, Editable content, char c, - boolean insert, int count) { - String set = PICKER_SETS.get(c); - if (set == null) { - return false; - } - - if (count == 1) { - new CharacterPickerDialog(view.getContext(), - view, content, set, insert).show(); - } - - return true; - } - - private static String toTitleCase(String src) { - return Character.toUpperCase(src.charAt(0)) + src.substring(1); - } - - /* package */ static class Replaced implements NoCopySpan - { - public Replaced(char[] text) { - mText = text; - } - - private char[] mText; - } - - private Capitalize mAutoCap; - private boolean mAutoText; -} - diff --git a/core/java/android/text/method/ReplacementTransformationMethod.java b/core/java/android/text/method/ReplacementTransformationMethod.java deleted file mode 100644 index d6f879a..0000000 --- a/core/java/android/text/method/ReplacementTransformationMethod.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.graphics.Rect; -import android.text.Editable; -import android.text.GetChars; -import android.text.Spannable; -import android.text.Spanned; -import android.text.SpannedString; -import android.text.TextUtils; -import android.view.View; - -/** - * This transformation method causes the characters in the {@link #getOriginal} - * array to be replaced by the corresponding characters in the - * {@link #getReplacement} array. - */ -public abstract class ReplacementTransformationMethod -implements TransformationMethod -{ - /** - * Returns the list of characters that are to be replaced by other - * characters when displayed. - */ - protected abstract char[] getOriginal(); - /** - * Returns a parallel array of replacement characters for the ones - * that are to be replaced. - */ - protected abstract char[] getReplacement(); - - /** - * Returns a CharSequence that will mirror the contents of the - * source CharSequence but with the characters in {@link #getOriginal} - * replaced by ones from {@link #getReplacement}. - */ - public CharSequence getTransformation(CharSequence source, View v) { - char[] original = getOriginal(); - char[] replacement = getReplacement(); - - /* - * Short circuit for faster display if the text will never change. - */ - if (!(source instanceof Editable)) { - /* - * Check whether the text does not contain any of the - * source characters so can be used unchanged. - */ - boolean doNothing = true; - int n = original.length; - for (int i = 0; i < n; i++) { - if (TextUtils.indexOf(source, original[i]) >= 0) { - doNothing = false; - break; - } - } - if (doNothing) { - return source; - } - - if (!(source instanceof Spannable)) { - /* - * The text contains some of the source characters, - * but they can be flattened out now instead of - * at display time. - */ - if (source instanceof Spanned) { - return new SpannedString(new SpannedReplacementCharSequence( - (Spanned) source, - original, replacement)); - } else { - return new ReplacementCharSequence(source, - original, - replacement).toString(); - } - } - } - - if (source instanceof Spanned) { - return new SpannedReplacementCharSequence((Spanned) source, - original, replacement); - } else { - return new ReplacementCharSequence(source, original, replacement); - } - } - - public void onFocusChanged(View view, CharSequence sourceText, - boolean focused, int direction, - Rect previouslyFocusedRect) { - // This callback isn't used. - } - - private static class ReplacementCharSequence - implements CharSequence, GetChars { - private char[] mOriginal, mReplacement; - - public ReplacementCharSequence(CharSequence source, char[] original, - char[] replacement) { - mSource = source; - mOriginal = original; - mReplacement = replacement; - } - - public int length() { - return mSource.length(); - } - - public char charAt(int i) { - char c = mSource.charAt(i); - - int n = mOriginal.length; - for (int j = 0; j < n; j++) { - if (c == mOriginal[j]) { - c = mReplacement[j]; - } - } - - return c; - } - - public CharSequence subSequence(int start, int end) { - char[] c = new char[end - start]; - - getChars(start, end, c, 0); - return new String(c); - } - - public String toString() { - char[] c = new char[length()]; - - getChars(0, length(), c, 0); - return new String(c); - } - - public void getChars(int start, int end, char[] dest, int off) { - TextUtils.getChars(mSource, start, end, dest, off); - int offend = end - start + off; - int n = mOriginal.length; - - for (int i = off; i < offend; i++) { - char c = dest[i]; - - for (int j = 0; j < n; j++) { - if (c == mOriginal[j]) { - dest[i] = mReplacement[j]; - } - } - } - } - - private CharSequence mSource; - } - - private static class SpannedReplacementCharSequence - extends ReplacementCharSequence - implements Spanned - { - public SpannedReplacementCharSequence(Spanned source, char[] original, - char[] replacement) { - super(source, original, replacement); - mSpanned = source; - } - - public CharSequence subSequence(int start, int end) { - return new SpannedString(this).subSequence(start, end); - } - - public <T> T[] getSpans(int start, int end, Class<T> type) { - return mSpanned.getSpans(start, end, type); - } - - public int getSpanStart(Object tag) { - return mSpanned.getSpanStart(tag); - } - - public int getSpanEnd(Object tag) { - return mSpanned.getSpanEnd(tag); - } - - public int getSpanFlags(Object tag) { - return mSpanned.getSpanFlags(tag); - } - - public int nextSpanTransition(int start, int end, Class type) { - return mSpanned.nextSpanTransition(start, end, type); - } - - private Spanned mSpanned; - } -} diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java deleted file mode 100644 index 563ceed..0000000 --- a/core/java/android/text/method/ScrollingMovementMethod.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.text.*; -import android.widget.TextView; -import android.view.View; - -public class -ScrollingMovementMethod -implements MovementMethod -{ - /** - * Scrolls the text to the left if possible. - */ - protected boolean left(TextView widget, Spannable buffer) { - Layout layout = widget.getLayout(); - - int scrolly = widget.getScrollY(); - int scr = widget.getScrollX(); - int em = Math.round(layout.getPaint().getFontSpacing()); - - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - int top = layout.getLineForVertical(scrolly); - int bottom = layout.getLineForVertical(scrolly + widget.getHeight() - - padding); - int left = Integer.MAX_VALUE; - - for (int i = top; i <= bottom; i++) { - left = (int) Math.min(left, layout.getLineLeft(i)); - } - - if (scr > left) { - int s = Math.max(scr - em, left); - widget.scrollTo(s, widget.getScrollY()); - return true; - } - - return false; - } - - /** - * Scrolls the text to the right if possible. - */ - protected boolean right(TextView widget, Spannable buffer) { - Layout layout = widget.getLayout(); - - int scrolly = widget.getScrollY(); - int scr = widget.getScrollX(); - int em = Math.round(layout.getPaint().getFontSpacing()); - - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - int top = layout.getLineForVertical(scrolly); - int bottom = layout.getLineForVertical(scrolly + widget.getHeight() - - padding); - int right = 0; - - for (int i = top; i <= bottom; i++) { - right = (int) Math.max(right, layout.getLineRight(i)); - } - - padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); - if (scr < right - (widget.getWidth() - padding)) { - int s = Math.min(scr + em, right - (widget.getWidth() - padding)); - widget.scrollTo(s, widget.getScrollY()); - return true; - } - - return false; - } - - /** - * Scrolls the text up if possible. - */ - protected boolean up(TextView widget, Spannable buffer) { - Layout layout = widget.getLayout(); - - int areatop = widget.getScrollY(); - int line = layout.getLineForVertical(areatop); - int linetop = layout.getLineTop(line); - - // If the top line is partially visible, bring it all the way - // into view; otherwise, bring the previous line into view. - if (areatop == linetop) - line--; - - if (line >= 0) { - Touch.scrollTo(widget, layout, - widget.getScrollX(), layout.getLineTop(line)); - return true; - } - - return false; - } - - /** - * Scrolls the text down if possible. - */ - protected boolean down(TextView widget, Spannable buffer) { - Layout layout = widget.getLayout(); - - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - - int areabot = widget.getScrollY() + widget.getHeight() - padding; - int line = layout.getLineForVertical(areabot); - - if (layout.getLineTop(line+1) < areabot + 1) { - // Less than a pixel of this line is out of view, - // so we must have tried to make it entirely in view - // and now want the next line to be in view instead. - - line++; - } - - if (line <= layout.getLineCount() - 1) { - widget.scrollTo(widget.getScrollX(), layout.getLineTop(line+1) - - (widget.getHeight() - padding)); - Touch.scrollTo(widget, layout, - widget.getScrollX(), widget.getScrollY()); - return true; - } - - return false; - } - - public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { - return executeDown(widget, buffer, keyCode); - } - - private boolean executeDown(TextView widget, Spannable buffer, int keyCode) { - boolean handled = false; - - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - handled |= left(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_RIGHT: - handled |= right(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_UP: - handled |= up(widget, buffer); - break; - - case KeyEvent.KEYCODE_DPAD_DOWN: - handled |= down(widget, buffer); - break; - } - - return handled; - } - - public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { - return false; - } - - public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) { - int code = event.getKeyCode(); - if (code != KeyEvent.KEYCODE_UNKNOWN - && event.getAction() == KeyEvent.ACTION_MULTIPLE) { - int repeat = event.getRepeatCount(); - boolean first = true; - boolean handled = false; - while ((--repeat) > 0) { - if (first && executeDown(view, text, code)) { - handled = true; - MetaKeyKeyListener.adjustMetaAfterKeypress(text); - MetaKeyKeyListener.resetLockedMeta(text); - } - first = false; - } - return handled; - } - return false; - } - - public boolean onTrackballEvent(TextView widget, Spannable text, - MotionEvent event) { - return false; - } - - public boolean onTouchEvent(TextView widget, Spannable buffer, - MotionEvent event) { - return Touch.onTouchEvent(widget, buffer, event); - } - - public void initialize(TextView widget, Spannable text) { } - - public boolean canSelectArbitrarily() { - return false; - } - - public void onTakeFocus(TextView widget, Spannable text, int dir) { - Layout layout = widget.getLayout(); - - if (layout != null && (dir & View.FOCUS_FORWARD) != 0) { - widget.scrollTo(widget.getScrollX(), - layout.getLineTop(0)); - } - if (layout != null && (dir & View.FOCUS_BACKWARD) != 0) { - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - int line = layout.getLineCount() - 1; - - widget.scrollTo(widget.getScrollX(), - layout.getLineTop(line+1) - - (widget.getHeight() - padding)); - } - } - - public static MovementMethod getInstance() { - if (sInstance == null) - sInstance = new ScrollingMovementMethod(); - - return sInstance; - } - - private static ScrollingMovementMethod sInstance; -} diff --git a/core/java/android/text/method/SingleLineTransformationMethod.java b/core/java/android/text/method/SingleLineTransformationMethod.java deleted file mode 100644 index 6a05fe4..0000000 --- a/core/java/android/text/method/SingleLineTransformationMethod.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.graphics.Rect; -import android.text.Editable; -import android.text.GetChars; -import android.text.Spannable; -import android.text.Spanned; -import android.text.SpannedString; -import android.text.TextUtils; -import android.view.View; - -/** - * This transformation method causes any newline characters (\n) to be - * displayed as spaces instead of causing line breaks, and causes - * carriage return characters (\r) to have no appearance. - */ -public class SingleLineTransformationMethod -extends ReplacementTransformationMethod { - private static char[] ORIGINAL = new char[] { '\n', '\r' }; - private static char[] REPLACEMENT = new char[] { ' ', '\uFEFF' }; - - /** - * The characters to be replaced are \n and \r. - */ - protected char[] getOriginal() { - return ORIGINAL; - } - - /** - * The character \n is replaced with is space; - * the character \r is replaced with is FEFF (zero width space). - */ - protected char[] getReplacement() { - return REPLACEMENT; - } - - public static SingleLineTransformationMethod getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new SingleLineTransformationMethod(); - return sInstance; - } - - private static SingleLineTransformationMethod sInstance; -} diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java deleted file mode 100644 index 5be2a48..0000000 --- a/core/java/android/text/method/TextKeyListener.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.provider.Settings; -import android.provider.Settings.System; -import android.text.*; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.View; -import android.text.InputType; - -import java.lang.ref.WeakReference; - -/** - * This is the key listener for typing normal text. It delegates to - * other key listeners appropriate to the current keyboard and language. - */ -public class TextKeyListener extends BaseKeyListener implements SpanWatcher { - private static TextKeyListener[] sInstance = - new TextKeyListener[Capitalize.values().length * 2]; - - /* package */ static final Object ACTIVE = new NoCopySpan.Concrete(); - /* package */ static final Object CAPPED = new NoCopySpan.Concrete(); - /* package */ static final Object INHIBIT_REPLACEMENT = new NoCopySpan.Concrete(); - /* package */ static final Object LAST_TYPED = new NoCopySpan.Concrete(); - - private Capitalize mAutoCap; - private boolean mAutoText; - - private int mPrefs; - private boolean mPrefsInited; - - /* package */ static final int AUTO_CAP = 1; - /* package */ static final int AUTO_TEXT = 2; - /* package */ static final int AUTO_PERIOD = 4; - /* package */ static final int SHOW_PASSWORD = 8; - private WeakReference<ContentResolver> mResolver; - private TextKeyListener.SettingsObserver mObserver; - - /** - * Creates a new TextKeyListener with the specified capitalization - * and correction properties. - * - * @param cap when, if ever, to automatically capitalize. - * @param autotext whether to automatically do spelling corrections. - */ - public TextKeyListener(Capitalize cap, boolean autotext) { - mAutoCap = cap; - mAutoText = autotext; - } - - /** - * Returns a new or existing instance with the specified capitalization - * and correction properties. - * - * @param cap when, if ever, to automatically capitalize. - * @param autotext whether to automatically do spelling corrections. - */ - public static TextKeyListener getInstance(boolean autotext, - Capitalize cap) { - int off = cap.ordinal() * 2 + (autotext ? 1 : 0); - - if (sInstance[off] == null) { - sInstance[off] = new TextKeyListener(cap, autotext); - } - - return sInstance[off]; - } - - /** - * Returns a new or existing instance with no automatic capitalization - * or correction. - */ - public static TextKeyListener getInstance() { - return getInstance(false, Capitalize.NONE); - } - - /** - * Returns whether it makes sense to automatically capitalize at the - * specified position in the specified text, with the specified rules. - * - * @param cap the capitalization rules to consider. - * @param cs the text in which an insertion is being made. - * @param off the offset into that text where the insertion is being made. - * - * @return whether the character being inserted should be capitalized. - */ - public static boolean shouldCap(Capitalize cap, CharSequence cs, int off) { - int i; - char c; - - if (cap == Capitalize.NONE) { - return false; - } - if (cap == Capitalize.CHARACTERS) { - return true; - } - - return TextUtils.getCapsMode(cs, off, cap == Capitalize.WORDS - ? TextUtils.CAP_MODE_WORDS : TextUtils.CAP_MODE_SENTENCES) - != 0; - } - - public int getInputType() { - return makeTextContentType(mAutoCap, mAutoText); - } - - @Override - public boolean onKeyDown(View view, Editable content, - int keyCode, KeyEvent event) { - KeyListener im = getKeyListener(event); - - return im.onKeyDown(view, content, keyCode, event); - } - - @Override - public boolean onKeyUp(View view, Editable content, - int keyCode, KeyEvent event) { - KeyListener im = getKeyListener(event); - - return im.onKeyUp(view, content, keyCode, event); - } - - @Override - public boolean onKeyOther(View view, Editable content, KeyEvent event) { - KeyListener im = getKeyListener(event); - - return im.onKeyOther(view, content, event); - } - - /** - * Clear all the input state (autotext, autocap, multitap, undo) - * from the specified Editable, going beyond Editable.clear(), which - * just clears the text but not the input state. - * - * @param e the buffer whose text and state are to be cleared. - */ - public static void clear(Editable e) { - e.clear(); - e.removeSpan(ACTIVE); - e.removeSpan(CAPPED); - e.removeSpan(INHIBIT_REPLACEMENT); - e.removeSpan(LAST_TYPED); - - QwertyKeyListener.Replaced[] repl = e.getSpans(0, e.length(), - QwertyKeyListener.Replaced.class); - final int count = repl.length; - for (int i = 0; i < count; i++) { - e.removeSpan(repl[i]); - } - } - - public void onSpanAdded(Spannable s, Object what, int start, int end) { } - public void onSpanRemoved(Spannable s, Object what, int start, int end) { } - - public void onSpanChanged(Spannable s, Object what, int start, int end, - int st, int en) { - if (what == Selection.SELECTION_END) { - s.removeSpan(ACTIVE); - } - } - - private KeyListener getKeyListener(KeyEvent event) { - KeyCharacterMap kmap = KeyCharacterMap.load(event.getKeyboardDevice()); - int kind = kmap.getKeyboardType(); - - if (kind == KeyCharacterMap.ALPHA) { - return QwertyKeyListener.getInstance(mAutoText, mAutoCap); - } else if (kind == KeyCharacterMap.NUMERIC) { - return MultiTapKeyListener.getInstance(mAutoText, mAutoCap); - } - - return NullKeyListener.getInstance(); - } - - public enum Capitalize { - NONE, SENTENCES, WORDS, CHARACTERS, - } - - private static class NullKeyListener implements KeyListener - { - public int getInputType() { - return InputType.TYPE_NULL; - } - - public boolean onKeyDown(View view, Editable content, - int keyCode, KeyEvent event) { - return false; - } - - public boolean onKeyUp(View view, Editable content, int keyCode, - KeyEvent event) { - return false; - } - - public boolean onKeyOther(View view, Editable content, KeyEvent event) { - return false; - } - - public void clearMetaKeyState(View view, Editable content, int states) { - } - - public static NullKeyListener getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new NullKeyListener(); - return sInstance; - } - - private static NullKeyListener sInstance; - } - - public void release() { - if (mResolver != null) { - final ContentResolver contentResolver = mResolver.get(); - if (contentResolver != null) { - contentResolver.unregisterContentObserver(mObserver); - mResolver.clear(); - } - mObserver = null; - mResolver = null; - mPrefsInited = false; - } - } - - private void initPrefs(Context context) { - final ContentResolver contentResolver = context.getContentResolver(); - mResolver = new WeakReference<ContentResolver>(contentResolver); - mObserver = new SettingsObserver(); - contentResolver.registerContentObserver(Settings.System.CONTENT_URI, true, mObserver); - - updatePrefs(contentResolver); - mPrefsInited = true; - } - - private class SettingsObserver extends ContentObserver { - public SettingsObserver() { - super(new Handler()); - } - - @Override - public void onChange(boolean selfChange) { - if (mResolver != null) { - final ContentResolver contentResolver = mResolver.get(); - if (contentResolver == null) { - mPrefsInited = false; - } else { - updatePrefs(contentResolver); - } - } else { - mPrefsInited = false; - } - } - } - - private void updatePrefs(ContentResolver resolver) { - boolean cap = System.getInt(resolver, System.TEXT_AUTO_CAPS, 1) > 0; - boolean text = System.getInt(resolver, System.TEXT_AUTO_REPLACE, 1) > 0; - boolean period = System.getInt(resolver, System.TEXT_AUTO_PUNCTUATE, 1) > 0; - boolean pw = System.getInt(resolver, System.TEXT_SHOW_PASSWORD, 1) > 0; - - mPrefs = (cap ? AUTO_CAP : 0) | - (text ? AUTO_TEXT : 0) | - (period ? AUTO_PERIOD : 0) | - (pw ? SHOW_PASSWORD : 0); - } - - /* package */ int getPrefs(Context context) { - synchronized (this) { - if (!mPrefsInited || mResolver.get() == null) { - initPrefs(context); - } - } - - return mPrefs; - } -} diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java deleted file mode 100644 index 3fbfd8c..0000000 --- a/core/java/android/text/method/TimeKeyListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.view.KeyEvent; -import android.text.InputType; - -/** - * For entering times in a text field. - */ -public class TimeKeyListener extends NumberKeyListener -{ - public int getInputType() { - return InputType.TYPE_CLASS_DATETIME - | InputType.TYPE_DATETIME_VARIATION_TIME; - } - - @Override - protected char[] getAcceptedChars() - { - return CHARACTERS; - } - - public static TimeKeyListener getInstance() { - if (sInstance != null) - return sInstance; - - sInstance = new TimeKeyListener(); - return sInstance; - } - - /** - * The characters that are used. - * - * @see KeyEvent#getMatch - * @see #getAcceptedChars - */ - public static final char[] CHARACTERS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'm', - 'p', ':' - }; - - private static TimeKeyListener sInstance; -} diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java deleted file mode 100644 index 65036ad..0000000 --- a/core/java/android/text/method/Touch.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.text.Layout; -import android.text.NoCopySpan; -import android.text.Layout.Alignment; -import android.text.Spannable; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.widget.TextView; - -public class Touch { - private Touch() { } - - /** - * Scrolls the specified widget to the specified coordinates, except - * constrains the X scrolling position to the horizontal regions of - * the text that will be visible after scrolling to the specified - * Y position. - */ - public static void scrollTo(TextView widget, Layout layout, int x, int y) { - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - int top = layout.getLineForVertical(y); - int bottom = layout.getLineForVertical(y + widget.getHeight() - - padding); - - int left = Integer.MAX_VALUE; - int right = 0; - Alignment a = null; - - for (int i = top; i <= bottom; i++) { - left = (int) Math.min(left, layout.getLineLeft(i)); - right = (int) Math.max(right, layout.getLineRight(i)); - - if (a == null) { - a = layout.getParagraphAlignment(i); - } - } - - padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); - int width = widget.getWidth(); - int diff = 0; - - if (right - left < width - padding) { - if (a == Alignment.ALIGN_CENTER) { - diff = (width - padding - (right - left)) / 2; - } else if (a == Alignment.ALIGN_OPPOSITE) { - diff = width - padding - (right - left); - } - } - - x = Math.min(x, right - (width - padding) - diff); - x = Math.max(x, left - diff); - - widget.scrollTo(x, y); - } - - /** - * Handles touch events for dragging. You may want to do other actions - * like moving the cursor on touch as well. - */ - public static boolean onTouchEvent(TextView widget, Spannable buffer, - MotionEvent event) { - DragState[] ds; - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - buffer.setSpan(new DragState(event.getX(), event.getY()), - 0, 0, Spannable.SPAN_MARK_MARK); - return true; - - case MotionEvent.ACTION_UP: - ds = buffer.getSpans(0, buffer.length(), DragState.class); - - for (int i = 0; i < ds.length; i++) { - buffer.removeSpan(ds[i]); - } - - if (ds.length > 0 && ds[0].mUsed) { - return true; - } else { - return false; - } - - case MotionEvent.ACTION_MOVE: - ds = buffer.getSpans(0, buffer.length(), DragState.class); - - if (ds.length > 0) { - if (ds[0].mFarEnough == false) { - int slop = ViewConfiguration.get(widget.getContext()).getScaledTouchSlop(); - - if (Math.abs(event.getX() - ds[0].mX) >= slop || - Math.abs(event.getY() - ds[0].mY) >= slop) { - ds[0].mFarEnough = true; - } - } - - if (ds[0].mFarEnough) { - ds[0].mUsed = true; - - float dx = ds[0].mX - event.getX(); - float dy = ds[0].mY - event.getY(); - - ds[0].mX = event.getX(); - ds[0].mY = event.getY(); - - int nx = widget.getScrollX() + (int) dx; - int ny = widget.getScrollY() + (int) dy; - - int padding = widget.getTotalPaddingTop() + - widget.getTotalPaddingBottom(); - Layout layout = widget.getLayout(); - - ny = Math.min(ny, layout.getHeight() - (widget.getHeight() - - padding)); - ny = Math.max(ny, 0); - - scrollTo(widget, layout, nx, ny); - widget.cancelLongPress(); - return true; - } - } - } - - return false; - } - - private static class DragState implements NoCopySpan { - public float mX; - public float mY; - public boolean mFarEnough; - public boolean mUsed; - - public DragState(float x, float y) { - mX = x; - mY = y; - } - } -} diff --git a/core/java/android/text/method/TransformationMethod.java b/core/java/android/text/method/TransformationMethod.java deleted file mode 100644 index 9f51c2a..0000000 --- a/core/java/android/text/method/TransformationMethod.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.method; - -import android.graphics.Rect; -import android.view.View; -import android.widget.TextView; - -/** - * TextView uses TransformationMethods to do things like replacing the - * characters of passwords with dots, or keeping the newline characters - * from causing line breaks in single-line text fields. - */ -public interface TransformationMethod -{ - /** - * Returns a CharSequence that is a transformation of the source text -- - * for example, replacing each character with a dot in a password field. - * Beware that the returned text must be exactly the same length as - * the source text, and that if the source text is Editable, the returned - * text must mirror it dynamically instead of doing a one-time copy. - */ - public CharSequence getTransformation(CharSequence source, View view); - - /** - * This method is called when the TextView that uses this - * TransformationMethod gains or loses focus. - */ - public void onFocusChanged(View view, CharSequence sourceText, - boolean focused, int direction, - Rect previouslyFocusedRect); -} diff --git a/core/java/android/text/method/package.html b/core/java/android/text/method/package.html deleted file mode 100644 index 93698b8..0000000 --- a/core/java/android/text/method/package.html +++ /dev/null @@ -1,21 +0,0 @@ -<html> -<body> - -<p>Provides classes that monitor or modify keypad input.</p> -<p>You can use these classes to modify the type of keypad entry -for your application, or decipher the keypresses entered for your specific -entry method. For example:</p> -<pre> -// Set the text to password display style: -EditText txtView = (EditText)findViewById(R.id.text); -txtView.setTransformationMethod(PasswordTransformationMethod.getInstance()); - -//Set the input style to numbers, rather than qwerty keyboard style. -txtView.setInputMethod(DigitsInputMethod.getInstance()); - -// Find out whether the caps lock is on. -// 0 is no, 1 is yes, 2 is caps lock on. -int active = MultiTapInputMethod.getCapsActive(txtView.getText()); -</pre> -</body> -</html> diff --git a/core/java/android/text/package.html b/core/java/android/text/package.html deleted file mode 100644 index 162dcd8..0000000 --- a/core/java/android/text/package.html +++ /dev/null @@ -1,13 +0,0 @@ -<html> -<body> - -<p>Provides classes used to render or track text and text spans on the screen.</p> -<p>You can use these classes to design your own widgets that manage text, -to handle arbitrary text spans for changes, or to handle drawing yourself -for an existing widget.</p> -<p>The Span… interfaces and classes are used to create or manage spans of -text in a View item. You can use these to style the text or background, or to -listen for changes. If creating your own widget, extend DynamicLayout, to manages -the actual wrapping and drawing of your text. -</body> -</html> diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java deleted file mode 100644 index 484f8ce..0000000 --- a/core/java/android/text/style/AbsoluteSizeSpan.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan { - - private final int mSize; - - public AbsoluteSizeSpan(int size) { - mSize = size; - } - - public AbsoluteSizeSpan(Parcel src) { - mSize = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.ABSOLUTE_SIZE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mSize); - } - - public int getSize() { - return mSize; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setTextSize(mSize); - } - - @Override - public void updateMeasureState(TextPaint ds) { - ds.setTextSize(mSize); - } -} diff --git a/core/java/android/text/style/AlignmentSpan.java b/core/java/android/text/style/AlignmentSpan.java deleted file mode 100644 index b8a37da..0000000 --- a/core/java/android/text/style/AlignmentSpan.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.Layout; -import android.text.ParcelableSpan; -import android.text.TextUtils; - -public interface AlignmentSpan extends ParagraphStyle { - public Layout.Alignment getAlignment(); - - public static class Standard - implements AlignmentSpan, ParcelableSpan { - public Standard(Layout.Alignment align) { - mAlignment = align; - } - - public Standard(Parcel src) { - mAlignment = Layout.Alignment.valueOf(src.readString()); - } - - public int getSpanTypeId() { - return TextUtils.ALIGNMENT_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mAlignment.name()); - } - - public Layout.Alignment getAlignment() { - return mAlignment; - } - - private final Layout.Alignment mAlignment; - } -} diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java deleted file mode 100644 index 580a369..0000000 --- a/core/java/android/text/style/BackgroundColorSpan.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class BackgroundColorSpan extends CharacterStyle - implements UpdateAppearance, ParcelableSpan { - - private final int mColor; - - public BackgroundColorSpan(int color) { - mColor = color; - } - - public BackgroundColorSpan(Parcel src) { - mColor = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.BACKGROUND_COLOR_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mColor); - } - - public int getBackgroundColor() { - return mColor; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.bgColor = mColor; - } -} diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java deleted file mode 100644 index 655bd81..0000000 --- a/core/java/android/text/style/BulletSpan.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.os.Parcel; -import android.text.Layout; -import android.text.ParcelableSpan; -import android.text.Spanned; -import android.text.TextUtils; - -public class BulletSpan implements LeadingMarginSpan, ParcelableSpan { - private final int mGapWidth; - private final boolean mWantColor; - private final int mColor; - - private static final int BULLET_RADIUS = 3; - public static final int STANDARD_GAP_WIDTH = 2; - - public BulletSpan() { - mGapWidth = STANDARD_GAP_WIDTH; - mWantColor = false; - mColor = 0; - } - - public BulletSpan(int gapWidth) { - mGapWidth = gapWidth; - mWantColor = false; - mColor = 0; - } - - public BulletSpan(int gapWidth, int color) { - mGapWidth = gapWidth; - mWantColor = true; - mColor = color; - } - - public BulletSpan(Parcel src) { - mGapWidth = src.readInt(); - mWantColor = src.readInt() != 0; - mColor = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.BULLET_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mGapWidth); - dest.writeInt(mWantColor ? 1 : 0); - dest.writeInt(mColor); - } - - public int getLeadingMargin(boolean first) { - return 2 * BULLET_RADIUS + mGapWidth; - } - - public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - boolean first, Layout l) { - if (((Spanned) text).getSpanStart(this) == start) { - Paint.Style style = p.getStyle(); - int oldcolor = 0; - - if (mWantColor) { - oldcolor = p.getColor(); - p.setColor(mColor); - } - - p.setStyle(Paint.Style.FILL); - - c.drawCircle(x + dir * BULLET_RADIUS, (top + bottom) / 2.0f, - BULLET_RADIUS, p); - - if (mWantColor) { - p.setColor(oldcolor); - } - - p.setStyle(style); - } - } -} diff --git a/core/java/android/text/style/CharacterStyle.java b/core/java/android/text/style/CharacterStyle.java deleted file mode 100644 index 14dfddd..0000000 --- a/core/java/android/text/style/CharacterStyle.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.text.TextPaint; - -/** - * The classes that affect character-level text formatting extend this - * class. Most extend its subclass {@link MetricAffectingSpan}, but simple - * ones may just implement {@link UpdateAppearance}. - */ -public abstract class CharacterStyle { - public abstract void updateDrawState(TextPaint tp); - - /** - * A given CharacterStyle can only applied to a single region of a given - * Spanned. If you need to attach the same CharacterStyle to multiple - * regions, you can use this method to wrap it with a new object that - * will have the same effect but be a distinct object so that it can - * also be attached without conflict. - */ - public static CharacterStyle wrap(CharacterStyle cs) { - if (cs instanceof MetricAffectingSpan) { - return new MetricAffectingSpan.Passthrough((MetricAffectingSpan) cs); - } else { - return new Passthrough(cs); - } - } - - /** - * Returns "this" for most CharacterStyles, but for CharacterStyles - * that were generated by {@link #wrap}, returns the underlying - * CharacterStyle. - */ - public CharacterStyle getUnderlying() { - return this; - } - - /** - * A Passthrough CharacterStyle is one that - * passes {@link #updateDrawState} calls through to the - * specified CharacterStyle while still being a distinct object, - * and is therefore able to be attached to the same Spannable - * to which the specified CharacterStyle is already attached. - */ - private static class Passthrough extends CharacterStyle { - private CharacterStyle mStyle; - - /** - * Creates a new Passthrough of the specfied CharacterStyle. - */ - public Passthrough(CharacterStyle cs) { - mStyle = cs; - } - - /** - * Passes updateDrawState through to the underlying CharacterStyle. - */ - @Override - public void updateDrawState(TextPaint tp) { - mStyle.updateDrawState(tp); - } - - /** - * Returns the CharacterStyle underlying this one, or the one - * underlying it if it too is a Passthrough. - */ - @Override - public CharacterStyle getUnderlying() { - return mStyle.getUnderlying(); - } - } -} diff --git a/core/java/android/text/style/ClickableSpan.java b/core/java/android/text/style/ClickableSpan.java deleted file mode 100644 index 989ef54..0000000 --- a/core/java/android/text/style/ClickableSpan.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.text.TextPaint; -import android.view.View; - -/** - * If an object of this type is attached to the text of a TextView - * with a movement method of LinkMovementMethod, the affected spans of - * text can be selected. If clicked, the {@link #onClick} method will - * be called. - */ -public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance { - - /** - * Performs the click action associated with this span. - */ - public abstract void onClick(View widget); - - /** - * Makes the text underlined and in the link color. - */ - @Override - public void updateDrawState(TextPaint ds) { - ds.setColor(ds.linkColor); - ds.setUnderlineText(true); - } -} diff --git a/core/java/android/text/style/DrawableMarginSpan.java b/core/java/android/text/style/DrawableMarginSpan.java deleted file mode 100644 index 3c471a5..0000000 --- a/core/java/android/text/style/DrawableMarginSpan.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.drawable.Drawable; -import android.graphics.Paint; -import android.graphics.Canvas; -import android.graphics.RectF; -import android.text.Spanned; -import android.text.Layout; - -public class DrawableMarginSpan -implements LeadingMarginSpan, LineHeightSpan -{ - public DrawableMarginSpan(Drawable b) { - mDrawable = b; - } - - public DrawableMarginSpan(Drawable b, int pad) { - mDrawable = b; - mPad = pad; - } - - public int getLeadingMargin(boolean first) { - return mDrawable.getIntrinsicWidth() + mPad; - } - - public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - boolean first, Layout layout) { - int st = ((Spanned) text).getSpanStart(this); - int ix = (int)x; - int itop = (int)layout.getLineTop(layout.getLineForOffset(st)); - - int dw = mDrawable.getIntrinsicWidth(); - int dh = mDrawable.getIntrinsicHeight(); - - if (dir < 0) - x -= dw; - - // XXX What to do about Paint? - mDrawable.setBounds(ix, itop, ix+dw, itop+dh); - mDrawable.draw(c); - } - - public void chooseHeight(CharSequence text, int start, int end, - int istartv, int v, - Paint.FontMetricsInt fm) { - if (end == ((Spanned) text).getSpanEnd(this)) { - int ht = mDrawable.getIntrinsicHeight(); - - int need = ht - (v + fm.descent - fm.ascent - istartv); - if (need > 0) - fm.descent += need; - - need = ht - (v + fm.bottom - fm.top - istartv); - if (need > 0) - fm.bottom += need; - } - } - - private Drawable mDrawable; - private int mPad; -} diff --git a/core/java/android/text/style/DynamicDrawableSpan.java b/core/java/android/text/style/DynamicDrawableSpan.java deleted file mode 100644 index 89dc45b..0000000 --- a/core/java/android/text/style/DynamicDrawableSpan.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.Paint.Style; -import android.graphics.drawable.Drawable; -import android.util.Log; - -import java.lang.ref.WeakReference; - -/** - * - */ -public abstract class DynamicDrawableSpan extends ReplacementSpan { - private static final String TAG = "DynamicDrawableSpan"; - - /** - * A constant indicating that the bottom of this span should be aligned - * with the bottom of the surrounding text, i.e., at the same level as the - * lowest descender in the text. - */ - public static final int ALIGN_BOTTOM = 0; - - /** - * A constant indicating that the bottom of this span should be aligned - * with the baseline of the surrounding text. - */ - public static final int ALIGN_BASELINE = 1; - - protected final int mVerticalAlignment; - - public DynamicDrawableSpan() { - mVerticalAlignment = ALIGN_BOTTOM; - } - - /** - * @param verticalAlignment one of {@link #ALIGN_BOTTOM} or {@link #ALIGN_BASELINE}. - */ - protected DynamicDrawableSpan(int verticalAlignment) { - mVerticalAlignment = verticalAlignment; - } - - /** - * Returns the vertical alignment of this span, one of {@link #ALIGN_BOTTOM} or - * {@link #ALIGN_BASELINE}. - */ - public int getVerticalAlignment() { - return mVerticalAlignment; - } - - /** - * Your subclass must implement this method to provide the bitmap - * to be drawn. The dimensions of the bitmap must be the same - * from each call to the next. - */ - public abstract Drawable getDrawable(); - - @Override - public int getSize(Paint paint, CharSequence text, - int start, int end, - Paint.FontMetricsInt fm) { - Drawable d = getCachedDrawable(); - Rect rect = d.getBounds(); - - if (fm != null) { - fm.ascent = -rect.bottom; - fm.descent = 0; - - fm.top = fm.ascent; - fm.bottom = 0; - } - - return rect.right; - } - - @Override - public void draw(Canvas canvas, CharSequence text, - int start, int end, float x, - int top, int y, int bottom, Paint paint) { - Drawable b = getCachedDrawable(); - canvas.save(); - - int transY = bottom - b.getBounds().bottom; - if (mVerticalAlignment == ALIGN_BASELINE) { - transY -= paint.getFontMetricsInt().descent; - } - - canvas.translate(x, transY); - b.draw(canvas); - canvas.restore(); - } - - private Drawable getCachedDrawable() { - WeakReference<Drawable> wr = mDrawableRef; - Drawable d = null; - - if (wr != null) - d = wr.get(); - - if (d == null) { - d = getDrawable(); - mDrawableRef = new WeakReference<Drawable>(d); - } - - return d; - } - - private WeakReference<Drawable> mDrawableRef; -} - diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java deleted file mode 100644 index 476124d..0000000 --- a/core/java/android/text/style/ForegroundColorSpan.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class ForegroundColorSpan extends CharacterStyle - implements UpdateAppearance, ParcelableSpan { - - private final int mColor; - - public ForegroundColorSpan(int color) { - mColor = color; - } - - public ForegroundColorSpan(Parcel src) { - mColor = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.FOREGROUND_COLOR_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mColor); - } - - public int getForegroundColor() { - return mColor; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setColor(mColor); - } -} diff --git a/core/java/android/text/style/IconMarginSpan.java b/core/java/android/text/style/IconMarginSpan.java deleted file mode 100644 index c786a17..0000000 --- a/core/java/android/text/style/IconMarginSpan.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.RectF; -import android.text.Spanned; -import android.text.Layout; - -public class IconMarginSpan -implements LeadingMarginSpan, LineHeightSpan -{ - public IconMarginSpan(Bitmap b) { - mBitmap = b; - } - - public IconMarginSpan(Bitmap b, int pad) { - mBitmap = b; - mPad = pad; - } - - public int getLeadingMargin(boolean first) { - return mBitmap.getWidth() + mPad; - } - - public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - boolean first, Layout layout) { - int st = ((Spanned) text).getSpanStart(this); - int itop = layout.getLineTop(layout.getLineForOffset(st)); - - if (dir < 0) - x -= mBitmap.getWidth(); - - c.drawBitmap(mBitmap, x, itop, p); - } - - public void chooseHeight(CharSequence text, int start, int end, - int istartv, int v, - Paint.FontMetricsInt fm) { - if (end == ((Spanned) text).getSpanEnd(this)) { - int ht = mBitmap.getHeight(); - - int need = ht - (v + fm.descent - fm.ascent - istartv); - if (need > 0) - fm.descent += need; - - need = ht - (v + fm.bottom - fm.top - istartv); - if (need > 0) - fm.bottom += need; - } - } - - private Bitmap mBitmap; - private int mPad; -} diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java deleted file mode 100644 index efb88a0..0000000 --- a/core/java/android/text/style/ImageSpan.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.util.Log; - -import java.io.InputStream; - -public class ImageSpan extends DynamicDrawableSpan { - private Drawable mDrawable; - private Uri mContentUri; - private int mResourceId; - private Context mContext; - private String mSource; - - public ImageSpan(Bitmap b) { - this(b, ALIGN_BOTTOM); - } - - /** - * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or - * {@link DynamicDrawableSpan#ALIGN_BASELINE}. - */ - public ImageSpan(Bitmap b, int verticalAlignment) { - super(verticalAlignment); - mDrawable = new BitmapDrawable(b); - int width = mDrawable.getIntrinsicWidth(); - int height = mDrawable.getIntrinsicHeight(); - mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0); - } - - public ImageSpan(Drawable d) { - this(d, ALIGN_BOTTOM); - } - - /** - * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or - * {@link DynamicDrawableSpan#ALIGN_BASELINE}. - */ - public ImageSpan(Drawable d, int verticalAlignment) { - super(verticalAlignment); - mDrawable = d; - } - - public ImageSpan(Drawable d, String source) { - this(d, source, ALIGN_BOTTOM); - } - - /** - * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or - * {@link DynamicDrawableSpan#ALIGN_BASELINE}. - */ - public ImageSpan(Drawable d, String source, int verticalAlignment) { - super(verticalAlignment); - mDrawable = d; - mSource = source; - } - - public ImageSpan(Context context, Uri uri) { - this(context, uri, ALIGN_BOTTOM); - } - - /** - * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or - * {@link DynamicDrawableSpan#ALIGN_BASELINE}. - */ - public ImageSpan(Context context, Uri uri, int verticalAlignment) { - super(verticalAlignment); - mContext = context; - mContentUri = uri; - } - - public ImageSpan(Context context, int resourceId) { - this(context, resourceId, ALIGN_BOTTOM); - } - - /** - * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or - * {@link DynamicDrawableSpan#ALIGN_BASELINE}. - */ - public ImageSpan(Context context, int resourceId, int verticalAlignment) { - super(verticalAlignment); - mContext = context; - mResourceId = resourceId; - } - - @Override - public Drawable getDrawable() { - Drawable drawable = null; - - if (mDrawable != null) { - drawable = mDrawable; - } else if (mContentUri != null) { - Bitmap bitmap = null; - try { - InputStream is = mContext.getContentResolver().openInputStream( - mContentUri); - bitmap = BitmapFactory.decodeStream(is); - drawable = new BitmapDrawable(bitmap); - is.close(); - } catch (Exception e) { - Log.e("sms", "Failed to loaded content " + mContentUri, e); - } - } else { - try { - drawable = mContext.getResources().getDrawable(mResourceId); - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight()); - } catch (Exception e) { - Log.e("sms", "Unable to find resource: " + mResourceId); - } - } - - return drawable; - } - - /** - * Returns the source string that was saved during construction. - */ - public String getSource() { - return mSource; - } - -} diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java deleted file mode 100644 index 8e212e3..0000000 --- a/core/java/android/text/style/LeadingMarginSpan.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Canvas; -import android.os.Parcel; -import android.text.Layout; -import android.text.ParcelableSpan; -import android.text.TextUtils; - -public interface LeadingMarginSpan -extends ParagraphStyle -{ - public int getLeadingMargin(boolean first); - public void drawLeadingMargin(Canvas c, Paint p, - int x, int dir, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - boolean first, Layout layout); - - public static class Standard implements LeadingMarginSpan, ParcelableSpan { - private final int mFirst, mRest; - - public Standard(int first, int rest) { - mFirst = first; - mRest = rest; - } - - public Standard(int every) { - this(every, every); - } - - public Standard(Parcel src) { - mFirst = src.readInt(); - mRest = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.LEADING_MARGIN_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mFirst); - dest.writeInt(mRest); - } - - public int getLeadingMargin(boolean first) { - return first ? mFirst : mRest; - } - - public void drawLeadingMargin(Canvas c, Paint p, - int x, int dir, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - boolean first, Layout layout) { - ; - } - } -} diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java deleted file mode 100644 index 854aeaf..0000000 --- a/core/java/android/text/style/LineBackgroundSpan.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Canvas; - -public interface LineBackgroundSpan -extends ParagraphStyle -{ - public void drawBackground(Canvas c, Paint p, - int left, int right, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - int lnum); -} diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java deleted file mode 100644 index c0ef97c..0000000 --- a/core/java/android/text/style/LineHeightSpan.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Canvas; -import android.text.Layout; - -public interface LineHeightSpan -extends ParagraphStyle, WrapTogetherSpan -{ - public void chooseHeight(CharSequence text, int start, int end, - int spanstartv, int v, - Paint.FontMetricsInt fm); -} diff --git a/core/java/android/text/style/MaskFilterSpan.java b/core/java/android/text/style/MaskFilterSpan.java deleted file mode 100644 index 64ab0d8..0000000 --- a/core/java/android/text/style/MaskFilterSpan.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.MaskFilter; -import android.text.TextPaint; - -public class MaskFilterSpan extends CharacterStyle implements UpdateAppearance { - - private MaskFilter mFilter; - - public MaskFilterSpan(MaskFilter filter) { - mFilter = filter; - } - - public MaskFilter getMaskFilter() { - return mFilter; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setMaskFilter(mFilter); - } -} diff --git a/core/java/android/text/style/MetricAffectingSpan.java b/core/java/android/text/style/MetricAffectingSpan.java deleted file mode 100644 index 92558eb..0000000 --- a/core/java/android/text/style/MetricAffectingSpan.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.text.TextPaint; - -/** - * The classes that affect character-level text formatting in a way that - * changes the width or height of characters extend this class. - */ -public abstract class MetricAffectingSpan -extends CharacterStyle -implements UpdateLayout { - - public abstract void updateMeasureState(TextPaint p); - - /** - * Returns "this" for most MetricAffectingSpans, but for - * MetricAffectingSpans that were generated by {@link #wrap}, - * returns the underlying MetricAffectingSpan. - */ - @Override - public MetricAffectingSpan getUnderlying() { - return this; - } - - /** - * A Passthrough MetricAffectingSpan is one that - * passes {@link #updateDrawState} and {@link #updateMeasureState} - * calls through to the specified MetricAffectingSpan - * while still being a distinct object, - * and is therefore able to be attached to the same Spannable - * to which the specified MetricAffectingSpan is already attached. - */ - /* package */ static class Passthrough extends MetricAffectingSpan { - private MetricAffectingSpan mStyle; - - /** - * Creates a new Passthrough of the specfied MetricAffectingSpan. - */ - public Passthrough(MetricAffectingSpan cs) { - mStyle = cs; - } - - /** - * Passes updateDrawState through to the underlying MetricAffectingSpan. - */ - @Override - public void updateDrawState(TextPaint tp) { - mStyle.updateDrawState(tp); - } - - /** - * Passes updateMeasureState through to the underlying MetricAffectingSpan. - */ - @Override - public void updateMeasureState(TextPaint tp) { - mStyle.updateMeasureState(tp); - } - - /** - * Returns the MetricAffectingSpan underlying this one, or the one - * underlying it if it too is a Passthrough. - */ - @Override - public MetricAffectingSpan getUnderlying() { - return mStyle.getUnderlying(); - } - } -} diff --git a/core/java/android/text/style/ParagraphStyle.java b/core/java/android/text/style/ParagraphStyle.java deleted file mode 100644 index 423156e..0000000 --- a/core/java/android/text/style/ParagraphStyle.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -/** - * The classes that affect paragraph-level text formatting implement - * this interface. - */ -public interface ParagraphStyle -{ - -} diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java deleted file mode 100644 index 29dd273..0000000 --- a/core/java/android/text/style/QuoteSpan.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Canvas; -import android.os.Parcel; -import android.text.Layout; -import android.text.ParcelableSpan; -import android.text.TextUtils; - -public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan { - private static final int STRIPE_WIDTH = 2; - private static final int GAP_WIDTH = 2; - - private final int mColor; - - public QuoteSpan() { - super(); - mColor = 0xff0000ff; - } - - public QuoteSpan(int color) { - super(); - mColor = color; - } - - public QuoteSpan(Parcel src) { - mColor = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.QUOTE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mColor); - } - - public int getColor() { - return mColor; - } - - public int getLeadingMargin(boolean first) { - return STRIPE_WIDTH + GAP_WIDTH; - } - - public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, - int top, int baseline, int bottom, - CharSequence text, int start, int end, - boolean first, Layout layout) { - Paint.Style style = p.getStyle(); - int color = p.getColor(); - - p.setStyle(Paint.Style.FILL); - p.setColor(mColor); - - c.drawRect(x, top, x + dir * STRIPE_WIDTH, bottom, p); - - p.setStyle(style); - p.setColor(color); - } -} diff --git a/core/java/android/text/style/RasterizerSpan.java b/core/java/android/text/style/RasterizerSpan.java deleted file mode 100644 index 75b5bcc..0000000 --- a/core/java/android/text/style/RasterizerSpan.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Rasterizer; -import android.text.TextPaint; - -public class RasterizerSpan extends CharacterStyle implements UpdateAppearance { - - private Rasterizer mRasterizer; - - public RasterizerSpan(Rasterizer r) { - mRasterizer = r; - } - - public Rasterizer getRasterizer() { - return mRasterizer; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setRasterizer(mRasterizer); - } -} diff --git a/core/java/android/text/style/RelativeSizeSpan.java b/core/java/android/text/style/RelativeSizeSpan.java deleted file mode 100644 index 9717362..0000000 --- a/core/java/android/text/style/RelativeSizeSpan.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableSpan { - - private final float mProportion; - - public RelativeSizeSpan(float proportion) { - mProportion = proportion; - } - - public RelativeSizeSpan(Parcel src) { - mProportion = src.readFloat(); - } - - public int getSpanTypeId() { - return TextUtils.RELATIVE_SIZE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeFloat(mProportion); - } - - public float getSizeChange() { - return mProportion; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setTextSize(ds.getTextSize() * mProportion); - } - - @Override - public void updateMeasureState(TextPaint ds) { - ds.setTextSize(ds.getTextSize() * mProportion); - } -} diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java deleted file mode 100644 index 26c725f..0000000 --- a/core/java/android/text/style/ReplacementSpan.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Canvas; -import android.text.TextPaint; - -public abstract class ReplacementSpan extends MetricAffectingSpan { - - public abstract int getSize(Paint paint, CharSequence text, - int start, int end, - Paint.FontMetricsInt fm); - public abstract void draw(Canvas canvas, CharSequence text, - int start, int end, float x, - int top, int y, int bottom, Paint paint); - - /** - * This method does nothing, since ReplacementSpans are measured - * explicitly instead of affecting Paint properties. - */ - public void updateMeasureState(TextPaint p) { } - - /** - * This method does nothing, since ReplacementSpans are drawn - * explicitly instead of affecting Paint properties. - */ - public void updateDrawState(TextPaint ds) { } -} diff --git a/core/java/android/text/style/ScaleXSpan.java b/core/java/android/text/style/ScaleXSpan.java deleted file mode 100644 index 655064b..0000000 --- a/core/java/android/text/style/ScaleXSpan.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan { - - private final float mProportion; - - public ScaleXSpan(float proportion) { - mProportion = proportion; - } - - public ScaleXSpan(Parcel src) { - mProportion = src.readFloat(); - } - - public int getSpanTypeId() { - return TextUtils.SCALE_X_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeFloat(mProportion); - } - - public float getScaleX() { - return mProportion; - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setTextScaleX(ds.getTextScaleX() * mProportion); - } - - @Override - public void updateMeasureState(TextPaint ds) { - ds.setTextScaleX(ds.getTextScaleX() * mProportion); - } -} diff --git a/core/java/android/text/style/StrikethroughSpan.java b/core/java/android/text/style/StrikethroughSpan.java deleted file mode 100644 index b51363a..0000000 --- a/core/java/android/text/style/StrikethroughSpan.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class StrikethroughSpan extends CharacterStyle - implements UpdateAppearance, ParcelableSpan { - public StrikethroughSpan() { - } - - public StrikethroughSpan(Parcel src) { - } - - public int getSpanTypeId() { - return TextUtils.STRIKETHROUGH_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setStrikeThruText(true); - } -} diff --git a/core/java/android/text/style/StyleSpan.java b/core/java/android/text/style/StyleSpan.java deleted file mode 100644 index 8e6147c..0000000 --- a/core/java/android/text/style/StyleSpan.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Typeface; -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -/** - * - * Describes a style in a span. - * Note that styles are cumulative -- if both bold and italic are set in - * separate spans, or if the base style is bold and a span calls for italic, - * you get bold italic. You can't turn off a style from the base style. - * - */ -public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { - - private final int mStyle; - - /** - * - * @param style An integer constant describing the style for this span. Examples - * include bold, italic, and normal. Values are constants defined - * in {@link android.graphics.Typeface}. - */ - public StyleSpan(int style) { - mStyle = style; - } - - public StyleSpan(Parcel src) { - mStyle = src.readInt(); - } - - public int getSpanTypeId() { - return TextUtils.STYLE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mStyle); - } - - /** - * Returns the style constant defined in {@link android.graphics.Typeface}. - */ - public int getStyle() { - return mStyle; - } - - @Override - public void updateDrawState(TextPaint ds) { - apply(ds, mStyle); - } - - @Override - public void updateMeasureState(TextPaint paint) { - apply(paint, mStyle); - } - - private static void apply(Paint paint, int style) { - int oldStyle; - - Typeface old = paint.getTypeface(); - if (old == null) { - oldStyle = 0; - } else { - oldStyle = old.getStyle(); - } - - int want = oldStyle | style; - - Typeface tf; - if (old == null) { - tf = Typeface.defaultFromStyle(want); - } else { - tf = Typeface.create(old, want); - } - - int fake = want & ~tf.getStyle(); - - if ((fake & Typeface.BOLD) != 0) { - paint.setFakeBoldText(true); - } - - if ((fake & Typeface.ITALIC) != 0) { - paint.setTextSkewX(-0.25f); - } - - paint.setTypeface(tf); - } -} diff --git a/core/java/android/text/style/SubscriptSpan.java b/core/java/android/text/style/SubscriptSpan.java deleted file mode 100644 index de1d8b2..0000000 --- a/core/java/android/text/style/SubscriptSpan.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan { - public SubscriptSpan() { - } - - public SubscriptSpan(Parcel src) { - } - - public int getSpanTypeId() { - return TextUtils.SUBSCRIPT_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - } - - @Override - public void updateDrawState(TextPaint tp) { - tp.baselineShift -= (int) (tp.ascent() / 2); - } - - @Override - public void updateMeasureState(TextPaint tp) { - tp.baselineShift -= (int) (tp.ascent() / 2); - } -} diff --git a/core/java/android/text/style/SuperscriptSpan.java b/core/java/android/text/style/SuperscriptSpan.java deleted file mode 100644 index 285fe84..0000000 --- a/core/java/android/text/style/SuperscriptSpan.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSpan { - public SuperscriptSpan() { - } - - public SuperscriptSpan(Parcel src) { - } - - public int getSpanTypeId() { - return TextUtils.SUPERSCRIPT_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - } - - @Override - public void updateDrawState(TextPaint tp) { - tp.baselineShift += (int) (tp.ascent() / 2); - } - - @Override - public void updateMeasureState(TextPaint tp) { - tp.baselineShift += (int) (tp.ascent() / 2); - } -} diff --git a/core/java/android/text/style/TabStopSpan.java b/core/java/android/text/style/TabStopSpan.java deleted file mode 100644 index e5b7644..0000000 --- a/core/java/android/text/style/TabStopSpan.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -public interface TabStopSpan -extends ParagraphStyle -{ - public int getTabStop(); - - public static class Standard - implements TabStopSpan - { - public Standard(int where) { - mTab = where; - } - - public int getTabStop() { - return mTab; - } - - private int mTab; - } -} diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java deleted file mode 100644 index de929e3..0000000 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.Typeface; -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -/** - * Sets the text color, size, style, and typeface to match a TextAppearance - * resource. - */ -public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan { - private final String mTypeface; - private final int mStyle; - private final int mTextSize; - private final ColorStateList mTextColor; - private final ColorStateList mTextColorLink; - - /** - * Uses the specified TextAppearance resource to determine the - * text appearance. The <code>appearance</code> should be, for example, - * <code>android.R.style.TextAppearance_Small</code>. - */ - public TextAppearanceSpan(Context context, int appearance) { - this(context, appearance, -1); - } - - /** - * Uses the specified TextAppearance resource to determine the - * text appearance, and the specified text color resource - * to determine the color. The <code>appearance</code> should be, - * for example, <code>android.R.style.TextAppearance_Small</code>, - * and the <code>colorList</code> should be, for example, - * <code>android.R.styleable.Theme_textColorDim</code>. - */ - public TextAppearanceSpan(Context context, int appearance, - int colorList) { - ColorStateList textColor; - - TypedArray a = - context.obtainStyledAttributes(appearance, - com.android.internal.R.styleable.TextAppearance); - - textColor = a.getColorStateList(com.android.internal.R.styleable. - TextAppearance_textColor); - mTextColorLink = a.getColorStateList(com.android.internal.R.styleable. - TextAppearance_textColorLink); - mTextSize = a.getDimensionPixelSize(com.android.internal.R.styleable. - TextAppearance_textSize, -1); - - mStyle = a.getInt(com.android.internal.R.styleable.TextAppearance_textStyle, 0); - int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0); - - switch (tf) { - case 1: - mTypeface = "sans"; - break; - - case 2: - mTypeface = "serif"; - break; - - case 3: - mTypeface = "monospace"; - break; - - default: - mTypeface = null; - break; - } - - a.recycle(); - - if (colorList >= 0) { - a = context.obtainStyledAttributes(com.android.internal.R.style.Theme, - com.android.internal.R.styleable.Theme); - - textColor = a.getColorStateList(colorList); - a.recycle(); - } - - mTextColor = textColor; - } - - /** - * Makes text be drawn with the specified typeface, size, style, - * and colors. - */ - public TextAppearanceSpan(String family, int style, int size, - ColorStateList color, ColorStateList linkColor) { - mTypeface = family; - mStyle = style; - mTextSize = size; - mTextColor = color; - mTextColorLink = linkColor; - } - - public TextAppearanceSpan(Parcel src) { - mTypeface = src.readString(); - mStyle = src.readInt(); - mTextSize = src.readInt(); - if (src.readInt() != 0) { - mTextColor = ColorStateList.CREATOR.createFromParcel(src); - } else { - mTextColor = null; - } - if (src.readInt() != 0) { - mTextColorLink = ColorStateList.CREATOR.createFromParcel(src); - } else { - mTextColorLink = null; - } - } - - public int getSpanTypeId() { - return TextUtils.TEXT_APPEARANCE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mTypeface); - dest.writeInt(mStyle); - dest.writeInt(mTextSize); - if (mTextColor != null) { - dest.writeInt(1); - mTextColor.writeToParcel(dest, flags); - } else { - dest.writeInt(0); - } - if (mTextColorLink != null) { - dest.writeInt(1); - mTextColorLink.writeToParcel(dest, flags); - } else { - dest.writeInt(0); - } - } - - /** - * Returns the typeface family specified by this span, or <code>null</code> - * if it does not specify one. - */ - public String getFamily() { - return mTypeface; - } - - /** - * Returns the text color specified by this span, or <code>null</code> - * if it does not specify one. - */ - public ColorStateList getTextColor() { - return mTextColor; - } - - /** - * Returns the link color specified by this span, or <code>null</code> - * if it does not specify one. - */ - public ColorStateList getLinkTextColor() { - return mTextColorLink; - } - - /** - * Returns the text size specified by this span, or <code>-1</code> - * if it does not specify one. - */ - public int getTextSize() { - return mTextSize; - } - - /** - * Returns the text style specified by this span, or <code>0</code> - * if it does not specify one. - */ - public int getTextStyle() { - return mStyle; - } - - @Override - public void updateDrawState(TextPaint ds) { - updateMeasureState(ds); - - if (mTextColor != null) { - ds.setColor(mTextColor.getColorForState(ds.drawableState, 0)); - } - - if (mTextColorLink != null) { - ds.linkColor = mTextColor.getColorForState(ds.drawableState, 0); - } - } - - @Override - public void updateMeasureState(TextPaint ds) { - if (mTypeface != null || mStyle != 0) { - Typeface tf = ds.getTypeface(); - int style = 0; - - if (tf != null) { - style = tf.getStyle(); - } - - style |= mStyle; - - if (mTypeface != null) { - tf = Typeface.create(mTypeface, style); - } else if (tf == null) { - tf = Typeface.defaultFromStyle(style); - } else { - tf = Typeface.create(tf, style); - } - - int fake = style & ~tf.getStyle(); - - if ((fake & Typeface.BOLD) != 0) { - ds.setFakeBoldText(true); - } - - if ((fake & Typeface.ITALIC) != 0) { - ds.setTextSkewX(-0.25f); - } - - ds.setTypeface(tf); - } - - if (mTextSize > 0) { - ds.setTextSize(mTextSize); - } - } -} diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java deleted file mode 100644 index f194060..0000000 --- a/core/java/android/text/style/TypefaceSpan.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.graphics.Paint; -import android.graphics.Typeface; -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -/** - * Changes the typeface family of the text to which the span is attached. - */ -public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan { - private final String mFamily; - - /** - * @param family The font family for this typeface. Examples include - * "monospace", "serif", and "sans-serif". - */ - public TypefaceSpan(String family) { - mFamily = family; - } - - public TypefaceSpan(Parcel src) { - mFamily = src.readString(); - } - - public int getSpanTypeId() { - return TextUtils.TYPEFACE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mFamily); - } - - /** - * Returns the font family name. - */ - public String getFamily() { - return mFamily; - } - - @Override - public void updateDrawState(TextPaint ds) { - apply(ds, mFamily); - } - - @Override - public void updateMeasureState(TextPaint paint) { - apply(paint, mFamily); - } - - private static void apply(Paint paint, String family) { - int oldStyle; - - Typeface old = paint.getTypeface(); - if (old == null) { - oldStyle = 0; - } else { - oldStyle = old.getStyle(); - } - - Typeface tf = Typeface.create(family, oldStyle); - int fake = oldStyle & ~tf.getStyle(); - - if ((fake & Typeface.BOLD) != 0) { - paint.setFakeBoldText(true); - } - - if ((fake & Typeface.ITALIC) != 0) { - paint.setTextSkewX(-0.25f); - } - - paint.setTypeface(tf); - } -} diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java deleted file mode 100644 index f458611..0000000 --- a/core/java/android/text/style/URLSpan.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.content.Intent; -import android.net.Uri; -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextUtils; -import android.view.View; - -public class URLSpan extends ClickableSpan implements ParcelableSpan { - - private final String mURL; - - public URLSpan(String url) { - mURL = url; - } - - public URLSpan(Parcel src) { - mURL = src.readString(); - } - - public int getSpanTypeId() { - return TextUtils.URL_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mURL); - } - - public String getURL() { - return mURL; - } - - @Override - public void onClick(View widget) { - Uri uri = Uri.parse(getURL()); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - widget.getContext().startActivity(intent); - } -} diff --git a/core/java/android/text/style/UnderlineSpan.java b/core/java/android/text/style/UnderlineSpan.java deleted file mode 100644 index b0cb0e8..0000000 --- a/core/java/android/text/style/UnderlineSpan.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -import android.os.Parcel; -import android.text.ParcelableSpan; -import android.text.TextPaint; -import android.text.TextUtils; - -public class UnderlineSpan extends CharacterStyle - implements UpdateAppearance, ParcelableSpan { - public UnderlineSpan() { - } - - public UnderlineSpan(Parcel src) { - } - - public int getSpanTypeId() { - return TextUtils.UNDERLINE_SPAN; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - } - - @Override - public void updateDrawState(TextPaint ds) { - ds.setUnderlineText(true); - } -} diff --git a/core/java/android/text/style/UpdateAppearance.java b/core/java/android/text/style/UpdateAppearance.java deleted file mode 100644 index 198e4fa..0000000 --- a/core/java/android/text/style/UpdateAppearance.java +++ /dev/null @@ -1,10 +0,0 @@ -package android.text.style; - -/** - * The classes that affect character-level text in a way that modifies their - * appearance when one is added or removed must implement this interface. Note - * that if the class also impacts size or other metrics, it should instead - * implement {@link UpdateLayout}. - */ -public interface UpdateAppearance { -} diff --git a/core/java/android/text/style/UpdateLayout.java b/core/java/android/text/style/UpdateLayout.java deleted file mode 100644 index 591075e..0000000 --- a/core/java/android/text/style/UpdateLayout.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -/** - * The classes that affect character-level text formatting in a way that - * triggers a text layout update when one is added or removed must implement - * this interface. This interface also includes {@link UpdateAppearance} - * since such a change implicitly also impacts the appearance. - */ -public interface UpdateLayout extends UpdateAppearance { } diff --git a/core/java/android/text/style/WrapTogetherSpan.java b/core/java/android/text/style/WrapTogetherSpan.java deleted file mode 100644 index 11721a8..0000000 --- a/core/java/android/text/style/WrapTogetherSpan.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.style; - -public interface WrapTogetherSpan -extends ParagraphStyle -{ - -} diff --git a/core/java/android/text/style/package.html b/core/java/android/text/style/package.html deleted file mode 100644 index 0a8520c..0000000 --- a/core/java/android/text/style/package.html +++ /dev/null @@ -1,10 +0,0 @@ -<html> -<body> - -<p>Provides classes used to view or change the style of a span of text in a View object. -The classes with a subclass Standard are passed in to {@link android.text.SpannableString#setSpan(java.lang.Object, int, int, int) -SpannableString.setSpan()} or {@link android.text.SpannableStringBuilder#setSpan(java.lang.Object, int, int, int) -SpannableStringBuilder.setSpan()} to add a new styled span to a string in a View object. - -</body> -</html> diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java deleted file mode 100644 index d61e888..0000000 --- a/core/java/android/text/util/Linkify.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.util; - -import android.text.method.LinkMovementMethod; -import android.text.method.MovementMethod; -import android.text.style.URLSpan; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.webkit.WebView; -import android.widget.TextView; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Linkify take a piece of text and a regular expression and turns all of the - * regex matches in the text into clickable links. This is particularly - * useful for matching things like email addresses, web urls, etc. and making - * them actionable. - * - * Alone with the pattern that is to be matched, a url scheme prefix is also - * required. Any pattern match that does not begin with the supplied scheme - * will have the scheme prepended to the matched text when the clickable url - * is created. For instance, if you are matching web urls you would supply - * the scheme <code>http://</code>. If the pattern matches example.com, which - * does not have a url scheme prefix, the supplied scheme will be prepended to - * create <code>http://example.com</code> when the clickable url link is - * created. - */ - -public class Linkify { - /** - * Bit field indicating that web URLs should be matched in methods that - * take an options mask - */ - public static final int WEB_URLS = 0x01; - - /** - * Bit field indicating that email addresses should be matched in methods - * that take an options mask - */ - public static final int EMAIL_ADDRESSES = 0x02; - - /** - * Bit field indicating that phone numbers should be matched in methods that - * take an options mask - */ - public static final int PHONE_NUMBERS = 0x04; - - /** - * Bit field indicating that street addresses should be matched in methods that - * take an options mask - */ - public static final int MAP_ADDRESSES = 0x08; - - /** - * Bit mask indicating that all available patterns should be matched in - * methods that take an options mask - */ - public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS | MAP_ADDRESSES; - - /** - * Don't treat anything with fewer than this many digits as a - * phone number. - */ - private static final int PHONE_NUMBER_MINIMUM_DIGITS = 5; - - /** - * Filters out web URL matches that occur after an at-sign (@). This is - * to prevent turning the domain name in an email address into a web link. - */ - public static final MatchFilter sUrlMatchFilter = new MatchFilter() { - public final boolean acceptMatch(CharSequence s, int start, int end) { - if (start == 0) { - return true; - } - - if (s.charAt(start - 1) == '@') { - return false; - } - - return true; - } - }; - - /** - * Filters out URL matches that don't have enough digits to be a - * phone number. - */ - public static final MatchFilter sPhoneNumberMatchFilter = new MatchFilter() { - public final boolean acceptMatch(CharSequence s, int start, int end) { - int digitCount = 0; - - for (int i = start; i < end; i++) { - if (Character.isDigit(s.charAt(i))) { - digitCount++; - if (digitCount >= PHONE_NUMBER_MINIMUM_DIGITS) { - return true; - } - } - } - return false; - } - }; - - /** - * Transforms matched phone number text into something suitable - * to be used in a tel: URL. It does this by removing everything - * but the digits and plus signs. For instance: - * '+1 (919) 555-1212' - * becomes '+19195551212' - */ - public static final TransformFilter sPhoneNumberTransformFilter = new TransformFilter() { - public final String transformUrl(final Matcher match, String url) { - return Regex.digitsAndPlusOnly(match); - } - }; - - /** - * MatchFilter enables client code to have more control over - * what is allowed to match and become a link, and what is not. - * - * For example: when matching web urls you would like things like - * http://www.example.com to match, as well as just example.com itelf. - * However, you would not want to match against the domain in - * support@example.com. So, when matching against a web url pattern you - * might also include a MatchFilter that disallows the match if it is - * immediately preceded by an at-sign (@). - */ - public interface MatchFilter { - /** - * Examines the character span matched by the pattern and determines - * if the match should be turned into an actionable link. - * - * @param s The body of text against which the pattern - * was matched - * @param start The index of the first character in s that was - * matched by the pattern - inclusive - * @param end The index of the last character in s that was - * matched - exclusive - * - * @return Whether this match should be turned into a link - */ - boolean acceptMatch(CharSequence s, int start, int end); - } - - /** - * TransformFilter enables client code to have more control over - * how matched patterns are represented as URLs. - * - * For example: when converting a phone number such as (919) 555-1212 - * into a tel: URL the parentheses, white space, and hyphen need to be - * removed to produce tel:9195551212. - */ - public interface TransformFilter { - /** - * Examines the matched text and either passes it through or uses the - * data in the Matcher state to produce a replacement. - * - * @param match The regex matcher state that found this URL text - * @param url The text that was matched - * - * @return The transformed form of the URL - */ - String transformUrl(final Matcher match, String url); - } - - /** - * Scans the text of the provided Spannable and turns all occurrences - * of the link types indicated in the mask into clickable links. - * If the mask is nonzero, it also removes any existing URLSpans - * attached to the Spannable, to avoid problems if you call it - * repeatedly on the same text. - */ - public static final boolean addLinks(Spannable text, int mask) { - if (mask == 0) { - return false; - } - - URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class); - - for (int i = old.length - 1; i >= 0; i--) { - text.removeSpan(old[i]); - } - - ArrayList<LinkSpec> links = new ArrayList<LinkSpec>(); - - if ((mask & WEB_URLS) != 0) { - gatherLinks(links, text, Regex.WEB_URL_PATTERN, - new String[] { "http://", "https://" }, - sUrlMatchFilter, null); - } - - if ((mask & EMAIL_ADDRESSES) != 0) { - gatherLinks(links, text, Regex.EMAIL_ADDRESS_PATTERN, - new String[] { "mailto:" }, - null, null); - } - - if ((mask & PHONE_NUMBERS) != 0) { - gatherLinks(links, text, Regex.PHONE_PATTERN, - new String[] { "tel:" }, - sPhoneNumberMatchFilter, sPhoneNumberTransformFilter); - } - - if ((mask & MAP_ADDRESSES) != 0) { - gatherMapLinks(links, text); - } - - pruneOverlaps(links); - - if (links.size() == 0) { - return false; - } - - for (LinkSpec link: links) { - applyLink(link.url, link.start, link.end, text); - } - - return true; - } - - /** - * Scans the text of the provided TextView and turns all occurrences of - * the link types indicated in the mask into clickable links. If matches - * are found the movement method for the TextView is set to - * LinkMovementMethod. - */ - public static final boolean addLinks(TextView text, int mask) { - if (mask == 0) { - return false; - } - - CharSequence t = text.getText(); - - if (t instanceof Spannable) { - if (addLinks((Spannable) t, mask)) { - addLinkMovementMethod(text); - return true; - } - - return false; - } else { - SpannableString s = SpannableString.valueOf(t); - - if (addLinks(s, mask)) { - addLinkMovementMethod(text); - text.setText(s); - - return true; - } - - return false; - } - } - - private static final void addLinkMovementMethod(TextView t) { - MovementMethod m = t.getMovementMethod(); - - if ((m == null) || !(m instanceof LinkMovementMethod)) { - if (t.getLinksClickable()) { - t.setMovementMethod(LinkMovementMethod.getInstance()); - } - } - } - - /** - * Applies a regex to the text of a TextView turning the matches into - * links. If links are found then UrlSpans are applied to the link - * text match areas, and the movement method for the text is changed - * to LinkMovementMethod. - * - * @param text TextView whose text is to be marked-up with links - * @param pattern Regex pattern to be used for finding links - * @param scheme Url scheme string (eg <code>http://</code> to be - * prepended to the url of links that do not have - * a scheme specified in the link text - */ - public static final void addLinks(TextView text, Pattern pattern, String scheme) { - addLinks(text, pattern, scheme, null, null); - } - - /** - * Applies a regex to the text of a TextView turning the matches into - * links. If links are found then UrlSpans are applied to the link - * text match areas, and the movement method for the text is changed - * to LinkMovementMethod. - * - * @param text TextView whose text is to be marked-up with links - * @param p Regex pattern to be used for finding links - * @param scheme Url scheme string (eg <code>http://</code> to be - * prepended to the url of links that do not have - * a scheme specified in the link text - * @param matchFilter The filter that is used to allow the client code - * additional control over which pattern matches are - * to be converted into links. - */ - public static final void addLinks(TextView text, Pattern p, String scheme, - MatchFilter matchFilter, TransformFilter transformFilter) { - SpannableString s = SpannableString.valueOf(text.getText()); - - if (addLinks(s, p, scheme, matchFilter, transformFilter)) { - text.setText(s); - addLinkMovementMethod(text); - } - } - - /** - * Applies a regex to a Spannable turning the matches into - * links. - * - * @param text Spannable whose text is to be marked-up with - * links - * @param pattern Regex pattern to be used for finding links - * @param scheme Url scheme string (eg <code>http://</code> to be - * prepended to the url of links that do not have - * a scheme specified in the link text - */ - public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) { - return addLinks(text, pattern, scheme, null, null); - } - - /** - * Applies a regex to a Spannable turning the matches into - * links. - * - * @param s Spannable whose text is to be marked-up with - * links - * @param p Regex pattern to be used for finding links - * @param scheme Url scheme string (eg <code>http://</code> to be - * prepended to the url of links that do not have - * a scheme specified in the link text - * @param matchFilter The filter that is used to allow the client code - * additional control over which pattern matches are - * to be converted into links. - */ - public static final boolean addLinks(Spannable s, Pattern p, - String scheme, MatchFilter matchFilter, - TransformFilter transformFilter) { - boolean hasMatches = false; - String prefix = (scheme == null) ? "" : scheme.toLowerCase(); - Matcher m = p.matcher(s); - - while (m.find()) { - int start = m.start(); - int end = m.end(); - boolean allowed = true; - - if (matchFilter != null) { - allowed = matchFilter.acceptMatch(s, start, end); - } - - if (allowed) { - String url = makeUrl(m.group(0), new String[] { prefix }, - m, transformFilter); - - applyLink(url, start, end, s); - hasMatches = true; - } - } - - return hasMatches; - } - - private static final void applyLink(String url, int start, int end, Spannable text) { - URLSpan span = new URLSpan(url); - - text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - private static final String makeUrl(String url, String[] prefixes, - Matcher m, TransformFilter filter) { - if (filter != null) { - url = filter.transformUrl(m, url); - } - - boolean hasPrefix = false; - - for (int i = 0; i < prefixes.length; i++) { - if (url.regionMatches(true, 0, prefixes[i], 0, - prefixes[i].length())) { - hasPrefix = true; - - // Fix capitalization if necessary - if (!url.regionMatches(false, 0, prefixes[i], 0, - prefixes[i].length())) { - url = prefixes[i] + url.substring(prefixes[i].length()); - } - - break; - } - } - - if (!hasPrefix) { - url = prefixes[0] + url; - } - - return url; - } - - private static final void gatherLinks(ArrayList<LinkSpec> links, - Spannable s, Pattern pattern, String[] schemes, - MatchFilter matchFilter, TransformFilter transformFilter) { - Matcher m = pattern.matcher(s); - - while (m.find()) { - int start = m.start(); - int end = m.end(); - - if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) { - LinkSpec spec = new LinkSpec(); - String url = makeUrl(m.group(0), schemes, m, transformFilter); - - spec.url = url; - spec.start = start; - spec.end = end; - - links.add(spec); - } - } - } - - private static final void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) { - String string = s.toString(); - String address; - int base = 0; - - while ((address = WebView.findAddress(string)) != null) { - int start = string.indexOf(address); - - if (start < 0) { - break; - } - - LinkSpec spec = new LinkSpec(); - int length = address.length(); - int end = start + length; - - spec.start = base + start; - spec.end = base + end; - string = string.substring(end); - base += end; - - String encodedAddress = null; - - try { - encodedAddress = URLEncoder.encode(address,"UTF-8"); - } catch (UnsupportedEncodingException e) { - continue; - } - - spec.url = "geo:0,0?q=" + encodedAddress; - links.add(spec); - } - } - - private static final void pruneOverlaps(ArrayList<LinkSpec> links) { - Comparator<LinkSpec> c = new Comparator<LinkSpec>() { - public final int compare(LinkSpec a, LinkSpec b) { - if (a.start < b.start) { - return -1; - } - - if (a.start > b.start) { - return 1; - } - - if (a.end < b.end) { - return 1; - } - - if (a.end > b.end) { - return -1; - } - - return 0; - } - - public final boolean equals(Object o) { - return false; - } - }; - - Collections.sort(links, c); - - int len = links.size(); - int i = 0; - - while (i < len - 1) { - LinkSpec a = links.get(i); - LinkSpec b = links.get(i + 1); - int remove = -1; - - if ((a.start <= b.start) && (a.end > b.start)) { - if (b.end <= a.end) { - remove = i + 1; - } else if ((a.end - a.start) > (b.end - b.start)) { - remove = i + 1; - } else if ((a.end - a.start) < (b.end - b.start)) { - remove = i; - } - - if (remove != -1) { - links.remove(remove); - len--; - continue; - } - - } - - i++; - } - } -} - -class LinkSpec { - String url; - int start; - int end; -} diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java deleted file mode 100644 index 4c128ad..0000000 --- a/core/java/android/text/util/Regex.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @hide - */ -public class Regex { - /** - * Regular expression pattern to match all IANA top-level domains. - * List accurate as of 2007/06/15. List taken from: - * http://data.iana.org/TLD/tlds-alpha-by-domain.txt - * This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py - */ - public static final Pattern TOP_LEVEL_DOMAIN_PATTERN - = Pattern.compile( - "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])" - + "|(biz|b[abdefghijmnorstvwyz])" - + "|(cat|com|coop|c[acdfghiklmnoruvxyz])" - + "|d[ejkmoz]" - + "|(edu|e[cegrstu])" - + "|f[ijkmor]" - + "|(gov|g[abdefghilmnpqrstuwy])" - + "|h[kmnrtu]" - + "|(info|int|i[delmnoqrst])" - + "|(jobs|j[emop])" - + "|k[eghimnrwyz]" - + "|l[abcikrstuvy]" - + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])" - + "|(name|net|n[acefgilopruz])" - + "|(org|om)" - + "|(pro|p[aefghklmnrstwy])" - + "|qa" - + "|r[eouw]" - + "|s[abcdeghijklmnortuvyz]" - + "|(tel|travel|t[cdfghjklmnoprtvwz])" - + "|u[agkmsyz]" - + "|v[aceginu]" - + "|w[fs]" - + "|y[etu]" - + "|z[amw])"); - - /** - * Regular expression pattern to match RFC 1738 URLs - * List accurate as of 2007/06/15. List taken from: - * http://data.iana.org/TLD/tlds-alpha-by-domain.txt - * This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py - */ - public static final Pattern WEB_URL_PATTERN - = Pattern.compile( - "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" - + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" - + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+)?\\@)?)?" - + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+" // named host - + "(?:" // plus top level domain - + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])" - + "|(?:biz|b[abdefghijmnorstvwyz])" - + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])" - + "|d[ejkmoz]" - + "|(?:edu|e[cegrstu])" - + "|f[ijkmor]" - + "|(?:gov|g[abdefghilmnpqrstuwy])" - + "|h[kmnrtu]" - + "|(?:info|int|i[delmnoqrst])" - + "|(?:jobs|j[emop])" - + "|k[eghimnrwyz]" - + "|l[abcikrstuvy]" - + "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])" - + "|(?:name|net|n[acefgilopruz])" - + "|(?:org|om)" - + "|(?:pro|p[aefghklmnrstwy])" - + "|qa" - + "|r[eouw]" - + "|s[abcdeghijklmnortuvyz]" - + "|(?:tel|travel|t[cdfghjklmnoprtvwz])" - + "|u[agkmsyz]" - + "|v[aceginu]" - + "|w[fs]" - + "|y[etu]" - + "|z[amw]))" - + "|(?:(?:25[0-5]|2[0-4]" // or ip address - + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]" - + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]" - + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" - + "|[1-9][0-9]|[0-9])))" - + "(?:\\:\\d{1,5})?)" // plus option port number - + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params - + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" - + "(?:\\b|$)"); // and finally, a word boundary or end of - // input. This is to stop foo.sure from - // matching as foo.su - - public static final Pattern IP_ADDRESS_PATTERN - = Pattern.compile( - "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" - + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" - + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" - + "|[1-9][0-9]|[0-9]))"); - - public static final Pattern DOMAIN_NAME_PATTERN - = Pattern.compile( - "(((([a-zA-Z0-9][a-zA-Z0-9\\-]*)*[a-zA-Z0-9]\\.)+" - + TOP_LEVEL_DOMAIN_PATTERN + ")|" - + IP_ADDRESS_PATTERN + ")"); - - public static final Pattern EMAIL_ADDRESS_PATTERN - = Pattern.compile( - "[a-zA-Z0-9\\+\\.\\_\\%\\-]+" + - "\\@" + - "[a-zA-Z0-9][a-zA-Z0-9\\-]*" + - "(" + - "\\." + - "[a-zA-Z0-9][a-zA-Z0-9\\-]*" + - ")+" - ); - - /** - * This pattern is intended for searching for things that look like they - * might be phone numbers in arbitrary text, not for validating whether - * something is in fact a phone number. It will miss many things that - * are legitimate phone numbers. - * - * <p> The pattern matches the following: - * <ul> - * <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes - * may follow. - * <li>Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes. - * <li>A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes. - * </ul> - */ - public static final Pattern PHONE_PATTERN - = Pattern.compile( // sdd = space, dot, or dash - "(\\+[0-9]+[\\- \\.]*)?" // +<digits><sdd>* - + "(\\([0-9]+\\)[\\- \\.]*)?" // (<digits>)<sdd>* - + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit> - - /** - * Convenience method to take all of the non-null matching groups in a - * regex Matcher and return them as a concatenated string. - * - * @param matcher The Matcher object from which grouped text will - * be extracted - * - * @return A String comprising all of the non-null matched - * groups concatenated together - */ - public static final String concatGroups(Matcher matcher) { - StringBuilder b = new StringBuilder(); - final int numGroups = matcher.groupCount(); - - for (int i = 1; i <= numGroups; i++) { - String s = matcher.group(i); - - System.err.println("Group(" + i + ") : " + s); - - if (s != null) { - b.append(s); - } - } - - return b.toString(); - } - - /** - * Convenience method to return only the digits and plus signs - * in the matching string. - * - * @param matcher The Matcher object from which digits and plus will - * be extracted - * - * @return A String comprising all of the digits and plus in - * the match - */ - public static final String digitsAndPlusOnly(Matcher matcher) { - StringBuilder buffer = new StringBuilder(); - String matchingRegion = matcher.group(); - - for (int i = 0, size = matchingRegion.length(); i < size; i++) { - char character = matchingRegion.charAt(i); - - if (character == '+' || Character.isDigit(character)) { - buffer.append(character); - } - } - return buffer.toString(); - } -} diff --git a/core/java/android/text/util/Rfc822Token.java b/core/java/android/text/util/Rfc822Token.java deleted file mode 100644 index e6472df..0000000 --- a/core/java/android/text/util/Rfc822Token.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.util; - -/** - * This class stores an RFC 822-like name, address, and comment, - * and provides methods to convert them to quoted strings. - */ -public class Rfc822Token { - private String mName, mAddress, mComment; - - /** - * Creates a new Rfc822Token with the specified name, address, - * and comment. - */ - public Rfc822Token(String name, String address, String comment) { - mName = name; - mAddress = address; - mComment = comment; - } - - /** - * Returns the name part. - */ - public String getName() { - return mName; - } - - /** - * Returns the address part. - */ - public String getAddress() { - return mAddress; - } - - /** - * Returns the comment part. - */ - public String getComment() { - return mComment; - } - - /** - * Changes the name to the specified name. - */ - public void setName(String name) { - mName = name; - } - - /** - * Changes the address to the specified address. - */ - public void setAddress(String address) { - mAddress = address; - } - - /** - * Changes the comment to the specified comment. - */ - public void setComment(String comment) { - mComment = comment; - } - - /** - * Returns the name (with quoting added if necessary), - * the comment (in parentheses), and the address (in angle brackets). - * This should be suitable for inclusion in an RFC 822 address list. - */ - public String toString() { - StringBuilder sb = new StringBuilder(); - - if (mName != null && mName.length() != 0) { - sb.append(quoteNameIfNecessary(mName)); - sb.append(' '); - } - - if (mComment != null && mComment.length() != 0) { - sb.append('('); - sb.append(quoteComment(mComment)); - sb.append(") "); - } - - if (mAddress != null && mAddress.length() != 0) { - sb.append('<'); - sb.append(mAddress); - sb.append('>'); - } - - return sb.toString(); - } - - /** - * Returns the name, conservatively quoting it if there are any - * characters that are likely to cause trouble outside of a - * quoted string, or returning it literally if it seems safe. - */ - public static String quoteNameIfNecessary(String name) { - int len = name.length(); - - for (int i = 0; i < len; i++) { - char c = name.charAt(i); - - if (! ((c >= 'A' && i <= 'Z') || - (c >= 'a' && c <= 'z') || - (c == ' ') || - (c >= '0' && c <= '9'))) { - return '"' + quoteName(name) + '"'; - } - } - - return name; - } - - /** - * Returns the name, with internal backslashes and quotation marks - * preceded by backslashes. The outer quote marks themselves are not - * added by this method. - */ - public static String quoteName(String name) { - StringBuilder sb = new StringBuilder(); - - int len = name.length(); - for (int i = 0; i < len; i++) { - char c = name.charAt(i); - - if (c == '\\' || c == '"') { - sb.append('\\'); - } - - sb.append(c); - } - - return sb.toString(); - } - - /** - * Returns the comment, with internal backslashes and parentheses - * preceded by backslashes. The outer parentheses themselves are - * not added by this method. - */ - public static String quoteComment(String comment) { - int len = comment.length(); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < len; i++) { - char c = comment.charAt(i); - - if (c == '(' || c == ')' || c == '\\') { - sb.append('\\'); - } - - sb.append(c); - } - - return sb.toString(); - } -} - diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java deleted file mode 100644 index d4e78b0..0000000 --- a/core/java/android/text/util/Rfc822Tokenizer.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.util; - -import android.widget.MultiAutoCompleteTextView; - -import java.util.ArrayList; - -/** - * This class works as a Tokenizer for MultiAutoCompleteTextView for - * address list fields, and also provides a method for converting - * a string of addresses (such as might be typed into such a field) - * into a series of Rfc822Tokens. - */ -public class Rfc822Tokenizer implements MultiAutoCompleteTextView.Tokenizer { - /** - * This constructor will try to take a string like - * "Foo Bar (something) <foo\@google.com>, - * blah\@google.com (something)" - * and convert it into one or more Rfc822Tokens. - * It does *not* decode MIME encoded-words; charset conversion - * must already have taken place if necessary. - * It will try to be tolerant of broken syntax instead of - * returning an error. - */ - public static Rfc822Token[] tokenize(CharSequence text) { - ArrayList<Rfc822Token> out = new ArrayList<Rfc822Token>(); - StringBuilder name = new StringBuilder(); - StringBuilder address = new StringBuilder(); - StringBuilder comment = new StringBuilder(); - - int i = 0; - int cursor = text.length(); - - while (i < cursor) { - char c = text.charAt(i); - - if (c == ',' || c == ';') { - i++; - - while (i < cursor && text.charAt(i) == ' ') { - i++; - } - - crunch(name); - - if (address.length() > 0) { - out.add(new Rfc822Token(name.toString(), - address.toString(), - comment.toString())); - } else if (name.length() > 0) { - out.add(new Rfc822Token(null, - name.toString(), - comment.toString())); - } - - name.setLength(0); - address.setLength(0); - address.setLength(0); - } else if (c == '"') { - i++; - - while (i < cursor) { - c = text.charAt(i); - - if (c == '"') { - i++; - break; - } else if (c == '\\') { - name.append(text.charAt(i + 1)); - i += 2; - } else { - name.append(c); - i++; - } - } - } else if (c == '(') { - int level = 1; - i++; - - while (i < cursor && level > 0) { - c = text.charAt(i); - - if (c == ')') { - if (level > 1) { - comment.append(c); - } - - level--; - i++; - } else if (c == '(') { - comment.append(c); - level++; - i++; - } else if (c == '\\') { - comment.append(text.charAt(i + 1)); - i += 2; - } else { - comment.append(c); - i++; - } - } - } else if (c == '<') { - i++; - - while (i < cursor) { - c = text.charAt(i); - - if (c == '>') { - i++; - break; - } else { - address.append(c); - i++; - } - } - } else if (c == ' ') { - name.append('\0'); - i++; - } else { - name.append(c); - i++; - } - } - - crunch(name); - - if (address.length() > 0) { - out.add(new Rfc822Token(name.toString(), - address.toString(), - comment.toString())); - } else if (name.length() > 0) { - out.add(new Rfc822Token(null, - name.toString(), - comment.toString())); - } - - return out.toArray(new Rfc822Token[out.size()]); - } - - private static void crunch(StringBuilder sb) { - int i = 0; - int len = sb.length(); - - while (i < len) { - char c = sb.charAt(i); - - if (c == '\0') { - if (i == 0 || i == len - 1 || - sb.charAt(i - 1) == ' ' || - sb.charAt(i - 1) == '\0' || - sb.charAt(i + 1) == ' ' || - sb.charAt(i + 1) == '\0') { - sb.deleteCharAt(i); - len--; - } else { - i++; - } - } else { - i++; - } - } - - for (i = 0; i < len; i++) { - if (sb.charAt(i) == '\0') { - sb.setCharAt(i, ' '); - } - } - } - - /** - * {@inheritDoc} - */ - public int findTokenStart(CharSequence text, int cursor) { - /* - * It's hard to search backward, so search forward until - * we reach the cursor. - */ - - int best = 0; - int i = 0; - - while (i < cursor) { - i = findTokenEnd(text, i); - - if (i < cursor) { - i++; // Skip terminating punctuation - - while (i < cursor && text.charAt(i) == ' ') { - i++; - } - - if (i < cursor) { - best = i; - } - } - } - - return best; - } - - /** - * {@inheritDoc} - */ - public int findTokenEnd(CharSequence text, int cursor) { - int len = text.length(); - int i = cursor; - - while (i < len) { - char c = text.charAt(i); - - if (c == ',' || c == ';') { - return i; - } else if (c == '"') { - i++; - - while (i < len) { - c = text.charAt(i); - - if (c == '"') { - i++; - break; - } else if (c == '\\') { - i += 2; - } else { - i++; - } - } - } else if (c == '(') { - int level = 1; - i++; - - while (i < len && level > 0) { - c = text.charAt(i); - - if (c == ')') { - level--; - i++; - } else if (c == '(') { - level++; - i++; - } else if (c == '\\') { - i += 2; - } else { - i++; - } - } - } else if (c == '<') { - i++; - - while (i < len) { - c = text.charAt(i); - - if (c == '>') { - i++; - break; - } else { - i++; - } - } - } else { - i++; - } - } - - return i; - } - - /** - * Terminates the specified address with a comma and space. - * This assumes that the specified text already has valid syntax. - * The Adapter subclass's convertToString() method must make that - * guarantee. - */ - public CharSequence terminateToken(CharSequence text) { - return text + ", "; - } -} diff --git a/core/java/android/text/util/Rfc822Validator.java b/core/java/android/text/util/Rfc822Validator.java deleted file mode 100644 index 6a6bf69..0000000 --- a/core/java/android/text/util/Rfc822Validator.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text.util; - -import android.text.TextUtils; -import android.widget.AutoCompleteTextView; - -import java.util.regex.Pattern; - -/** - * This class works as a Validator for AutoCompleteTextView for - * email addresses. If a token does not appear to be a valid address, - * it is trimmed of characters that cannot legitimately appear in one - * and has the specified domain name added. It is meant for use with - * {@link Rfc822Token} and {@link Rfc822Tokenizer}. - * - * @deprecated In the future make sure we don't quietly alter the user's - * text in ways they did not intend. Meanwhile, hide this - * class from the public API because it does not even have - * a full understanding of the syntax it claims to correct. - * @hide - */ -public class Rfc822Validator implements AutoCompleteTextView.Validator { - /* - * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we - * want to make sure we will keep accepting email addresses with TLD's - * that don't exist at the time of this writing, so this regexp relaxes - * that constraint by accepting any kind of top level domain, not just - * ".com", ".fr", etc... - */ - private static final Pattern EMAIL_ADDRESS_PATTERN = - Pattern.compile("[^\\s@]+@[^\\s@]+\\.[a-zA-z][a-zA-Z][a-zA-Z]*"); - - private String mDomain; - - /** - * Constructs a new validator that uses the specified domain name as - * the default when none is specified. - */ - public Rfc822Validator(String domain) { - mDomain = domain; - } - - /** - * {@inheritDoc} - */ - public boolean isValid(CharSequence text) { - Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text); - - return tokens.length == 1 && - EMAIL_ADDRESS_PATTERN. - matcher(tokens[0].getAddress()).matches(); - } - - /** - * @return a string in which all the characters that are illegal for the username - * or the domain name part of the email address have been removed. - */ - private String removeIllegalCharacters(String s) { - StringBuilder result = new StringBuilder(); - int length = s.length(); - for (int i = 0; i < length; i++) { - char c = s.charAt(i); - - /* - * An RFC822 atom can contain any ASCII printing character - * except for periods and any of the following punctuation. - * A local-part can contain multiple atoms, concatenated by - * periods, so do allow periods here. - */ - - if (c <= ' ' || c > '~') { - continue; - } - - if (c == '(' || c == ')' || c == '<' || c == '>' || - c == '@' || c == ',' || c == ';' || c == ':' || - c == '\\' || c == '"' || c == '[' || c == ']') { - continue; - } - - result.append(c); - } - return result.toString(); - } - - /** - * {@inheritDoc} - */ - public CharSequence fixText(CharSequence cs) { - // Return an empty string if the email address only contains spaces, \n or \t - if (TextUtils.getTrimmedLength(cs) == 0) return ""; - - Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < tokens.length; i++) { - String text = tokens[i].getAddress(); - int index = text.indexOf('@'); - if (index < 0) { - // If there is no @, just append the domain of the account - tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain); - } else { - // Otherwise, remove the illegal characters on both sides of the '@' - String fix = removeIllegalCharacters(text.substring(0, index)); - String domain = removeIllegalCharacters(text.substring(index + 1)); - tokens[i].setAddress(fix + "@" + (domain.length() != 0 ? domain : mDomain)); - } - - sb.append(tokens[i].toString()); - if (i + 1 < tokens.length) { - sb.append(", "); - } - } - - return sb; - } -} diff --git a/core/java/android/text/util/package.html b/core/java/android/text/util/package.html deleted file mode 100644 index d9312aa2..0000000 --- a/core/java/android/text/util/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Utilities for converting identifiable text strings into clickable links -and creating RFC 822-type message (SMTP) tokens. -</BODY> -</HTML>
\ No newline at end of file |
