Merge "Improve IME perf test show/hide stability" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b65f67968d
@@ -18,6 +18,7 @@ package android.inputmethod;
|
|||||||
|
|
||||||
import static android.perftests.utils.ManualBenchmarkState.StatsReport;
|
import static android.perftests.utils.ManualBenchmarkState.StatsReport;
|
||||||
import static android.perftests.utils.PerfTestActivity.ID_EDITOR;
|
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.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
|
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
|
|||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.annotation.UiThread;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -64,6 +66,7 @@ import java.io.InputStreamReader;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@@ -72,6 +75,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
public class ImePerfTest extends ImePerfTestBase
|
public class ImePerfTest extends ImePerfTestBase
|
||||||
implements ManualBenchmarkState.CustomizedIterationListener {
|
implements ManualBenchmarkState.CustomizedIterationListener {
|
||||||
private static final String TAG = ImePerfTest.class.getSimpleName();
|
private static final String TAG = ImePerfTest.class.getSimpleName();
|
||||||
|
private static final long ANIMATION_NOT_STARTED = -1;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
|
public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
|
||||||
@@ -304,36 +308,54 @@ public class ImePerfTest extends ImePerfTestBase
|
|||||||
latchEnd.set(new CountDownLatch(2));
|
latchEnd.set(new CountDownLatch(2));
|
||||||
// For measuring hide, lets show IME first.
|
// For measuring hide, lets show IME first.
|
||||||
if (!show) {
|
if (!show) {
|
||||||
activity.runOnUiThread(() -> {
|
AtomicBoolean showCalled = new AtomicBoolean();
|
||||||
|
getInstrumentation().runOnMainSync(() -> {
|
||||||
|
if (!isImeVisible(activity)) {
|
||||||
controller.show(WindowInsets.Type.ime());
|
controller.show(WindowInsets.Type.ime());
|
||||||
|
showCalled.set(true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
if (showCalled.get()) {
|
||||||
PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS,
|
PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS,
|
||||||
() -> latchStart.get().getCount() == 1
|
() -> latchStart.get().getCount() == 1
|
||||||
&& latchEnd.get().getCount() == 1);
|
&& latchEnd.get().getCount() == 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!mIsTraceStarted && !state.isWarmingUp()) {
|
if (!mIsTraceStarted && !state.isWarmingUp()) {
|
||||||
startAsyncAtrace();
|
startAsyncAtrace();
|
||||||
mIsTraceStarted = true;
|
mIsTraceStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicLong startTime = new AtomicLong();
|
AtomicLong startTime = new AtomicLong();
|
||||||
activity.runOnUiThread(() -> {
|
AtomicBoolean unexpectedVisibility = new AtomicBoolean();
|
||||||
|
getInstrumentation().runOnMainSync(() -> {
|
||||||
|
boolean isVisible = isImeVisible(activity);
|
||||||
startTime.set(SystemClock.elapsedRealtimeNanos());
|
startTime.set(SystemClock.elapsedRealtimeNanos());
|
||||||
if (show) {
|
|
||||||
|
if (show && !isVisible) {
|
||||||
controller.show(WindowInsets.Type.ime());
|
controller.show(WindowInsets.Type.ime());
|
||||||
} else {
|
} else if (!show && isVisible) {
|
||||||
controller.hide(WindowInsets.Type.ime());
|
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.
|
// hide IME before next iteration.
|
||||||
if (show) {
|
if (show) {
|
||||||
activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime()));
|
activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime()));
|
||||||
try {
|
try {
|
||||||
latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
|
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.");
|
Assert.fail("IME hide animation should finish.");
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -350,12 +372,18 @@ public class ImePerfTest extends ImePerfTestBase
|
|||||||
addResultToState(state);
|
addResultToState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private boolean isImeVisible(@NonNull final Activity activity) {
|
||||||
|
return activity.getWindow().getDecorView().getRootWindowInsets().isVisible(
|
||||||
|
WindowInsets.Type.ime());
|
||||||
|
}
|
||||||
|
|
||||||
private long waitForAnimationStart(
|
private long waitForAnimationStart(
|
||||||
AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) {
|
AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) {
|
||||||
try {
|
try {
|
||||||
latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
|
latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
|
||||||
if (latchStart.get().getCount() != 0) {
|
if (latchStart.get().getCount() != 0) {
|
||||||
Assert.fail("IME animation should start " + latchStart.get().getCount());
|
return ANIMATION_NOT_STARTED;
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) { }
|
} catch (InterruptedException e) { }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user