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