Move tests with private APIs to coretests
Tests have been moved from CTS tests, with some small modifications. Test: adb shell am instrument -w -e package android.text com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner Bug: 37780152 Change-Id: I87ce084276db0f1157260bbeb0c9009c5227bfcf
This commit is contained in:
84
core/tests/coretests/src/android/text/BidiFormatterTest.java
Normal file
84
core/tests/coretests/src/android/text/BidiFormatterTest.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BidiFormatterTest {
|
||||
private static final BidiFormatter LTR_FMT = BidiFormatter.getInstance(false /* LTR context */);
|
||||
private static final BidiFormatter RTL_FMT = BidiFormatter.getInstance(true /* RTL context */);
|
||||
|
||||
private static final String EN = "abba";
|
||||
private static final String HE = "\u05E0\u05E1";
|
||||
|
||||
private static final String LRM = "\u200E";
|
||||
private static final String RLM = "\u200F";
|
||||
|
||||
@Test
|
||||
public void testMarkAfter() {
|
||||
assertEquals("uniform dir matches LTR context",
|
||||
"", LTR_FMT.markAfter(EN, TextDirectionHeuristics.LTR));
|
||||
assertEquals("uniform dir matches RTL context",
|
||||
"", RTL_FMT.markAfter(HE, TextDirectionHeuristics.RTL));
|
||||
|
||||
assertEquals("exit dir opposite to LTR context",
|
||||
LRM, LTR_FMT.markAfter(EN + HE, TextDirectionHeuristics.LTR));
|
||||
assertEquals("exit dir opposite to RTL context",
|
||||
RLM, RTL_FMT.markAfter(HE + EN, TextDirectionHeuristics.RTL));
|
||||
|
||||
assertEquals("overall dir (but not exit dir) opposite to LTR context",
|
||||
LRM, LTR_FMT.markAfter(HE + EN, TextDirectionHeuristics.RTL));
|
||||
assertEquals("overall dir (but not exit dir) opposite to RTL context",
|
||||
RLM, RTL_FMT.markAfter(EN + HE, TextDirectionHeuristics.LTR));
|
||||
|
||||
assertEquals("exit dir neutral, overall dir matches LTR context",
|
||||
"", LTR_FMT.markAfter(".", TextDirectionHeuristics.LTR));
|
||||
assertEquals("exit dir neutral, overall dir matches RTL context",
|
||||
"", RTL_FMT.markAfter(".", TextDirectionHeuristics.RTL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkBefore() {
|
||||
assertEquals("uniform dir matches LTR context",
|
||||
"", LTR_FMT.markBefore(EN, TextDirectionHeuristics.LTR));
|
||||
assertEquals("uniform dir matches RTL context",
|
||||
"", RTL_FMT.markBefore(HE, TextDirectionHeuristics.RTL));
|
||||
|
||||
assertEquals("entry dir opposite to LTR context",
|
||||
LRM, LTR_FMT.markBefore(HE + EN, TextDirectionHeuristics.LTR));
|
||||
assertEquals("entry dir opposite to RTL context",
|
||||
RLM, RTL_FMT.markBefore(EN + HE, TextDirectionHeuristics.RTL));
|
||||
|
||||
assertEquals("overall dir (but not entry dir) opposite to LTR context",
|
||||
LRM, LTR_FMT.markBefore(EN + HE, TextDirectionHeuristics.RTL));
|
||||
assertEquals("overall dir (but not entry dir) opposite to RTL context",
|
||||
RLM, RTL_FMT.markBefore(HE + EN, TextDirectionHeuristics.LTR));
|
||||
|
||||
assertEquals("exit dir neutral, overall dir matches LTR context",
|
||||
"", LTR_FMT.markBefore(".", TextDirectionHeuristics.LTR));
|
||||
assertEquals("exit dir neutral, overall dir matches RTL context",
|
||||
"", RTL_FMT.markBefore(".", TextDirectionHeuristics.RTL));
|
||||
}
|
||||
}
|
||||
469
core/tests/coretests/src/android/text/LayoutTest.java
Normal file
469
core/tests/coretests/src/android/text/LayoutTest.java
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.style.StrikethroughSpan;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class LayoutTest {
|
||||
private static final int LINE_COUNT = 5;
|
||||
private static final int LINE_HEIGHT = 12;
|
||||
private static final int LINE_DESCENT = 4;
|
||||
private static final CharSequence LAYOUT_TEXT = "alwei\t;sdfs\ndf @";
|
||||
|
||||
private SpannableString mSpannedText;
|
||||
|
||||
private int mWidth;
|
||||
private Layout.Alignment mAlign;
|
||||
private float mSpacingMult;
|
||||
private float mSpacingAdd;
|
||||
private TextPaint mTextPaint;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mTextPaint = new TextPaint();
|
||||
mSpannedText = new SpannableString(LAYOUT_TEXT);
|
||||
mSpannedText.setSpan(new StrikethroughSpan(), 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
mWidth = 11;
|
||||
mAlign = Alignment.ALIGN_CENTER;
|
||||
mSpacingMult = 1;
|
||||
mSpacingAdd = 2;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor() {
|
||||
new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testConstructorNull() {
|
||||
new MockLayout(null, null, -1, null, 0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetText() {
|
||||
CharSequence text = "test case 1";
|
||||
Layout layout = new MockLayout(text, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(text, layout.getText());
|
||||
|
||||
layout = new MockLayout(null, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertNull(layout.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPaint() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
|
||||
assertSame(mTextPaint, layout.getPaint());
|
||||
|
||||
layout = new MockLayout(LAYOUT_TEXT, null, mWidth, mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertNull(layout.getPaint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWidth() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 10,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(10, layout.getWidth());
|
||||
|
||||
layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(0, layout.getWidth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetEllipsizedWidth() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 15,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(15, layout.getEllipsizedWidth());
|
||||
|
||||
layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(0, layout.getEllipsizedWidth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncreaseWidthTo() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
int oldWidth = layout.getWidth();
|
||||
|
||||
layout.increaseWidthTo(oldWidth);
|
||||
assertEquals(oldWidth, layout.getWidth());
|
||||
|
||||
try {
|
||||
layout.increaseWidthTo(oldWidth - 1);
|
||||
fail("should throw runtime exception attempted to reduce Layout width");
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
|
||||
layout.increaseWidthTo(oldWidth + 1);
|
||||
assertEquals(oldWidth + 1, layout.getWidth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetHeight() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(60, layout.getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAlignment() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertSame(mAlign, layout.getAlignment());
|
||||
|
||||
layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, null, mSpacingMult, mSpacingAdd);
|
||||
assertNull(layout.getAlignment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSpacingMultiplier() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, -1, mSpacingAdd);
|
||||
assertEquals(-1.0f, layout.getSpacingMultiplier(), 0.0f);
|
||||
|
||||
layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, 5, mSpacingAdd);
|
||||
assertEquals(5.0f, layout.getSpacingMultiplier(), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSpacingAdd() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, -1);
|
||||
assertEquals(-1.0f, layout.getSpacingAdd(), 0.0f);
|
||||
|
||||
layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, 20);
|
||||
assertEquals(20.0f, layout.getSpacingAdd(), 0.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineBounds() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
Rect bounds = new Rect();
|
||||
|
||||
assertEquals(32, layout.getLineBounds(2, bounds));
|
||||
assertEquals(0, bounds.left);
|
||||
assertEquals(mWidth, bounds.right);
|
||||
assertEquals(24, bounds.top);
|
||||
assertEquals(36, bounds.bottom);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineForVertical() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(0, layout.getLineForVertical(-1));
|
||||
assertEquals(0, layout.getLineForVertical(0));
|
||||
assertEquals(0, layout.getLineForVertical(LINE_COUNT));
|
||||
assertEquals(LINE_COUNT - 1, layout.getLineForVertical(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineForOffset() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(0, layout.getLineForOffset(-1));
|
||||
assertEquals(1, layout.getLineForOffset(1));
|
||||
assertEquals(LINE_COUNT - 1, layout.getLineForOffset(LINE_COUNT - 1));
|
||||
assertEquals(LINE_COUNT - 1, layout.getLineForOffset(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineEnd() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(2, layout.getLineEnd(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineVisibleEnd() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
|
||||
assertEquals(2, layout.getLineVisibleEnd(1));
|
||||
assertEquals(LINE_COUNT, layout.getLineVisibleEnd(LINE_COUNT - 1));
|
||||
assertEquals(LAYOUT_TEXT.length(), layout.getLineVisibleEnd(LAYOUT_TEXT.length() - 1));
|
||||
try {
|
||||
layout.getLineVisibleEnd(LAYOUT_TEXT.length());
|
||||
fail("should throw .StringIndexOutOfBoundsException here");
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineBottom() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(LINE_HEIGHT, layout.getLineBottom(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineBaseline() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(8, layout.getLineBaseline(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineAscent() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(-8, layout.getLineAscent(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParagraphAlignment() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertSame(mAlign, layout.getParagraphAlignment(0));
|
||||
|
||||
layout = new MockLayout(mSpannedText, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertSame(mAlign, layout.getParagraphAlignment(0));
|
||||
assertSame(mAlign, layout.getParagraphAlignment(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParagraphLeft() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(0, layout.getParagraphLeft(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParagraphRight() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertEquals(mWidth, layout.getParagraphRight(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSpanned() {
|
||||
MockLayout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
// default is not spanned text
|
||||
assertFalse(layout.mockIsSpanned());
|
||||
|
||||
// try to create a spanned text
|
||||
layout = new MockLayout(mSpannedText, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
assertTrue(layout.mockIsSpanned());
|
||||
}
|
||||
|
||||
private static final class MockLayout extends Layout {
|
||||
MockLayout(CharSequence text, TextPaint paint, int width,
|
||||
Alignment align, float spacingmult, float spacingadd) {
|
||||
super(text, paint, width, align, spacingmult, spacingadd);
|
||||
}
|
||||
|
||||
protected boolean mockIsSpanned() {
|
||||
return super.isSpanned();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBottomPadding() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEllipsisCount(int line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEllipsisStart(int line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLineContainsTab(int line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineCount() {
|
||||
return LINE_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineDescent(int line) {
|
||||
return LINE_DESCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directions getLineDirections(int line) {
|
||||
return Layout.DIRS_ALL_LEFT_TO_RIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineStart(int line) {
|
||||
if (line < 0) {
|
||||
return 0;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineTop(int line) {
|
||||
if (line < 0) {
|
||||
return 0;
|
||||
}
|
||||
return LINE_HEIGHT * (line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParagraphDirection(int line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTopPadding() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLineWidth() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
for (int i = 0; i < LINE_COUNT; i++) {
|
||||
int start = layout.getLineStart(i);
|
||||
int end = layout.getLineEnd(i);
|
||||
String text = LAYOUT_TEXT.toString().substring(start, end);
|
||||
assertEquals(mTextPaint.measureText(text), layout.getLineWidth(i), 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCursorPath() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
Path path = new Path();
|
||||
final float epsilon = 1.0f;
|
||||
for (int i = 0; i < LINE_COUNT; i++) {
|
||||
layout.getCursorPath(i, path, LAYOUT_TEXT);
|
||||
RectF bounds = new RectF();
|
||||
path.computeBounds(bounds, false);
|
||||
assertTrue(bounds.top >= layout.getLineTop(i) - epsilon);
|
||||
assertTrue(bounds.bottom <= layout.getLineBottom(i) + epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDraw() {
|
||||
Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
|
||||
mAlign, mSpacingMult, mSpacingAdd);
|
||||
final int width = 256;
|
||||
final int height = 256;
|
||||
MockCanvas c = new MockCanvas(width, height);
|
||||
layout.draw(c);
|
||||
List<MockCanvas.DrawCommand> drawCommands = c.getDrawCommands();
|
||||
assertEquals(LINE_COUNT, drawCommands.size());
|
||||
for (int i = 0; i < LINE_COUNT; i++) {
|
||||
MockCanvas.DrawCommand drawCommand = drawCommands.get(i);
|
||||
int start = layout.getLineStart(i);
|
||||
int end = layout.getLineEnd(i);
|
||||
assertEquals(LAYOUT_TEXT.toString().substring(start, end), drawCommand.text);
|
||||
float expected_y = (i + 1) * LINE_HEIGHT - LINE_DESCENT;
|
||||
assertEquals(expected_y, drawCommand.y, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
private final class MockCanvas extends Canvas {
|
||||
|
||||
class DrawCommand {
|
||||
public final String text;
|
||||
public final float x;
|
||||
public final float y;
|
||||
|
||||
DrawCommand(String text, float x, float y) {
|
||||
this.text = text;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
List<DrawCommand> mDrawCommands;
|
||||
|
||||
MockCanvas(int width, int height) {
|
||||
super();
|
||||
mDrawCommands = new ArrayList<>();
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
setBitmap(bitmap);
|
||||
}
|
||||
|
||||
// Drawing text with either drawText or drawTextRun is valid; we don't care which.
|
||||
// We also don't care which of the string representations is used.
|
||||
|
||||
@Override
|
||||
public void drawText(String text, int start, int end, float x, float y, Paint p) {
|
||||
mDrawCommands.add(new DrawCommand(text.substring(start, end), x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(CharSequence text, int start, int end, float x, float y, Paint p) {
|
||||
drawText(text.toString(), start, end, x, y, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawText(char[] text, int index, int count, float x, float y, Paint p) {
|
||||
mDrawCommands.add(new DrawCommand(new String(text, index, count), x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTextRun(CharSequence text, int start, int end, int contextStart,
|
||||
int contextEnd, float x, float y, boolean isRtl, Paint paint) {
|
||||
drawText(text, start, end, x, y, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTextRun(char[] text, int index, int count, int contextIndex,
|
||||
int contextCount, float x, float y, boolean isRtl, Paint paint) {
|
||||
drawText(text, index, count, x, y, paint);
|
||||
}
|
||||
|
||||
List<DrawCommand> getDrawCommands() {
|
||||
return mDrawCommands;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,46 @@
|
||||
|
||||
package android.text;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import android.text.style.BulletSpan;
|
||||
import android.text.style.QuoteSpan;
|
||||
import android.text.style.SubscriptSpan;
|
||||
import android.text.style.UnderlineSpan;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class SpannableStringBuilderTest extends SpannableTest {
|
||||
|
||||
protected Spannable newSpannableWithText(String text) {
|
||||
return new SpannableStringBuilder(text);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSpans_sortsByPriorityEvenWhenSortParamIsFalse() {
|
||||
String text = "p_in_s";
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(text);
|
||||
Object first = new SubscriptSpan();
|
||||
Object second = new UnderlineSpan();
|
||||
Object third = new BulletSpan();
|
||||
Object fourth = new QuoteSpan();
|
||||
|
||||
builder.setSpan(first, 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
builder.setSpan(second, 1, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
builder.setSpan(third, 2, text.length(), 1 << Spanned.SPAN_PRIORITY_SHIFT);
|
||||
builder.setSpan(fourth, 0, text.length(), 2 << Spanned.SPAN_PRIORITY_SHIFT);
|
||||
|
||||
Object[] spans = builder.getSpans(0, text.length(), Object.class, false);
|
||||
|
||||
assertNotNull(spans);
|
||||
assertEquals(4, spans.length);
|
||||
// priority spans are first
|
||||
assertEquals(fourth, spans[0]);
|
||||
assertEquals(third, spans[1]);
|
||||
// other spans should be there
|
||||
assertEquals(second, spans[2]);
|
||||
assertEquals(first, spans[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.style.MetricAffectingSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StaticLayoutLineBreakingTest {
|
||||
// Span test are currently not supported because text measurement uses the MeasuredText
|
||||
// internal mWorkPaint instead of the provided MockTestPaint.
|
||||
private static final boolean SPAN_TESTS_SUPPORTED = false;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final float SPACE_MULTI = 1.0f;
|
||||
private static final float SPACE_ADD = 0.0f;
|
||||
private static final int WIDTH = 100;
|
||||
private static final Alignment ALIGN = Alignment.ALIGN_LEFT;
|
||||
|
||||
private static final char SURR_FIRST = '\uD800';
|
||||
private static final char SURR_SECOND = '\uDF31';
|
||||
|
||||
private static final int[] NO_BREAK = new int[] {};
|
||||
|
||||
private static final TextPaint sTextPaint = new MockTextPaint();
|
||||
|
||||
private static class MockTextPaint extends TextPaint {
|
||||
|
||||
@Override
|
||||
public float getTextRunAdvances(char[] chars, int index, int count,
|
||||
int contextIndex, int contextCount, boolean isRtl, float[] advances,
|
||||
int advancesIndex) {
|
||||
|
||||
// Conditions copy pasted from Paint
|
||||
if (chars == null) {
|
||||
throw new IllegalArgumentException("text cannot be null");
|
||||
}
|
||||
|
||||
if ((index | count | contextIndex | contextCount | advancesIndex
|
||||
| (index - contextIndex) | (contextCount - count)
|
||||
| ((contextIndex + contextCount) - (index + count))
|
||||
| (chars.length - (contextIndex + contextCount))
|
||||
| (advances == null ? 0 :
|
||||
(advances.length - (advancesIndex + count)))) < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
float res = 0.0f;
|
||||
|
||||
if (advances != null) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
float width = getCharWidth(chars[index + i]);
|
||||
advances[advancesIndex + i] = width;
|
||||
res += width;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private static float getCharWidth(char c) {
|
||||
switch (Character.toUpperCase(c)) {
|
||||
// Roman figures
|
||||
case 'I': return 1.0f;
|
||||
case 'V': return 5.0f;
|
||||
case 'X': return 10.0f;
|
||||
case 'L': return 50.0f;
|
||||
case 'C': return 100.0f; // equals to WIDTH
|
||||
case ' ': return 10.0f;
|
||||
case '_': return 0.0f; // 0-width character
|
||||
case SURR_FIRST: return 7.0f;
|
||||
case SURR_SECOND: return 3.0f; // Sum of SURR_FIRST-SURR_SECOND is 10
|
||||
default: return 10.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private static StaticLayout getStaticLayout(CharSequence source, int width) {
|
||||
return new StaticLayout(source, sTextPaint, width, ALIGN, SPACE_MULTI, SPACE_ADD, false);
|
||||
}
|
||||
|
||||
private static int[] getBreaks(CharSequence source) {
|
||||
return getBreaks(source, WIDTH);
|
||||
}
|
||||
|
||||
private static int[] getBreaks(CharSequence source, int width) {
|
||||
StaticLayout staticLayout = getStaticLayout(source, width);
|
||||
|
||||
int[] breaks = new int[staticLayout.getLineCount() - 1];
|
||||
for (int line = 0; line < breaks.length; line++) {
|
||||
breaks[line] = staticLayout.getLineEnd(line);
|
||||
}
|
||||
return breaks;
|
||||
}
|
||||
|
||||
private static void debugLayout(CharSequence source, StaticLayout staticLayout) {
|
||||
if (DEBUG) {
|
||||
int count = staticLayout.getLineCount();
|
||||
Log.i("SLLBTest", "\"" + source.toString() + "\": "
|
||||
+ count + " lines");
|
||||
for (int line = 0; line < count; line++) {
|
||||
int lineStart = staticLayout.getLineStart(line);
|
||||
int lineEnd = staticLayout.getLineEnd(line);
|
||||
Log.i("SLLBTest", "Line " + line + " [" + lineStart + ".."
|
||||
+ lineEnd + "]\t" + source.subSequence(lineStart, lineEnd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void layout(CharSequence source, int[] breaks) {
|
||||
layout(source, breaks, WIDTH);
|
||||
}
|
||||
|
||||
private static void layout(CharSequence source, int[] breaks, int width) {
|
||||
StaticLayout staticLayout = getStaticLayout(source, width);
|
||||
|
||||
debugLayout(source, staticLayout);
|
||||
|
||||
int lineCount = breaks.length + 1;
|
||||
assertEquals("Number of lines", lineCount, staticLayout.getLineCount());
|
||||
|
||||
for (int line = 0; line < lineCount; line++) {
|
||||
int lineStart = staticLayout.getLineStart(line);
|
||||
int lineEnd = staticLayout.getLineEnd(line);
|
||||
|
||||
if (line == 0) {
|
||||
assertEquals("Line start for first line", 0, lineStart);
|
||||
} else {
|
||||
assertEquals("Line start for line " + line, breaks[line - 1], lineStart);
|
||||
}
|
||||
|
||||
if (line == lineCount - 1) {
|
||||
assertEquals("Line end for last line", source.length(), lineEnd);
|
||||
} else {
|
||||
assertEquals("Line end for line " + line, breaks[line], lineEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void layoutMaxLines(CharSequence source, int[] breaks, int maxLines) {
|
||||
StaticLayout staticLayout = new StaticLayout(source, 0, source.length(), sTextPaint, WIDTH,
|
||||
ALIGN, TextDirectionHeuristics.LTR, SPACE_MULTI, SPACE_ADD, false /* includePad */,
|
||||
null, WIDTH, maxLines);
|
||||
|
||||
debugLayout(source, staticLayout);
|
||||
|
||||
final int lineCount = staticLayout.getLineCount();
|
||||
|
||||
for (int line = 0; line < lineCount; line++) {
|
||||
int lineStart = staticLayout.getLineStart(line);
|
||||
int lineEnd = staticLayout.getLineEnd(line);
|
||||
|
||||
if (line == 0) {
|
||||
assertEquals("Line start for first line", 0, lineStart);
|
||||
} else {
|
||||
assertEquals("Line start for line " + line, breaks[line - 1], lineStart);
|
||||
}
|
||||
|
||||
if (line == lineCount - 1 && line != breaks.length - 1) {
|
||||
assertEquals("Line end for last line", source.length(), lineEnd);
|
||||
} else {
|
||||
assertEquals("Line end for line " + line, breaks[line], lineEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAX_SPAN_COUNT = 10;
|
||||
private static final int[] sSpanStarts = new int[MAX_SPAN_COUNT];
|
||||
private static final int[] sSpanEnds = new int[MAX_SPAN_COUNT];
|
||||
|
||||
private static MetricAffectingSpan getMetricAffectingSpan() {
|
||||
return new MetricAffectingSpan() {
|
||||
@Override
|
||||
public void updateDrawState(TextPaint tp) { /* empty */ }
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(TextPaint p) { /* empty */ }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the "<...>" blocks by spans, assuming non overlapping, correctly defined spans
|
||||
* @param text
|
||||
* @return A CharSequence with '<' '>' replaced by MetricAffectingSpan
|
||||
*/
|
||||
private static CharSequence spanify(String text) {
|
||||
int startIndex = text.indexOf('<');
|
||||
if (startIndex < 0) return text;
|
||||
|
||||
int spanCount = 0;
|
||||
do {
|
||||
int endIndex = text.indexOf('>');
|
||||
if (endIndex < 0) throw new IllegalArgumentException("Unbalanced span markers");
|
||||
|
||||
text = text.substring(0, startIndex) + text.substring(startIndex + 1, endIndex)
|
||||
+ text.substring(endIndex + 1);
|
||||
|
||||
sSpanStarts[spanCount] = startIndex;
|
||||
sSpanEnds[spanCount] = endIndex - 2;
|
||||
spanCount++;
|
||||
|
||||
startIndex = text.indexOf('<');
|
||||
} while (startIndex >= 0);
|
||||
|
||||
SpannableStringBuilder result = new SpannableStringBuilder(text);
|
||||
for (int i = 0; i < spanCount; i++) {
|
||||
result.setSpan(getMetricAffectingSpan(), sSpanStarts[i], sSpanEnds[i],
|
||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLineBreak() {
|
||||
// Width lower than WIDTH
|
||||
layout("", NO_BREAK);
|
||||
layout("I", NO_BREAK);
|
||||
layout("V", NO_BREAK);
|
||||
layout("X", NO_BREAK);
|
||||
layout("L", NO_BREAK);
|
||||
layout("I VILI", NO_BREAK);
|
||||
layout("XXXX", NO_BREAK);
|
||||
layout("LXXXX", NO_BREAK);
|
||||
|
||||
// Width equal to WIDTH
|
||||
layout("C", NO_BREAK);
|
||||
layout("LL", NO_BREAK);
|
||||
layout("L XXXX", NO_BREAK);
|
||||
layout("XXXXXXXXXX", NO_BREAK);
|
||||
layout("XXX XXXXXX", NO_BREAK);
|
||||
layout("XXX XXXX X", NO_BREAK);
|
||||
layout("XXX XXXXX ", NO_BREAK);
|
||||
layout(" XXXXXXXX ", NO_BREAK);
|
||||
layout(" XX XXX ", NO_BREAK);
|
||||
// 0123456789
|
||||
|
||||
// Width greater than WIDTH, but no break
|
||||
layout(" XX XXX ", NO_BREAK);
|
||||
layout("XX XXX XXX ", NO_BREAK);
|
||||
layout("XX XXX XXX ", NO_BREAK);
|
||||
layout("XXXXXXXXXX ", NO_BREAK);
|
||||
// 01234567890
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneLineBreak() {
|
||||
// 01234567890
|
||||
layout("XX XXX XXXX", new int[] {7});
|
||||
layout("XX XXXX XXX", new int[] {8});
|
||||
layout("XX XXXXX XX", new int[] {9});
|
||||
layout("XX XXXXXX X", new int[] {10});
|
||||
// 01234567890
|
||||
layout("XXXXXXXXXXX", new int[] {10});
|
||||
layout("XXXXXXXXX X", new int[] {10});
|
||||
layout("XXXXXXXX XX", new int[] {9});
|
||||
layout("XXXXXXX XXX", new int[] {8});
|
||||
layout("XXXXXX XXXX", new int[] {7});
|
||||
// 01234567890
|
||||
layout("LL LL", new int[] {3});
|
||||
layout("LLLL", new int[] {2});
|
||||
layout("C C", new int[] {2});
|
||||
layout("CC", new int[] {1});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpaceAtBreak() {
|
||||
// 0123456789012
|
||||
layout("XXXX XXXXX X", new int[] {11});
|
||||
layout("XXXXXXXXXX X", new int[] {11});
|
||||
layout("XXXXXXXXXV X", new int[] {11});
|
||||
layout("C X", new int[] {2});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleSpacesAtBreak() {
|
||||
// 0123456789012
|
||||
layout("LXX XXXX", new int[] {4});
|
||||
layout("LXX XXXX", new int[] {5});
|
||||
layout("LXX XXXX", new int[] {6});
|
||||
layout("LXX XXXX", new int[] {7});
|
||||
layout("LXX XXXX", new int[] {8});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroWidthCharacters() {
|
||||
// 0123456789012345678901234
|
||||
layout("X_X_X_X_X_X_X_X_X_X", NO_BREAK);
|
||||
layout("___X_X_X_X_X_X_X_X_X_X___", NO_BREAK);
|
||||
layout("C_X", new int[] {2});
|
||||
layout("C__X", new int[] {3});
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that when the text has spans, StaticLayout does not use the provided TextPaint to
|
||||
* measure text runs anymore. This is probably a bug.
|
||||
* To be able to use the fake sTextPaint and make this test pass, use mPaint instead of
|
||||
* mWorkPaint in MeasuredText#addStyleRun
|
||||
*/
|
||||
@Test
|
||||
public void testWithSpans() {
|
||||
if (!SPAN_TESTS_SUPPORTED) return;
|
||||
|
||||
layout(spanify("<012 456 89>"), NO_BREAK);
|
||||
layout(spanify("012 <456> 89"), NO_BREAK);
|
||||
layout(spanify("<012> <456>< 89>"), NO_BREAK);
|
||||
layout(spanify("<012> <456> <89>"), NO_BREAK);
|
||||
|
||||
layout(spanify("<012> <456> <89>012"), new int[] {8});
|
||||
layout(spanify("<012> <456> 89<012>"), new int[] {8});
|
||||
layout(spanify("<012> <456> <89><012>"), new int[] {8});
|
||||
layout(spanify("<012> <456> 89 <123>"), new int[] {11});
|
||||
layout(spanify("<012> <456> 89< 123>"), new int[] {11});
|
||||
layout(spanify("<012> <456> <89> <123>"), new int[] {11});
|
||||
layout(spanify("012 456 89 <LXX> XX XX"), new int[] {11, 18});
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding a span to the string should not change the layout, since the metrics are unchanged.
|
||||
*/
|
||||
@Test
|
||||
public void testWithOneSpan() {
|
||||
if (!SPAN_TESTS_SUPPORTED) return;
|
||||
|
||||
String[] texts = new String[] { "0123", "012 456", "012 456 89 123", "012 45678 012",
|
||||
"012 456 89012 456 89012", "0123456789012" };
|
||||
|
||||
MetricAffectingSpan metricAffectingSpan = getMetricAffectingSpan();
|
||||
|
||||
for (String text : texts) {
|
||||
// Get the line breaks without any span
|
||||
int[] breaks = getBreaks(text);
|
||||
|
||||
// Add spans on all possible offsets
|
||||
for (int spanStart = 0; spanStart < text.length(); spanStart++) {
|
||||
for (int spanEnd = spanStart; spanEnd < text.length(); spanEnd++) {
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
|
||||
ssb.setSpan(metricAffectingSpan, spanStart, spanEnd,
|
||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
layout(ssb, breaks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithTwoSpans() {
|
||||
if (!SPAN_TESTS_SUPPORTED) return;
|
||||
|
||||
String[] texts = new String[] { "0123", "012 456", "012 456 89 123", "012 45678 012",
|
||||
"012 456 89012 456 89012", "0123456789012" };
|
||||
|
||||
MetricAffectingSpan metricAffectingSpan1 = getMetricAffectingSpan();
|
||||
MetricAffectingSpan metricAffectingSpan2 = getMetricAffectingSpan();
|
||||
|
||||
for (String text : texts) {
|
||||
// Get the line breaks without any span
|
||||
int[] breaks = getBreaks(text);
|
||||
|
||||
// Add spans on all possible offsets
|
||||
for (int spanStart1 = 0; spanStart1 < text.length(); spanStart1++) {
|
||||
for (int spanEnd1 = spanStart1; spanEnd1 < text.length(); spanEnd1++) {
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
|
||||
ssb.setSpan(metricAffectingSpan1, spanStart1, spanEnd1,
|
||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
for (int spanStart2 = 0; spanStart2 < text.length(); spanStart2++) {
|
||||
for (int spanEnd2 = spanStart2; spanEnd2 < text.length(); spanEnd2++) {
|
||||
ssb.setSpan(metricAffectingSpan2, spanStart2, spanEnd2,
|
||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
layout(ssb, breaks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String replace(String string, char c, char r) {
|
||||
return string.replaceAll(String.valueOf(c), String.valueOf(r));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithSurrogate() {
|
||||
layout("LX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
|
||||
layout("LXXXX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
|
||||
// LXXXXI (91) + SURR_FIRST (7) fits. But we should not break the surrogate pair
|
||||
// Bug: surrogate pair is broken, should be 6 (breaking after the 'V')
|
||||
// Maybe not: may be ok if the second character of a pair always has a 0-width
|
||||
layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {7});
|
||||
|
||||
// LXXXXI (95) + SURR_SECOND (3) fits, but this is not a valid surrogate pair, breaking it
|
||||
layout("LXXXXV" + SURR_SECOND + SURR_FIRST, new int[] {7});
|
||||
|
||||
layout("C" + SURR_FIRST + SURR_SECOND, new int[] {1});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNarrowWidth() {
|
||||
int[] widths = new int[] { 0, 4, 10 };
|
||||
String[] texts = new String[] { "", "X", " ", "XX", " X", "XXX" };
|
||||
|
||||
for (String text: texts) {
|
||||
// 15 is such that only one character will fit
|
||||
int[] breaks = getBreaks(text, 15);
|
||||
|
||||
// Width under 15 should all lead to the same line break
|
||||
for (int width: widths) {
|
||||
layout(text, breaks, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNarrowWidthZeroWidth() {
|
||||
int[] widths = new int[] { 1, 4 };
|
||||
for (int width: widths) {
|
||||
layout("X.", new int[] {1}, width);
|
||||
layout("X__", NO_BREAK, width);
|
||||
layout("X__X", new int[] {3}, width);
|
||||
layout("X__X_", new int[] {3}, width);
|
||||
|
||||
layout("_", NO_BREAK, width);
|
||||
layout("__", NO_BREAK, width);
|
||||
layout("_X", new int[] {1}, width);
|
||||
layout("_X_", new int[] {1}, width);
|
||||
layout("__X__", new int[] {2}, width);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxLines() {
|
||||
layoutMaxLines("C", NO_BREAK, 1);
|
||||
layoutMaxLines("C C", new int[] {2}, 1);
|
||||
layoutMaxLines("C C", new int[] {2}, 2);
|
||||
layoutMaxLines("CC", new int[] {1}, 1);
|
||||
layoutMaxLines("CC", new int[] {1}, 2);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,9 @@
|
||||
package android.text;
|
||||
|
||||
import static android.text.Layout.Alignment.ALIGN_NORMAL;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.support.test.filters.SmallTest;
|
||||
@@ -26,15 +28,68 @@ import android.text.Layout.Alignment;
|
||||
import android.text.method.EditorState;
|
||||
import android.util.Log;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.text.Normalizer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests StaticLayout vertical metrics behavior.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StaticLayoutTest {
|
||||
private static final float SPACE_MULTI = 1.0f;
|
||||
private static final float SPACE_ADD = 0.0f;
|
||||
private static final int DEFAULT_OUTER_WIDTH = 150;
|
||||
|
||||
private static final CharSequence LAYOUT_TEXT = "CharSe\tq\nChar"
|
||||
+ "Sequence\nCharSequence\nHelllo\n, world\nLongLongLong";
|
||||
private static final CharSequence LAYOUT_TEXT_SINGLE_LINE = "CharSequence";
|
||||
|
||||
private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_CENTER;
|
||||
private static final int ELLIPSIZE_WIDTH = 8;
|
||||
|
||||
private StaticLayout mDefaultLayout;
|
||||
private TextPaint mDefaultPaint;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mDefaultPaint = new TextPaint();
|
||||
mDefaultLayout = createDefaultStaticLayout();
|
||||
}
|
||||
|
||||
private StaticLayout createDefaultStaticLayout() {
|
||||
return new StaticLayout(LAYOUT_TEXT, mDefaultPaint,
|
||||
DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilder() {
|
||||
{
|
||||
// Obtain.
|
||||
final StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
|
||||
LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
|
||||
final StaticLayout layout = builder.build();
|
||||
// Check default value.
|
||||
assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
layout.getTextDirectionHeuristic());
|
||||
}
|
||||
{
|
||||
// setTextDirection.
|
||||
final StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
|
||||
LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
|
||||
builder.setTextDirection(TextDirectionHeuristics.RTL);
|
||||
final StaticLayout layout = builder.build();
|
||||
// Always returns TextDirectionHeuristics.FIRSTSTRONG_LTR.
|
||||
assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
layout.getTextDirectionHeuristic());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic test showing expected behavior and relationship between font
|
||||
* metrics and line metrics.
|
||||
@@ -410,4 +465,210 @@ public class StaticLayoutTest {
|
||||
state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
|
||||
moveCursorToLeftCursorableOffset(state, paint);
|
||||
}
|
||||
|
||||
private StaticLayout createEllipsizeStaticLayout(CharSequence text,
|
||||
TextUtils.TruncateAt ellipsize, int maxLines) {
|
||||
return new StaticLayout(text, 0, text.length(),
|
||||
mDefaultPaint, DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN,
|
||||
TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, true /* include pad */,
|
||||
ellipsize,
|
||||
ELLIPSIZE_WIDTH,
|
||||
maxLines);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEllipsis_singleLine() {
|
||||
{
|
||||
// Single line case and TruncateAt.END so that we have some ellipsis
|
||||
StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE,
|
||||
TextUtils.TruncateAt.END, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
}
|
||||
{
|
||||
// Single line case and TruncateAt.MIDDLE so that we have some ellipsis
|
||||
StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE,
|
||||
TextUtils.TruncateAt.MIDDLE, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
}
|
||||
{
|
||||
// Single line case and TruncateAt.END so that we have some ellipsis
|
||||
StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE,
|
||||
TextUtils.TruncateAt.END, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
}
|
||||
{
|
||||
// Single line case and TruncateAt.MARQUEE so that we have NO ellipsis
|
||||
StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE,
|
||||
TextUtils.TruncateAt.MARQUEE, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) == 0);
|
||||
}
|
||||
{
|
||||
final String text = "\u3042" // HIRAGANA LETTER A
|
||||
+ "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
|
||||
final float textWidth = mDefaultPaint.measureText(text);
|
||||
final int halfWidth = (int) (textWidth / 2.0f);
|
||||
{
|
||||
StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
|
||||
halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.END, halfWidth, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
assertTrue(layout.getEllipsisStart(0) > 0);
|
||||
}
|
||||
{
|
||||
StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
|
||||
halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.START, halfWidth, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
assertEquals(0, mDefaultLayout.getEllipsisStart(0));
|
||||
}
|
||||
{
|
||||
StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
|
||||
halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MIDDLE, halfWidth, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
assertTrue(layout.getEllipsisStart(0) > 0);
|
||||
}
|
||||
{
|
||||
StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
|
||||
halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MARQUEE, halfWidth, 1);
|
||||
assertEquals(0, layout.getEllipsisCount(0));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// The white spaces in this text will be trailing if maxLines is larger than 1, but
|
||||
// width of the trailing white spaces must not be ignored if ellipsis is applied.
|
||||
final String text = "abc def";
|
||||
final float textWidth = mDefaultPaint.measureText(text);
|
||||
final int halfWidth = (int) (textWidth / 2.0f);
|
||||
{
|
||||
StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
|
||||
halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.END, halfWidth, 1);
|
||||
assertTrue(layout.getEllipsisCount(0) > 0);
|
||||
assertTrue(layout.getEllipsisStart(0) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// 2 family emojis (11 code units + 11 code units).
|
||||
final String text = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66"
|
||||
+ "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66";
|
||||
final float textWidth = mDefaultPaint.measureText(text);
|
||||
|
||||
final TextUtils.TruncateAt[] kinds = {TextUtils.TruncateAt.START,
|
||||
TextUtils.TruncateAt.MIDDLE, TextUtils.TruncateAt.END};
|
||||
for (final TextUtils.TruncateAt kind : kinds) {
|
||||
for (int i = 0; i <= 8; i++) {
|
||||
int avail = (int) (textWidth * i / 7.0f);
|
||||
StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
|
||||
avail, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
SPACE_MULTI, SPACE_ADD, false, kind, avail, 1);
|
||||
|
||||
assertTrue(layout.getEllipsisCount(0) == text.length()
|
||||
|| layout.getEllipsisCount(0) == text.length() / 2
|
||||
|| layout.getEllipsisCount(0) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String wrapper for testing not well known implementation of CharSequence.
|
||||
private class FakeCharSequence implements CharSequence {
|
||||
private String mStr;
|
||||
|
||||
FakeCharSequence(String str) {
|
||||
mStr = str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return mStr.charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return mStr.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return mStr.subSequence(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mStr;
|
||||
}
|
||||
};
|
||||
|
||||
private List<CharSequence> buildTestCharSequences(String testString, Normalizer.Form[] forms) {
|
||||
List<CharSequence> result = new ArrayList<>();
|
||||
|
||||
List<String> normalizedStrings = new ArrayList<>();
|
||||
for (Normalizer.Form form: forms) {
|
||||
normalizedStrings.add(Normalizer.normalize(testString, form));
|
||||
}
|
||||
|
||||
for (String str: normalizedStrings) {
|
||||
result.add(str);
|
||||
result.add(new SpannedString(str));
|
||||
result.add(new SpannableString(str));
|
||||
result.add(new SpannableStringBuilder(str)); // as a GraphicsOperations implementation.
|
||||
result.add(new FakeCharSequence(str)); // as a not well known implementation.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String buildTestMessage(CharSequence seq) {
|
||||
String normalized;
|
||||
if (Normalizer.isNormalized(seq, Normalizer.Form.NFC)) {
|
||||
normalized = "NFC";
|
||||
} else if (Normalizer.isNormalized(seq, Normalizer.Form.NFD)) {
|
||||
normalized = "NFD";
|
||||
} else if (Normalizer.isNormalized(seq, Normalizer.Form.NFKC)) {
|
||||
normalized = "NFKC";
|
||||
} else if (Normalizer.isNormalized(seq, Normalizer.Form.NFKD)) {
|
||||
normalized = "NFKD";
|
||||
} else {
|
||||
throw new IllegalStateException("Normalized form is not NFC/NFD/NFKC/NFKD");
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < seq.length(); ++i) {
|
||||
builder.append(String.format("0x%04X ", Integer.valueOf(seq.charAt(i))));
|
||||
}
|
||||
|
||||
return "testString: \"" + seq.toString() + "\"[" + builder.toString() + "]"
|
||||
+ ", class: " + seq.getClass().getName()
|
||||
+ ", Normalization: " + normalized;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOffset_UNICODE_Hebrew() {
|
||||
String testString = "\u05DE\u05E1\u05E2\u05D3\u05D4"; // Hebrew Characters
|
||||
for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
|
||||
StaticLayout layout = new StaticLayout(seq, mDefaultPaint,
|
||||
DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN,
|
||||
TextDirectionHeuristics.RTL, SPACE_MULTI, SPACE_ADD, true);
|
||||
|
||||
String testLabel = buildTestMessage(seq);
|
||||
|
||||
assertEquals(testLabel, 1, layout.getOffsetToLeftOf(0));
|
||||
assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1));
|
||||
assertEquals(testLabel, 3, layout.getOffsetToLeftOf(2));
|
||||
assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3));
|
||||
assertEquals(testLabel, 5, layout.getOffsetToLeftOf(4));
|
||||
assertEquals(testLabel, 5, layout.getOffsetToLeftOf(5));
|
||||
|
||||
assertEquals(testLabel, 0, layout.getOffsetToRightOf(0));
|
||||
assertEquals(testLabel, 0, layout.getOffsetToRightOf(1));
|
||||
assertEquals(testLabel, 1, layout.getOffsetToRightOf(2));
|
||||
assertEquals(testLabel, 2, layout.getOffsetToRightOf(3));
|
||||
assertEquals(testLabel, 3, layout.getOffsetToRightOf(4));
|
||||
assertEquals(testLabel, 4, layout.getOffsetToRightOf(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,16 @@ import android.os.LocaleList;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DateUtilsTest {
|
||||
@@ -103,6 +107,42 @@ public class DateUtilsTest {
|
||||
assertEquals("48h", DateUtils.formatDuration(172800000, DateUtils.LENGTH_SHORTEST));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatSameDayTime() {
|
||||
// This test assumes a default DateFormat.is24Hour setting.
|
||||
DateFormat.is24Hour = null;
|
||||
Date date = new Date(109, 0, 19, 3, 30, 15);
|
||||
long fixedTime = date.getTime();
|
||||
|
||||
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
|
||||
Date dateWithCurrentYear = new Date(currentYear - 1900, 0, 19, 3, 30, 15);
|
||||
|
||||
final long dayDuration = 5 * 24 * 60 * 60 * 1000;
|
||||
assertEquals("Saturday, January 24, 2009", DateUtils.formatSameDayTime(
|
||||
fixedTime + dayDuration, fixedTime, java.text.DateFormat.FULL,
|
||||
java.text.DateFormat.FULL));
|
||||
assertEquals("Jan 24, 2009", DateUtils.formatSameDayTime(fixedTime + dayDuration,
|
||||
fixedTime, java.text.DateFormat.DEFAULT, java.text.DateFormat.FULL));
|
||||
assertEquals("January 24, 2009", DateUtils.formatSameDayTime(fixedTime + dayDuration,
|
||||
fixedTime, java.text.DateFormat.LONG, java.text.DateFormat.FULL));
|
||||
assertEquals("Jan 24, 2009", DateUtils.formatSameDayTime(fixedTime + dayDuration,
|
||||
fixedTime, java.text.DateFormat.MEDIUM, java.text.DateFormat.FULL));
|
||||
assertEquals("1/24/09", DateUtils.formatSameDayTime(fixedTime + dayDuration,
|
||||
fixedTime, java.text.DateFormat.SHORT, java.text.DateFormat.FULL));
|
||||
|
||||
final long hourDuration = 2 * 60 * 60 * 1000;
|
||||
assertEquals("5:30:15 AM GMT+00:00", DateUtils.formatSameDayTime(fixedTime + hourDuration,
|
||||
fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.FULL));
|
||||
assertEquals("5:30:15 AM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
|
||||
fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.DEFAULT));
|
||||
assertEquals("5:30:15 AM GMT+00:00", DateUtils.formatSameDayTime(fixedTime + hourDuration,
|
||||
fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.LONG));
|
||||
assertEquals("5:30:15 AM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
|
||||
fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.MEDIUM));
|
||||
assertEquals("5:30 AM", DateUtils.formatSameDayTime(fixedTime + hourDuration,
|
||||
fixedTime, java.text.DateFormat.FULL, java.text.DateFormat.SHORT));
|
||||
}
|
||||
|
||||
private void setLocales(LocaleList locales) {
|
||||
final Resources systemResources = Resources.getSystem();
|
||||
final Configuration config = new Configuration(systemResources.getConfiguration());
|
||||
|
||||
@@ -21,19 +21,131 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
import java.util.Locale;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
// TODO(Bug: 24062099): Add more tests for non-ascii text.
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WordIteratorTest {
|
||||
|
||||
private WordIterator mWordIterator = new WordIterator();
|
||||
|
||||
private void verifyIsWordWithSurrogate(int beginning, int end, int surrogateIndex) {
|
||||
for (int i = beginning; i <= end; i++) {
|
||||
if (i == surrogateIndex) continue;
|
||||
assertEquals(beginning, mWordIterator.getBeginning(i));
|
||||
assertEquals(end, mWordIterator.getEnd(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void setCharSequence(String string) {
|
||||
mWordIterator.setCharSequence(string, 0, string.length());
|
||||
}
|
||||
|
||||
private void verifyIsWord(int beginning, int end) {
|
||||
verifyIsWordWithSurrogate(beginning, end, -1);
|
||||
}
|
||||
|
||||
private void verifyIsNotWord(int beginning, int end) {
|
||||
for (int i = beginning; i <= end; i++) {
|
||||
assertEquals(BreakIterator.DONE, mWordIterator.getBeginning(i));
|
||||
assertEquals(BreakIterator.DONE, mWordIterator.getEnd(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyString() {
|
||||
setCharSequence("");
|
||||
assertEquals(BreakIterator.DONE, mWordIterator.following(0));
|
||||
assertEquals(BreakIterator.DONE, mWordIterator.preceding(0));
|
||||
|
||||
assertEquals(BreakIterator.DONE, mWordIterator.getBeginning(0));
|
||||
assertEquals(BreakIterator.DONE, mWordIterator.getEnd(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneWord() {
|
||||
setCharSequence("I");
|
||||
verifyIsWord(0, 1);
|
||||
|
||||
setCharSequence("am");
|
||||
verifyIsWord(0, 2);
|
||||
|
||||
setCharSequence("zen");
|
||||
verifyIsWord(0, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpacesOnly() {
|
||||
setCharSequence(" ");
|
||||
verifyIsNotWord(0, 1);
|
||||
|
||||
setCharSequence(", ");
|
||||
verifyIsNotWord(0, 2);
|
||||
|
||||
setCharSequence(":-)");
|
||||
verifyIsNotWord(0, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeginningEnd() {
|
||||
setCharSequence("Well hello, there! ");
|
||||
// 0123456789012345678901
|
||||
verifyIsWord(0, 4);
|
||||
verifyIsWord(5, 10);
|
||||
verifyIsNotWord(11, 13);
|
||||
verifyIsWord(14, 19);
|
||||
verifyIsNotWord(20, 21);
|
||||
|
||||
setCharSequence(" Another - sentence");
|
||||
// 012345678901234567890
|
||||
verifyIsNotWord(0, 1);
|
||||
verifyIsWord(2, 9);
|
||||
verifyIsNotWord(10, 11);
|
||||
verifyIsWord(12, 20);
|
||||
|
||||
setCharSequence("This is \u0644\u0627 tested"); // Lama-aleph
|
||||
// 012345678 9 01234567
|
||||
verifyIsWord(0, 4);
|
||||
verifyIsWord(5, 7);
|
||||
verifyIsWord(8, 10);
|
||||
verifyIsWord(11, 17);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSurrogate() {
|
||||
final String gothicBairkan = "\uD800\uDF31";
|
||||
|
||||
setCharSequence("one we" + gothicBairkan + "ird word");
|
||||
// 012345 67 890123456
|
||||
|
||||
verifyIsWord(0, 3);
|
||||
// Skip index 7 (there is no point in starting between the two surrogate characters)
|
||||
verifyIsWordWithSurrogate(4, 11, 7);
|
||||
verifyIsWord(12, 16);
|
||||
|
||||
setCharSequence("one " + gothicBairkan + "xxx word");
|
||||
// 0123 45 678901234
|
||||
|
||||
verifyIsWord(0, 3);
|
||||
verifyIsWordWithSurrogate(4, 9, 5);
|
||||
verifyIsWord(10, 14);
|
||||
|
||||
setCharSequence("one xxx" + gothicBairkan + " word");
|
||||
// 0123456 78 901234
|
||||
|
||||
verifyIsWord(0, 3);
|
||||
verifyIsWordWithSurrogate(4, 9, 8);
|
||||
verifyIsWord(10, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCharSequence() {
|
||||
final String text = "text";
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UnderlineSpanTest {
|
||||
private class RedUnderlineSpan extends UnderlineSpan {
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
ds.setUnderlineText(android.graphics.Color.RED, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Identical to the normal UnderlineSpan test, except that a subclass of UnderlineSpan is used
|
||||
// that draws a red underline. This shouldn't affect width either.
|
||||
@Test
|
||||
public void testDoesntAffectWidth_colorUnderlineSubclass() {
|
||||
// Roboto kerns between "P" and "."
|
||||
final SpannableString text = new SpannableString("P.");
|
||||
final float origLineWidth = textWidth(text);
|
||||
// Underline just the "P".
|
||||
text.setSpan(new RedUnderlineSpan(), 0, 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
final float underlinedLineWidth = textWidth(text);
|
||||
assertEquals(origLineWidth, underlinedLineWidth, 0.0f);
|
||||
}
|
||||
|
||||
// Measures the width of some potentially-spanned text, assuming it's not too wide.
|
||||
private float textWidth(CharSequence text) {
|
||||
final TextPaint tp = new TextPaint();
|
||||
tp.setTextSize(100.0f); // Large enough so that the difference in kerning is visible.
|
||||
final int largeWidth = 10000; // Enough width so the whole text fits in one line.
|
||||
final StaticLayout layout = StaticLayout.Builder.obtain(
|
||||
text, 0, text.length(), tp, largeWidth).build();
|
||||
return layout.getLineWidth(0);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.text.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -25,15 +26,20 @@ import android.os.LocaleList;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.Patterns;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* LinkifyTest tests {@link Linkify}.
|
||||
*/
|
||||
@@ -98,4 +104,49 @@ public class LinkifyTest {
|
||||
overrideConfig.setLocales(LOCALE_LIST_US);
|
||||
return mContext.createConfigurationContext(overrideConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLinks_addsLinksWhenDefaultSchemeIsNull() {
|
||||
Spannable spannable = new SpannableString("any https://android.com any android.com any");
|
||||
Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, null, null, null);
|
||||
|
||||
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
|
||||
assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
|
||||
assertEquals("https://android.com", spans[0].getURL());
|
||||
assertEquals("android.com", spans[1].getURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLinks_addsLinksWhenSchemesArrayIsNull() {
|
||||
Spannable spannable = new SpannableString("any https://android.com any android.com any");
|
||||
Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://", null, null);
|
||||
|
||||
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
|
||||
assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
|
||||
// expected behavior, passing null schemes array means: prepend defaultScheme to all links.
|
||||
assertEquals("http://https://android.com", spans[0].getURL());
|
||||
assertEquals("http://android.com", spans[1].getURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLinks_prependsDefaultSchemeToBeginingOfLink() {
|
||||
Spannable spannable = new SpannableString("any android.com any");
|
||||
Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://",
|
||||
new String[] { "http://", "https://"}, null, null);
|
||||
|
||||
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
|
||||
assertEquals("android.com should be linkified", 1, spans.length);
|
||||
assertEquals("http://android.com", spans[0].getURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLinks_doesNotPrependSchemeIfSchemeExists() {
|
||||
Spannable spannable = new SpannableString("any https://android.com any");
|
||||
Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://",
|
||||
new String[] { "http://", "https://"}, null, null);
|
||||
|
||||
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
|
||||
assertEquals("android.com should be linkified", 1, spans.length);
|
||||
assertEquals("https://android.com", spans[0].getURL());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user