1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package android.text; 18 19 import android.app.Activity; 20 import android.graphics.Canvas; 21 import android.graphics.Paint; 22 import android.graphics.Paint.FontMetricsInt; 23 import android.os.Bundle; 24 import android.perftests.utils.BenchmarkState; 25 import android.perftests.utils.PerfStatusReporter; 26 import android.perftests.utils.StubActivity; 27 28 import android.support.test.InstrumentationRegistry; 29 import android.support.test.filters.LargeTest; 30 import android.support.test.rule.ActivityTestRule; 31 import android.support.test.runner.AndroidJUnit4; 32 import android.text.style.ReplacementSpan; 33 import android.util.ArraySet; 34 35 import static android.text.Layout.Alignment.ALIGN_NORMAL; 36 37 import java.util.Arrays; 38 import java.util.Collection; 39 import java.util.Locale; 40 import java.util.Random; 41 42 import org.junit.Assert; 43 import org.junit.Rule; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.junit.runners.Parameterized.Parameters; 47 import org.junit.runners.Parameterized; 48 49 @LargeTest 50 @RunWith(Parameterized.class) 51 public class DynamicLayoutPerfTest { 52 53 @Parameters(name = "{0}") 54 public static Collection cases() { 55 return Arrays.asList(new Object[][] { 56 { "0%", 0.0f}, 57 { "1%", 0.01f}, 58 { "5%", 0.05f}, 59 { "30%", 0.3f}, 60 { "100%", 1.0f}, 61 }); 62 } 63 64 private final String mMetricKey; 65 private final float mProbability; 66 public DynamicLayoutPerfTest(String metricKey, float probability) { 67 mMetricKey = metricKey; 68 mProbability = probability; 69 } 70 71 private static class MockReplacementSpan extends ReplacementSpan { 72 @Override 73 public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) { 74 return 10; 75 } 76 77 @Override 78 public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, 79 int y, int bottom, Paint paint) { 80 } 81 } 82 83 @Rule 84 public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); 85 86 @Rule 87 public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); 88 89 90 private final static String ALPHABETS = "abcdefghijklmnopqrstuvwxyz"; 91 92 private SpannableStringBuilder getText() { 93 final long seed = 1234567890; 94 final Random r = new Random(seed); 95 final SpannableStringBuilder builder = new SpannableStringBuilder(); 96 97 final int paragraphCount = 100; 98 for (int i = 0; i < paragraphCount; i++) { 99 final int wordCount = 5 + r.nextInt(20); 100 final boolean containsReplacementSpan = r.nextFloat() < mProbability; 101 final int replacedWordIndex = containsReplacementSpan ? r.nextInt(wordCount) : -1; 102 for (int j = 0; j < wordCount; j++) { 103 final int startIndex = builder.length(); 104 final int wordLength = 1 + r.nextInt(10); 105 for (int k = 0; k < wordLength; k++) { 106 char c = ALPHABETS.charAt(r.nextInt(ALPHABETS.length())); 107 builder.append(c); 108 } 109 if (replacedWordIndex == j) { 110 builder.setSpan(new MockReplacementSpan(), startIndex, 111 builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 112 } 113 builder.append(' '); 114 } 115 builder.append('\n'); 116 } 117 return builder; 118 } 119 120 @Test 121 public void testGetBlocksAlwaysNeedToBeRedrawn() { 122 final SpannableStringBuilder text = getText(); 123 final DynamicLayout layout = new DynamicLayout(text, new TextPaint(), 1000, 124 ALIGN_NORMAL, 0, 0, false); 125 126 BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); 127 final int steps = 10; 128 while (state.keepRunning()) { 129 for (int i = 0; i < steps; i++) { 130 int offset = (text.length() * i) / steps; 131 text.insert(offset, "\n"); 132 text.delete(offset, offset + 1); 133 final ArraySet<Integer> set = layout.getBlocksAlwaysNeedToBeRedrawn(); 134 if (set != null) { 135 for (int j = 0; j < set.size(); j++) { 136 layout.getBlockIndex(set.valueAt(j)); 137 } 138 } 139 } 140 } 141 } 142 } 143