1b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi/*
2b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * Copyright (C) 2016 The Android Open Source Project
3b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi *
4b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * Licensed under the Apache License, Version 2.0 (the "License");
5b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * you may not use this file except in compliance with the License.
6b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * You may obtain a copy of the License at
7b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi *
8b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi *      http://www.apache.org/licenses/LICENSE-2.0
9b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi *
10b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * Unless required by applicable law or agreed to in writing, software
11b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * distributed under the License is distributed on an "AS IS" BASIS,
12b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * See the License for the specific language governing permissions and
14b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi * limitations under the License.
15b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi */
16b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
17b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagipackage android.widget;
18b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
19b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport java.util.Arrays;
20b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport java.util.Collection;
21b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport java.util.Locale;
22b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport java.util.Random;
23b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
24b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport org.junit.Rule;
25b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport org.junit.Test;
26b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport org.junit.runner.RunWith;
27b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport org.junit.runners.Parameterized;
28b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport org.junit.runners.Parameterized.Parameters;
29b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
30b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.app.Activity;
31b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.graphics.Bitmap;
32b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.graphics.Canvas;
33b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.util.Log;
34b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.view.KeyEvent;
35b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.view.RenderNodeAnimator;
36b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.view.ViewGroup;
37b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.view.View.MeasureSpec;
38b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
39b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.perftests.utils.BenchmarkState;
40b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.perftests.utils.PerfStatusReporter;
41b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.perftests.utils.StubActivity;
42b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.support.test.filters.LargeTest;
43b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.support.test.runner.AndroidJUnit4;
44b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.support.test.rule.ActivityTestRule;
45b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagiimport android.support.test.InstrumentationRegistry;
46b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
47b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi@LargeTest
48b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi@RunWith(Parameterized.class)
49b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagipublic class EditTextLongTextPerfTest {
50b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    @Parameters(name = "{0}")
51b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    public static Collection cases() {
52b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        return Arrays.asList(new Object[][] {
53b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi            { "10x30K", 10, 30000 },
54b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi            { "300x1K", 300, 1000 },
55b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        });
56b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    }
57b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
58b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    private final String mMetricKey;
59b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    private final int mChars;
60b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    private final int mLines;
61b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
62b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    public EditTextLongTextPerfTest(String metricKey, int chars, int lines) {
63b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        mMetricKey = metricKey;
64b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        mChars = chars;
65b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        mLines = lines;
66b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    }
67b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
68b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    @Rule
69b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class);
70b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
71b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    @Rule
72b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
73b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
74b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    private EditText setupEditText() {
75b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        final EditText editText = new EditText(mActivityRule.getActivity());
76b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
77b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        String alphabet = "abcdefghijklmnopqrstuvwxyz";
78b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        final long seed = 1234567890;
79b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        Random r = new Random(seed);
80b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        StringBuilder sb = new StringBuilder();
81b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        for (int i = 0; i < mLines; i++) {
82b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi            for (int j = 0; j < mChars; j++) {
83b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi                char c = alphabet.charAt(r.nextInt(alphabet.length()));
84b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi                sb.append(c);
85b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi            }
86b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi            sb.append('\n');
87b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        }
88b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
89b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        final int height = 1000;
90b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        final int width = 1000;
91b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.setHeight(height);
92b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.setWidth(width);
93b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.setLayoutParams(new ViewGroup.LayoutParams(width, height));
94b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
95b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        Activity activity = mActivityRule.getActivity();
96b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        activity.setContentView(editText);
97b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
98b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.setText(sb.toString(), TextView.BufferType.EDITABLE);
99b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.invalidate();
100b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
101b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
102b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        editText.layout(0, 0, height, width);
103b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
104b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi        return editText;
105b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    }
106b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi
107b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    @Test
10836e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka    public void testEditText() throws Throwable {
10936e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka        mActivityRule.runOnUiThread(() -> {
11036e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
11136e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka            final EditText editText = setupEditText();
11236e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka            final KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
11336e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka            final int steps = 100;
11436e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka            while (state.keepRunning()) {
11536e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                for (int i = 0; i < steps; i++) {
11636e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                    int offset = (editText.getText().length() * i) / steps;
11736e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                    editText.setSelection(offset);
11836e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                    editText.bringPointIntoView(offset);
11936e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                    editText.onKeyDown(keyEvent.getKeyCode(), keyEvent);
12036e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                    editText.updateDisplayListIfDirty();
12136e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka                }
122b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi            }
12336e0f128929ca2cdcd51dcb1d0c1fc6557414875Seigo Nonaka        });
124b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi    }
125b7ff1333fe4e5d37ccf5d5b8860bf21235d38a1bKeisuke Kuroyanagi}
126