diff options
author | Seigo Nonaka <nona@google.com> | 2016-07-01 15:50:14 +0900 |
---|---|---|
committer | Seigo Nonaka <nona@google.com> | 2016-07-07 15:50:26 +0900 |
commit | 2a154e2940e79f694ff95b93012e56c5ade70234 (patch) | |
tree | 334abeac6ca3bd2334160f17b724436bd7953ba0 | |
parent | ef6ff327f39e4cdf52ee8249dd40d07a1c9351c1 (diff) |
Introduce backspace benchmark tests.
Bug: 29142734
Change-Id: I186a2019e883881ee8001848f4ae2076ed551f5b
-rw-r--r-- | apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java | 128 | ||||
-rw-r--r-- | apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java | 35 |
2 files changed, 161 insertions, 2 deletions
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java new file mode 100644 index 000000000000..40b56f4a59fd --- /dev/null +++ b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2016 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.widget; + +import android.app.Activity; +import android.os.Bundle; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.perftests.utils.StubActivity; +import android.text.Selection; +import android.view.KeyEvent; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.LargeTest; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized; + +@LargeTest +@RunWith(Parameterized.class) +public class EditTextBackspacePerfTest { + + private static final String BOY = "\uD83D\uDC66"; // U+1F466 + private static final String US_FLAG = "\uD83C\uDDFA\uD83C\uDDF8"; // U+1F1FA U+1F1F8 + private static final String FAMILY = + // U+1F469 U+200D U+1F469 U+200D U+1F467 U+200D U+1F467 + "\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67"; + private static final String EMOJI_MODIFIER = "\uD83C\uDFFD"; // U+1F3FD + private static final String KEYCAP = "\u20E3"; + private static final String COLOR_COPYRIGHT = "\u00A9\uFE0F"; + + @Parameters(name = "{0}") + public static Collection cases() { + return Arrays.asList(new Object[][] { + { "Latin", "aaa", 1 }, + { "Flags", US_FLAG + US_FLAG + US_FLAG, 4 }, + { "EmojiModifier", + BOY + EMOJI_MODIFIER + BOY + EMOJI_MODIFIER + BOY + EMOJI_MODIFIER, 4 }, + { "KeyCap", "1" + KEYCAP + "1" + KEYCAP + "1" + KEYCAP, 2 }, + { "ZwjSequence", FAMILY + FAMILY + FAMILY, 11 }, + { "VariationSelector", COLOR_COPYRIGHT + COLOR_COPYRIGHT + COLOR_COPYRIGHT, 2 }, + }); + } + + private final String mMetricKey; + private final String mText; + private final int mCursorPos; + + private static final KeyEvent BACKSPACE_KEY_EVENT = + new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); + private static final KeyEvent RIGHT_ARROW_KEY_EVENT = + new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT); + + public EditTextBackspacePerfTest(String metricKey, String text, int cursorPos) { + mMetricKey = metricKey; + mText = text; + mCursorPos = cursorPos; + } + + @Rule + public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + private void prepareTextForBackspace(EditText editText) { + editText.setText(mText, TextView.BufferType.EDITABLE); + Selection.setSelection(editText.getText(), 0, 0); + + // Do layout it here since the cursor movement requires layout information but it + // happens asynchronously even if the view is attached to an Activity. + editText.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + editText.invalidate(); + editText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + editText.layout(0, 0, 1024, 768); + + // mText contains three grapheme clusters. Move the cursor to the 2nd grapheme + // cluster by forwarding right arrow key event. + editText.onKeyDown(RIGHT_ARROW_KEY_EVENT.getKeyCode(), RIGHT_ARROW_KEY_EVENT); + Assert.assertEquals(mCursorPos, Selection.getSelectionStart(editText.getText())); + } + + @Test + public void testBackspace() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + EditText editText = new EditText(mActivityRule.getActivity()); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + // Prepare the test data for this iteration with pausing timer. + state.pauseTiming(); + prepareTextForBackspace(editText); + state.resumeTiming(); + + editText.onKeyDown(BACKSPACE_KEY_EVENT.getKeyCode(), BACKSPACE_KEY_EVENT); + } + }); + } +} diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java index 8e1674abae08..2c5a9eac481d 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java @@ -46,13 +46,16 @@ public class BenchmarkState { private static final int NOT_STARTED = 1; // The benchmark has not started yet. private static final int RUNNING = 2; // The benchmark is running. - private static final int FINISHED = 3; // The benchmark has stopped. + private static final int RUNNING_PAUSED = 3; // The benchmark is temporary paused. + private static final int FINISHED = 4; // The benchmark has stopped. private static final int MIN_REPEAT_TIMES = 16; private int mState = NOT_STARTED; // Current benchmark state. private long mNanoPreviousTime = 0; // Previously captured System.nanoTime(). private long mNanoFinishTime = 0; // Finish if System.nanoTime() returns after than this value. + private long mNanoPausedTime = 0; // The System.nanoTime() when the pauseTiming() is called. + private long mNanoPausedDuration = 0; // The duration of paused state in nano sec. private long mNanoTimeLimit = 1 * 1000 * 1000 * 1000; // 1 sec. Default time limit. // Statistics. These values will be filled when the benchmark has finished. @@ -89,6 +92,29 @@ public class BenchmarkState { mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1)); } + // Stops the benchmark timer. + // This method can be called only when the timer is running. + public void pauseTiming() { + if (mState == RUNNING_PAUSED) { + throw new IllegalStateException( + "Unable to pause the benchmark. The benchmark has already paused."); + } + mNanoPausedTime = System.nanoTime(); + mState = RUNNING_PAUSED; + } + + // Starts the benchmark timer. + // This method can be called only when the timer is stopped. + public void resumeTiming() { + if (mState == RUNNING) { + throw new IllegalStateException( + "Unable to resume the benchmark. The benchmark is already running."); + } + mNanoPausedDuration += System.nanoTime() - mNanoPausedTime; + mNanoPausedTime = 0; + mState = RUNNING; + } + /** * Judges whether the benchmark needs more samples. * @@ -103,7 +129,8 @@ public class BenchmarkState { return true; case RUNNING: final long currentTime = System.nanoTime(); - mResults.add(currentTime - mNanoPreviousTime); + mResults.add(currentTime - mNanoPreviousTime - mNanoPausedDuration); + mNanoPausedDuration = 0; // To calculate statistics, needs two or more samples. if (mResults.size() > MIN_REPEAT_TIMES && currentTime > mNanoFinishTime) { @@ -114,6 +141,10 @@ public class BenchmarkState { mNanoPreviousTime = currentTime; return true; + case RUNNING_PAUSED: + throw new IllegalStateException( + "Benchmark step finished with paused state. " + + "Resume the benchmark before finishing each step."); case FINISHED: throw new IllegalStateException("The benchmark has finished."); default: |