diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java new file mode 100644 index 0000000000000..47dd257b06b5c --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java @@ -0,0 +1,150 @@ +/* + * 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; + +import static android.text.Layout.Alignment.ALIGN_NORMAL; + +import android.graphics.Canvas; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.filters.LargeTest; +import android.text.NonEditableTextGenerator.TextType; +import android.view.DisplayListCanvas; +import android.view.RenderNode; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +/** + * Performance test for {@link BoringLayout} create and draw. + */ +@LargeTest +@RunWith(Parameterized.class) +public class BoringLayoutCreateDrawPerfTest { + + private static final boolean[] BOOLEANS = new boolean[]{false, true}; + private static final float SPACING_ADD = 10f; + private static final float SPACING_MULT = 1.5f; + + @Parameterized.Parameters(name = "cached={3},{1} chars,{0}") + public static Collection cases() { + final List params = new ArrayList<>(); + for (int length : new int[]{128}) { + for (boolean cached : BOOLEANS) { + for (TextType textType : new TextType[]{TextType.STRING, + TextType.SPANNABLE_BUILDER}) { + params.add(new Object[]{textType.name(), length, textType, cached}); + } + } + } + return params; + } + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + private final int mLength; + private final TextType mTextType; + private final boolean mCached; + private final TextPaint mTextPaint; + + public BoringLayoutCreateDrawPerfTest(String label, int length, TextType textType, + boolean cached) { + mLength = length; + mCached = cached; + mTextType = textType; + mTextPaint = new TextPaint(); + mTextPaint.setTextSize(10); + } + + /** + * Measures the creation time for {@link BoringLayout}. + */ + @Test + public void timeCreate() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final CharSequence text = createRandomText(); + // isBoring result is calculated in another test, we want to measure only the + // create time for Boring without isBoring check. Therefore it is calculated here. + final BoringLayout.Metrics metrics = BoringLayout.isBoring(text, mTextPaint); + if (mCached) createLayout(text, metrics); + state.resumeTiming(); + + while (state.keepRunning()) { + state.pauseTiming(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + createLayout(text, metrics); + } + } + + /** + * Measures the draw time for {@link BoringLayout} or {@link StaticLayout}. + */ + @Test + public void timeDraw() throws Throwable { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final RenderNode node = RenderNode.create("benchmark", null); + final CharSequence text = createRandomText(); + final BoringLayout.Metrics metrics = BoringLayout.isBoring(text, mTextPaint); + final Layout layout = createLayout(text, metrics); + state.resumeTiming(); + + while (state.keepRunning()) { + + state.pauseTiming(); + final DisplayListCanvas canvas = node.start(1200, 200); + final int save = canvas.save(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + layout.draw(canvas); + + state.pauseTiming(); + canvas.restoreToCount(save); + node.end(canvas); + state.resumeTiming(); + } + } + + private CharSequence createRandomText() { + return new NonEditableTextGenerator(new Random(0)) + .setSequenceLength(mLength) + .setCreateBoring(true) + .setTextType(mTextType) + .build(); + } + + private Layout createLayout(CharSequence text, + BoringLayout.Metrics metrics) { + return BoringLayout.make(text, mTextPaint, Integer.MAX_VALUE /*width*/, + ALIGN_NORMAL, SPACING_MULT, SPACING_ADD, metrics, true /*includePad*/); + } +} diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java new file mode 100644 index 0000000000000..34de65de2627c --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java @@ -0,0 +1,109 @@ +/* + * 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; + +import android.graphics.Canvas; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.filters.LargeTest; +import android.text.NonEditableTextGenerator.TextType; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +/** + * Performance test for {@link BoringLayout#isBoring(CharSequence, TextPaint)}. + */ +@LargeTest +@RunWith(Parameterized.class) +public class BoringLayoutIsBoringPerfTest { + + private static final boolean[] BOOLEANS = new boolean[]{false, true}; + + @Parameterized.Parameters(name = "cached={4},{1} chars,{0}") + public static Collection cases() { + final List params = new ArrayList<>(); + for (int length : new int[]{128}) { + for (boolean boring : BOOLEANS) { + for (boolean cached : BOOLEANS) { + for (TextType textType : new TextType[]{TextType.STRING, + TextType.SPANNABLE_BUILDER}) { + params.add(new Object[]{ + (boring ? "Boring" : "NotBoring") + "," + textType.name(), + length, boring, textType, cached}); + } + } + } + } + return params; + } + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + private final int mLength; + private final TextType mTextType; + private final boolean mCreateBoring; + private final boolean mCached; + private final TextPaint mTextPaint; + + public BoringLayoutIsBoringPerfTest(String label, int length, boolean boring, TextType textType, + boolean cached) { + mLength = length; + mCreateBoring = boring; + mCached = cached; + mTextType = textType; + mTextPaint = new TextPaint(); + mTextPaint.setTextSize(10); + } + + /** + * Measure the time for the {@link BoringLayout#isBoring(CharSequence, TextPaint)}. + */ + @Test + public void timeIsBoring() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final CharSequence text = createRandomText(); + if (mCached) BoringLayout.isBoring(text, mTextPaint); + state.resumeTiming(); + + while (state.keepRunning()) { + state.pauseTiming(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + BoringLayout.isBoring(text, mTextPaint); + } + } + + private CharSequence createRandomText() { + return new NonEditableTextGenerator(new Random(0)) + .setSequenceLength(mLength) + .setCreateBoring(mCreateBoring) + .setTextType(mTextType) + .build(); + } +} diff --git a/apct-tests/perftests/core/src/android/text/NonEditableTextGenerator.java b/apct-tests/perftests/core/src/android/text/NonEditableTextGenerator.java new file mode 100644 index 0000000000000..7c0cf0eebc790 --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/NonEditableTextGenerator.java @@ -0,0 +1,138 @@ +package android.text; + +import static android.text.Spanned.SPAN_INCLUSIVE_INCLUSIVE; + +import android.text.style.BulletSpan; + +import java.util.Random; + +/** + * + */ +public class NonEditableTextGenerator { + + enum TextType { + STRING, + SPANNED, + SPANNABLE_BUILDER + } + + private boolean mCreateBoring; + private TextType mTextType; + private int mSequenceLength; + private final Random mRandom; + + public NonEditableTextGenerator(Random random) { + mRandom = random; + } + + public NonEditableTextGenerator setCreateBoring(boolean createBoring) { + mCreateBoring = createBoring; + return this; + } + + public NonEditableTextGenerator setTextType(TextType textType) { + mTextType = textType; + return this; + } + + public NonEditableTextGenerator setSequenceLength(int sequenceLength) { + mSequenceLength = sequenceLength; + return this; + } + + /** + * Sample charSequence generated: + * NRjPzjvUadHmH ExoEoTqfx pCLw qtndsqfpk AqajVCbgjGZ igIeC dfnXRgA + */ + public CharSequence build() { + final RandomCharSequenceGenerator sequenceGenerator = new RandomCharSequenceGenerator( + mRandom); + if (mSequenceLength > 0) { + sequenceGenerator.setSequenceLength(mSequenceLength); + } + + final CharSequence charSequence = sequenceGenerator.buildLatinSequence(); + + switch (mTextType) { + case SPANNED: + case SPANNABLE_BUILDER: + return createSpannable(charSequence); + case STRING: + default: + return createString(charSequence); + } + } + + private Spannable createSpannable(CharSequence charSequence) { + final Spannable spannable = (mTextType == TextType.SPANNABLE_BUILDER) ? + new SpannableStringBuilder(charSequence) : new SpannableString(charSequence); + + if (!mCreateBoring) { + // add a paragraph style to make it non boring + spannable.setSpan(new BulletSpan(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE); + } + + spannable.setSpan(new Object(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE); + spannable.setSpan(new Object(), 0, 1, SPAN_INCLUSIVE_INCLUSIVE); + + return spannable; + } + + private String createString(CharSequence charSequence) { + if (mCreateBoring) { + return charSequence.toString(); + } else { + // BoringLayout checks to see if there is a surrogate pair and if so tells that + // the charSequence is not suitable for boring. Add an emoji to make it non boring. + // Emoji is added instead of RTL, since emoji stays in the same run and is a more + // common case. + return charSequence.toString() + "\uD83D\uDC68\uD83C\uDFFF"; + } + } + + public static class RandomCharSequenceGenerator { + + private static final int DEFAULT_MIN_WORD_LENGTH = 3; + private static final int DEFAULT_MAX_WORD_LENGTH = 15; + private static final int DEFAULT_SEQUENCE_LENGTH = 256; + + private int mMinWordLength = DEFAULT_MIN_WORD_LENGTH; + private int mMaxWordLength = DEFAULT_MAX_WORD_LENGTH; + private int mSequenceLength = DEFAULT_SEQUENCE_LENGTH; + private final Random mRandom; + + public RandomCharSequenceGenerator(Random random) { + mRandom = random; + } + + public RandomCharSequenceGenerator setSequenceLength(int sequenceLength) { + mSequenceLength = sequenceLength; + return this; + } + + public CharSequence buildLatinSequence() { + final StringBuilder result = new StringBuilder(); + while (result.length() < mSequenceLength) { + // add random word + result.append(buildLatinWord()); + result.append(' '); + } + return result.substring(0, mSequenceLength); + } + + public CharSequence buildLatinWord() { + final StringBuilder result = new StringBuilder(); + // create a random length that is (mMinWordLength + random amount of chars) where + // total size is less than mMaxWordLength + final int length = mRandom.nextInt(mMaxWordLength - mMinWordLength) + mMinWordLength; + while (result.length() < length) { + // add random letter + int base = mRandom.nextInt(2) == 0 ? 'A' : 'a'; + result.append(Character.toChars(mRandom.nextInt(26) + base)); + } + return result.toString(); + } + } + +} diff --git a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java new file mode 100644 index 0000000000000..00b60add5b15d --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java @@ -0,0 +1,131 @@ +/* + * 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; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.filters.LargeTest; +import android.view.DisplayListCanvas; +import android.view.RenderNode; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +/** + * Performance test for single line measure and draw using {@link Paint} and {@link Canvas}. + */ +@LargeTest +@RunWith(Parameterized.class) +public class PaintMeasureDrawPerfTest { + + private static final boolean[] BOOLEANS = new boolean[]{false, true}; + + @Parameterized.Parameters(name = "cached={1},{0} chars") + public static Collection cases() { + final List params = new ArrayList<>(); + for (int length : new int[]{128}) { + for (boolean cached : BOOLEANS) { + params.add(new Object[]{length, cached}); + } + } + return params; + } + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + private final int mLength; + private final boolean mCached; + private final TextPaint mTextPaint; + + + public PaintMeasureDrawPerfTest(int length, boolean cached) { + mLength = length; + mCached = cached; + mTextPaint = new TextPaint(); + mTextPaint.setTextSize(10); + } + + /** + * Measure the time for {@link Paint#measureText(String)} + */ + @Test + public void timeMeasure() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final String text = createRandomText(); + if (mCached) mTextPaint.measureText(text); + state.resumeTiming(); + + while (state.keepRunning()) { + state.pauseTiming(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + mTextPaint.measureText(text); + } + } + + /** + * Measures the time for {@link Canvas#drawText(String, float, float, Paint)} + */ + @Test + public void timeDraw() throws Throwable { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final RenderNode node = RenderNode.create("benchmark", null); + final String text = createRandomText(); + if (mCached) mTextPaint.measureText(text); + state.resumeTiming(); + + while (state.keepRunning()) { + + state.pauseTiming(); + final DisplayListCanvas canvas = node.start(1200, 200); + final int save = canvas.save(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + canvas.drawText(text, 0 /*x*/, 100 /*y*/, mTextPaint); + + state.pauseTiming(); + canvas.restoreToCount(save); + node.end(canvas); + state.resumeTiming(); + } + } + + private String createRandomText() { + return (String) new NonEditableTextGenerator(new Random(0)) + .setSequenceLength(mLength) + .setCreateBoring(true) + .setTextType(NonEditableTextGenerator.TextType.STRING) + .build(); + } +} diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java new file mode 100644 index 0000000000000..356e2e0dab3c9 --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java @@ -0,0 +1,151 @@ +/* + * 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; + +import static android.text.Layout.Alignment.ALIGN_NORMAL; + +import android.graphics.Canvas; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.filters.LargeTest; +import android.text.NonEditableTextGenerator.TextType; +import android.view.DisplayListCanvas; +import android.view.RenderNode; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +/** + * Performance test for multi line, single style {@link StaticLayout} creation/draw. + */ +@LargeTest +@RunWith(Parameterized.class) +public class StaticLayoutCreateDrawPerfTest { + + private static final boolean[] BOOLEANS = new boolean[]{false, true}; + + private static final float SPACING_ADD = 10f; + private static final float SPACING_MULT = 1.5f; + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Parameterized.Parameters(name = "cached={3},{1} chars,{0}") + public static Collection cases() { + final List params = new ArrayList<>(); + for (int length : new int[]{128}) { + for (boolean cached : BOOLEANS) { + for (TextType textType : new TextType[]{TextType.STRING, + TextType.SPANNABLE_BUILDER}) { + params.add(new Object[]{textType.name(), length, textType, cached}); + } + } + } + return params; + } + + private final int mLineWidth; + private final int mLength; + private final TextType mTextType; + private final boolean mCached; + private final TextPaint mTextPaint; + + public StaticLayoutCreateDrawPerfTest(String label, int length, TextType textType, + boolean cached) { + mLength = length; + mTextType = textType; + mCached = cached; + mTextPaint = new TextPaint(); + mTextPaint.setTextSize(10); + mLineWidth = Integer.MAX_VALUE; + } + + /** + * Measures the creation time for a multi line {@link StaticLayout}. + */ + @Test + public void timeCreate() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final CharSequence text = createRandomText(mLength); + createLayout(text); + state.resumeTiming(); + + while (state.keepRunning()) { + state.pauseTiming(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + createLayout(text); + } + } + + /** + * Measures the draw time for a multi line {@link StaticLayout}. + */ + @Test + public void timeDraw() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final RenderNode node = RenderNode.create("benchmark", null); + final CharSequence text = createRandomText(mLength); + final Layout layout = createLayout(text); + state.resumeTiming(); + + while (state.keepRunning()) { + + state.pauseTiming(); + final DisplayListCanvas canvas = node.start(1200, 200); + int save = canvas.save(); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + layout.draw(canvas); + + state.pauseTiming(); + canvas.restoreToCount(save); + node.end(canvas); + state.resumeTiming(); + } + } + + private Layout createLayout(CharSequence text) { + return StaticLayout.Builder.obtain(text, 0 /*start*/, text.length() /*end*/, mTextPaint, + mLineWidth) + .setAlignment(ALIGN_NORMAL) + .setIncludePad(true) + .setLineSpacing(SPACING_ADD, SPACING_MULT) + .build(); + } + + private CharSequence createRandomText(int length) { + return new NonEditableTextGenerator(new Random(0)) + .setSequenceLength(length) + .setTextType(mTextType) + .build(); + } +} diff --git a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java new file mode 100644 index 0000000000000..a2bf33e1f607d --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java @@ -0,0 +1,151 @@ +/* + * 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; + +import static android.view.View.MeasureSpec.AT_MOST; +import static android.view.View.MeasureSpec.UNSPECIFIED; + +import android.graphics.Canvas; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.LargeTest; +import android.text.NonEditableTextGenerator.TextType; +import android.view.DisplayListCanvas; +import android.view.RenderNode; +import android.widget.TextView; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Random; + +/** + * Performance test for multi line, single style {@link StaticLayout} creation/draw. + */ +@LargeTest +@RunWith(Parameterized.class) +public class TextViewSetTextMeasurePerfTest { + + private static final boolean[] BOOLEANS = new boolean[]{false, true}; + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Parameterized.Parameters(name = "cached={3},{1} chars,{0}") + public static Collection cases() { + final List params = new ArrayList<>(); + for (int length : new int[]{128}) { + for (boolean cached : BOOLEANS) { + for (TextType textType : new TextType[]{TextType.STRING, + TextType.SPANNABLE_BUILDER}) { + params.add(new Object[]{textType.name(), length, textType, cached}); + } + } + } + return params; + } + + private final int mLineWidth; + private final int mLength; + private final TextType mTextType; + private final boolean mCached; + private final TextPaint mTextPaint; + + public TextViewSetTextMeasurePerfTest(String label, int length, TextType textType, + boolean cached) { + mLength = length; + mTextType = textType; + mCached = cached; + mTextPaint = new TextPaint(); + mTextPaint.setTextSize(10); + mLineWidth = Integer.MAX_VALUE; + } + + /** + * Measures the time to setText and measure for a {@link TextView}. + */ + @Test + public void timeCreate() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final CharSequence text = createRandomText(mLength); + final TextView textView = new TextView(InstrumentationRegistry.getTargetContext()); + textView.setText(text); + state.resumeTiming(); + + while (state.keepRunning()) { + state.pauseTiming(); + textView.setTextLocale(Locale.UK); + textView.setTextLocale(Locale.US); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + textView.setText(text); + textView.measure(AT_MOST | mLineWidth, UNSPECIFIED); + } + } + + /** + * Measures the time to draw for a {@link TextView}. + */ + @Test + public void timeDraw() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + + state.pauseTiming(); + Canvas.freeTextLayoutCaches(); + final RenderNode node = RenderNode.create("benchmark", null); + final CharSequence text = createRandomText(mLength); + final TextView textView = new TextView(InstrumentationRegistry.getTargetContext()); + textView.setText(text); + state.resumeTiming(); + + while (state.keepRunning()) { + + state.pauseTiming(); + final DisplayListCanvas canvas = node.start(1200, 200); + int save = canvas.save(); + textView.setTextLocale(Locale.UK); + textView.setTextLocale(Locale.US); + if (!mCached) Canvas.freeTextLayoutCaches(); + state.resumeTiming(); + + textView.draw(canvas); + + state.pauseTiming(); + canvas.restoreToCount(save); + node.end(canvas); + state.resumeTiming(); + } + } + + private CharSequence createRandomText(int length) { + return new NonEditableTextGenerator(new Random(0)) + .setSequenceLength(length) + .setCreateBoring(false) + .setTextType(mTextType) + .build(); + } +}