Loading apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java +39 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.inputmethod; import static android.perftests.utils.ManualBenchmarkState.StatsReport; import static android.perftests.utils.PerfTestActivity.ID_EDITOR; import static android.perftests.utils.TestUtils.getOnMainSync; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; Loading @@ -25,6 +26,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static org.junit.Assert.assertTrue; import android.annotation.UiThread; import android.app.Activity; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -64,6 +66,7 @@ import java.io.InputStreamReader; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; Loading @@ -72,6 +75,7 @@ import java.util.concurrent.atomic.AtomicReference; public class ImePerfTest extends ImePerfTestBase implements ManualBenchmarkState.CustomizedIterationListener { private static final String TAG = ImePerfTest.class.getSimpleName(); private static final long ANIMATION_NOT_STARTED = -1; @Rule public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); Loading Loading @@ -304,36 +308,54 @@ public class ImePerfTest extends ImePerfTestBase latchEnd.set(new CountDownLatch(2)); // For measuring hide, lets show IME first. if (!show) { activity.runOnUiThread(() -> { AtomicBoolean showCalled = new AtomicBoolean(); getInstrumentation().runOnMainSync(() -> { if (!isImeVisible(activity)) { controller.show(WindowInsets.Type.ime()); showCalled.set(true); } }); if (showCalled.get()) { PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS, () -> latchStart.get().getCount() == 1 && latchEnd.get().getCount() == 1); } } if (!mIsTraceStarted && !state.isWarmingUp()) { startAsyncAtrace(); mIsTraceStarted = true; } AtomicLong startTime = new AtomicLong(); activity.runOnUiThread(() -> { AtomicBoolean unexpectedVisibility = new AtomicBoolean(); getInstrumentation().runOnMainSync(() -> { boolean isVisible = isImeVisible(activity); startTime.set(SystemClock.elapsedRealtimeNanos()); if (show) { if (show && !isVisible) { controller.show(WindowInsets.Type.ime()); } else { } else if (!show && isVisible) { controller.hide(WindowInsets.Type.ime()); } else { // ignore this iteration as unexpected IME visibility was encountered. unexpectedVisibility.set(true); } }); measuredTimeNs = waitForAnimationStart(latchStart, startTime); if (!unexpectedVisibility.get()) { long timeElapsed = waitForAnimationStart(latchStart, startTime); if (timeElapsed != ANIMATION_NOT_STARTED) { measuredTimeNs = timeElapsed; } } // hide IME before next iteration. if (show) { activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime())); try { latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS); if (latchEnd.get().getCount() != 0) { if (latchEnd.get().getCount() != 0 && getOnMainSync(() -> isImeVisible(activity))) { Assert.fail("IME hide animation should finish."); } } catch (InterruptedException e) { Loading @@ -350,12 +372,18 @@ public class ImePerfTest extends ImePerfTestBase addResultToState(state); } @UiThread private boolean isImeVisible(@NonNull final Activity activity) { return activity.getWindow().getDecorView().getRootWindowInsets().isVisible( WindowInsets.Type.ime()); } private long waitForAnimationStart( AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) { try { latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS); if (latchStart.get().getCount() != 0) { Assert.fail("IME animation should start " + latchStart.get().getCount()); return ANIMATION_NOT_STARTED; } } catch (InterruptedException e) { } Loading apct-tests/perftests/utils/src/android/perftests/utils/TestUtils.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.perftests.utils; import android.app.Instrumentation; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; public final class TestUtils { /** * Retrieves a value that needs to be obtained on the main thread. * * <p>A simple utility method that helps to return an object from the UI thread.</p> * * @param supplier callback to be called on the UI thread to return a value * @param <T> Type of the value to be returned * @return Value returned from {@code supplier} */ public static <T> T getOnMainSync(@NonNull Supplier<T> supplier) { final AtomicReference<T> result = new AtomicReference<>(); final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); instrumentation.runOnMainSync(() -> result.set(supplier.get())); return result.get(); } } Loading
apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java +39 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.inputmethod; import static android.perftests.utils.ManualBenchmarkState.StatsReport; import static android.perftests.utils.PerfTestActivity.ID_EDITOR; import static android.perftests.utils.TestUtils.getOnMainSync; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; Loading @@ -25,6 +26,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static org.junit.Assert.assertTrue; import android.annotation.UiThread; import android.app.Activity; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -64,6 +66,7 @@ import java.io.InputStreamReader; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; Loading @@ -72,6 +75,7 @@ import java.util.concurrent.atomic.AtomicReference; public class ImePerfTest extends ImePerfTestBase implements ManualBenchmarkState.CustomizedIterationListener { private static final String TAG = ImePerfTest.class.getSimpleName(); private static final long ANIMATION_NOT_STARTED = -1; @Rule public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); Loading Loading @@ -304,36 +308,54 @@ public class ImePerfTest extends ImePerfTestBase latchEnd.set(new CountDownLatch(2)); // For measuring hide, lets show IME first. if (!show) { activity.runOnUiThread(() -> { AtomicBoolean showCalled = new AtomicBoolean(); getInstrumentation().runOnMainSync(() -> { if (!isImeVisible(activity)) { controller.show(WindowInsets.Type.ime()); showCalled.set(true); } }); if (showCalled.get()) { PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS, () -> latchStart.get().getCount() == 1 && latchEnd.get().getCount() == 1); } } if (!mIsTraceStarted && !state.isWarmingUp()) { startAsyncAtrace(); mIsTraceStarted = true; } AtomicLong startTime = new AtomicLong(); activity.runOnUiThread(() -> { AtomicBoolean unexpectedVisibility = new AtomicBoolean(); getInstrumentation().runOnMainSync(() -> { boolean isVisible = isImeVisible(activity); startTime.set(SystemClock.elapsedRealtimeNanos()); if (show) { if (show && !isVisible) { controller.show(WindowInsets.Type.ime()); } else { } else if (!show && isVisible) { controller.hide(WindowInsets.Type.ime()); } else { // ignore this iteration as unexpected IME visibility was encountered. unexpectedVisibility.set(true); } }); measuredTimeNs = waitForAnimationStart(latchStart, startTime); if (!unexpectedVisibility.get()) { long timeElapsed = waitForAnimationStart(latchStart, startTime); if (timeElapsed != ANIMATION_NOT_STARTED) { measuredTimeNs = timeElapsed; } } // hide IME before next iteration. if (show) { activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime())); try { latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS); if (latchEnd.get().getCount() != 0) { if (latchEnd.get().getCount() != 0 && getOnMainSync(() -> isImeVisible(activity))) { Assert.fail("IME hide animation should finish."); } } catch (InterruptedException e) { Loading @@ -350,12 +372,18 @@ public class ImePerfTest extends ImePerfTestBase addResultToState(state); } @UiThread private boolean isImeVisible(@NonNull final Activity activity) { return activity.getWindow().getDecorView().getRootWindowInsets().isVisible( WindowInsets.Type.ime()); } private long waitForAnimationStart( AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) { try { latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS); if (latchStart.get().getCount() != 0) { Assert.fail("IME animation should start " + latchStart.get().getCount()); return ANIMATION_NOT_STARTED; } } catch (InterruptedException e) { } Loading
apct-tests/perftests/utils/src/android/perftests/utils/TestUtils.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.perftests.utils; import android.app.Instrumentation; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; public final class TestUtils { /** * Retrieves a value that needs to be obtained on the main thread. * * <p>A simple utility method that helps to return an object from the UI thread.</p> * * @param supplier callback to be called on the UI thread to return a value * @param <T> Type of the value to be returned * @return Value returned from {@code supplier} */ public static <T> T getOnMainSync(@NonNull Supplier<T> supplier) { final AtomicReference<T> result = new AtomicReference<>(); final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); instrumentation.runOnMainSync(() -> result.set(supplier.get())); return result.get(); } }