diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 7a8d1a1caf25fdec28338fb4e508d53b3cfe02fe..f66d12a6959445c947e67248ed050504fb9f5123 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -11,6 +11,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp libs/input/ services/core/jni/ services/incremental/ + tests/ tools/ [Hook Scripts] diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..647da2abd213edf2d02daed89c3e3351c2b42f2e --- /dev/null +++ b/tests/SurfaceViewBufferTests/Android.bp @@ -0,0 +1,58 @@ +// Copyright (C) 2020 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. + +android_test { + name: "SurfaceViewBufferTests", + srcs: ["**/*.java","**/*.kt"], + manifest: "AndroidManifest.xml", + test_config: "AndroidTest.xml", + platform_apis: true, + certificate: "platform", + use_embedded_native_libs: true, + jni_libs: [ + "libsurface_jni", + ], + + static_libs: [ + "androidx.appcompat_appcompat", + "androidx.test.rules", + "androidx.test.runner", + "androidx.test.ext.junit", + "kotlin-stdlib", + "kotlinx-coroutines-android", + "flickerlib", + "truth-prebuilt", + ], +} + +cc_library_shared { + name: "libsurface_jni", + srcs: [ + "cpp/SurfaceProxy.cpp", + ], + shared_libs: [ + "libutils", + "libgui", + "liblog", + "libandroid", + ], + include_dirs: [ + "system/core/include" + ], + stl: "libc++_static", + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/tests/SurfaceViewBufferTests/AndroidManifest.xml b/tests/SurfaceViewBufferTests/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..95885c1ca635faf615496be74bf8864a532d9743 --- /dev/null +++ b/tests/SurfaceViewBufferTests/AndroidManifest.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test"> + + <uses-sdk android:minSdkVersion="29" + android:targetSdkVersion="29"/> + <!-- Enable / Disable tracing !--> + <uses-permission android:name="android.permission.DUMP" /> + <!-- Enable / Disable sv blast adapter !--> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + + <application android:allowBackup="false" + android:supportsRtl="true"> + <activity android:name=".MainActivity" + android:taskAffinity="com.android.test.MainActivity" + android:theme="@style/AppTheme" + android:label="SurfaceViewBufferTestApp" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <uses-library android:name="android.test.runner"/> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.test" + android:label="SurfaceViewBufferTests"> + </instrumentation> +</manifest> diff --git a/tests/SurfaceViewBufferTests/AndroidTest.xml b/tests/SurfaceViewBufferTests/AndroidTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..b73fe4853ecfa7012c9b5e24e2ed77f5ef0075ce --- /dev/null +++ b/tests/SurfaceViewBufferTests/AndroidTest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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. +--> +<configuration description="Runs SurfaceView Buffer Tests"> + <option name="test-tag" value="SurfaceViewBufferTests" /> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <!-- keeps the screen on during tests --> + <option name="screen-always-on" value="on" /> + <!-- prevents the phone from restarting --> + <option name="force-skip-system-props" value="true" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="false"/> + <option name="test-file-name" value="SurfaceViewBufferTests.apk"/> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.test"/> + <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" /> + <option name="shell-timeout" value="6600s" /> + <option name="test-timeout" value="6000s" /> + <option name="hidden-api-checks" value="false" /> + </test> +</configuration> diff --git a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c86524293e772f7e17dde1ffa312cdadbdab6c6 --- /dev/null +++ b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 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. + */ + +#include <android/log.h> +#include <android/native_window.h> +#include <android/native_window_jni.h> +#include <android/window.h> +#include <gui/Surface.h> +#include <jni.h> +#include <system/window.h> +#include <utils/RefBase.h> +#include <cassert> +#include <chrono> +#include <thread> + +#define TAG "SurfaceViewBufferTests" +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) + +extern "C" { +int i = 0; +static ANativeWindow* sAnw; + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass, + jobject surfaceObject) { + sAnw = ANativeWindow_fromSurface(env, surfaceObject); + assert(sAnw); + android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); + surface->enableFrameTimestamps(true); + return 0; +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed( + JNIEnv*, jclass, jint jFrameNumber, jint timeoutSec) { + using namespace std::chrono_literals; + assert(sAnw); + android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw); + + uint64_t frameNumber = static_cast<uint64_t>(jFrameNumber); + nsecs_t outRequestedPresentTime, outAcquireTime, outLatchTime, outFirstRefreshStartTime; + nsecs_t outLastRefreshStartTime, outGlCompositionDoneTime, outDequeueReadyTime; + nsecs_t outDisplayPresentTime = -1; + nsecs_t outReleaseTime; + + auto start = std::chrono::steady_clock::now(); + while (outDisplayPresentTime < 0) { + std::this_thread::sleep_for(8ms); + surface->getFrameTimestamps(frameNumber, &outRequestedPresentTime, &outAcquireTime, + &outLatchTime, &outFirstRefreshStartTime, + &outLastRefreshStartTime, &outGlCompositionDoneTime, + &outDisplayPresentTime, &outDequeueReadyTime, &outReleaseTime); + if (outDisplayPresentTime < 0) { + auto end = std::chrono::steady_clock::now(); + if (std::chrono::duration_cast<std::chrono::seconds>(end - start).count() > + timeoutSec) { + return -1; + } + } + } + return 0; +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_draw(JNIEnv*, jclass) { + assert(sAnw); + ANativeWindow_Buffer outBuffer; + ANativeWindow_lock(sAnw, &outBuffer, nullptr); + return 0; +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowLock(JNIEnv*, jclass) { + assert(sAnw); + ANativeWindow_Buffer outBuffer; + ANativeWindow_lock(sAnw, &outBuffer, nullptr); + return 0; +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowUnlockAndPost(JNIEnv*, + jclass) { + assert(sAnw); + ANativeWindow_unlockAndPost(sAnw); + return 0; +} + +JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersGeometry( + JNIEnv* /* env */, jclass /* clazz */, jobject /* surfaceObject */, jint w, jint h, + jint format) { + assert(sAnw); + return ANativeWindow_setBuffersGeometry(sAnw, w, h, format); +} +} \ No newline at end of file diff --git a/tests/SurfaceViewBufferTests/res/values/styles.xml b/tests/SurfaceViewBufferTests/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..8b50738a06de2b2fda0ec672afebe2b89ad86a4e --- /dev/null +++ b/tests/SurfaceViewBufferTests/res/values/styles.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2020 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. +--> +<resources> +<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> + <item name="windowNoTitle">true</item> + <item name="windowActionBar">false</item> + <item name="android:windowFullscreen">true</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:windowDisablePreview">true</item> +</style> +</resources> diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt b/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..b1e1336c4f6d5740060dbe2bc2e13b6598fa6a1f --- /dev/null +++ b/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 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 com.android.test + +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.os.Bundle +import android.view.Gravity +import android.view.Surface +import android.view.SurfaceHolder +import android.view.SurfaceView +import android.widget.FrameLayout +import java.util.concurrent.CountDownLatch +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock + +class MainActivity : Activity() { + val mSurfaceProxy = SurfaceProxy() + private var mSurfaceHolder: SurfaceHolder? = null + private val mDrawLock = ReentrantLock() + + val surface: Surface? get() = mSurfaceHolder?.surface + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addSurfaceView(Rect(0, 0, 500, 200)) + } + + fun addSurfaceView(size: Rect): CountDownLatch { + val layout = findViewById<FrameLayout>(android.R.id.content) + val surfaceReadyLatch = CountDownLatch(1) + val surfaceView = createSurfaceView(applicationContext, size, surfaceReadyLatch) + layout.addView(surfaceView, + FrameLayout.LayoutParams(size.width(), size.height(), Gravity.TOP or Gravity.LEFT) + .also { it.setMargins(100, 100, 0, 0) }) + return surfaceReadyLatch + } + + private fun createSurfaceView( + context: Context, + size: Rect, + surfaceReadyLatch: CountDownLatch + ): SurfaceView { + val surfaceView = SurfaceView(context) + surfaceView.setWillNotDraw(false) + surfaceView.holder.setFixedSize(size.width(), size.height()) + surfaceView.holder.addCallback(object : SurfaceHolder.Callback { + override fun surfaceCreated(holder: SurfaceHolder) { + mDrawLock.withLock { + mSurfaceHolder = holder + mSurfaceProxy.setSurface(holder.surface) + } + surfaceReadyLatch.countDown() + } + + override fun surfaceChanged( + holder: SurfaceHolder, + format: Int, + width: Int, + height: Int + ) { + } + + override fun surfaceDestroyed(holder: SurfaceHolder) { + mDrawLock.withLock { + mSurfaceHolder = null + } + } + }) + return surfaceView + } + + fun drawFrame(): Rect { + mDrawLock.withLock { + val holder = mSurfaceHolder ?: return Rect() + val canvas = holder.lockCanvas() + val canvasSize = Rect(0, 0, canvas.width, canvas.height) + canvas.drawColor(Color.GREEN) + val p = Paint() + p.color = Color.RED + canvas.drawRect(canvasSize, p) + holder.unlockCanvasAndPost(canvas) + return canvasSize + } + } +} \ No newline at end of file diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt new file mode 100644 index 0000000000000000000000000000000000000000..884aae41446cb0bf6c684c463b0a7848e8fab244 --- /dev/null +++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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 com.android.test + +class SurfaceProxy { + init { + System.loadLibrary("surface_jni") + } + + external fun setSurface(surface: Any) + external fun waitUntilBufferDisplayed(frameNumber: Int, timeoutSec: Int) + external fun draw() + + // android/native_window.h functions + external fun ANativeWindowLock() + external fun ANativeWindowUnlockAndPost() + external fun ANativeWindowSetBuffersGeometry(surface: Any, width: Int, height: Int, format: Int) +} diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTest.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..b48a91d49b91819d9ac6918f3d59dd5fc61fcb4a --- /dev/null +++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTest.kt @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2020 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 com.android.test + +import android.app.Instrumentation +import android.graphics.Rect +import android.provider.Settings +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.monitor.LayersTraceMonitor +import com.android.server.wm.flicker.monitor.withSFTracing +import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import java.util.concurrent.CountDownLatch +import kotlin.properties.Delegates + +@RunWith(Parameterized::class) +class SurfaceViewBufferTest(val useBlastAdapter: Boolean) { + private var mInitialUseBlastConfig by Delegates.notNull<Int>() + + @get:Rule + var scenarioRule: ActivityScenarioRule<MainActivity> = + ActivityScenarioRule<MainActivity>(MainActivity::class.java) + + protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + val defaultBufferSize = Rect(0, 0, 640, 480) + + @Before + fun setup() { + mInitialUseBlastConfig = Settings.Global.getInt(instrumentation.context.contentResolver, + "use_blast_adapter_sv", 0) + val enable = if (useBlastAdapter) 1 else 0 + Settings.Global.putInt(instrumentation.context.contentResolver, "use_blast_adapter_sv", + enable) + val tmpDir = instrumentation.targetContext.dataDir.toPath() + LayersTraceMonitor(tmpDir).stop() + + lateinit var surfaceReadyLatch: CountDownLatch + scenarioRule.getScenario().onActivity { + surfaceReadyLatch = it.addSurfaceView(defaultBufferSize) + } + surfaceReadyLatch.await() + } + + @After + fun teardown() { + scenarioRule.getScenario().close() + Settings.Global.putInt(instrumentation.context.contentResolver, + "use_blast_adapter_sv", mInitialUseBlastConfig) + } + + @Test + fun testSetBuffersGeometry_0x0_resetsBufferSize() { + val trace = withSFTracing(instrumentation, TRACE_FLAGS) { + scenarioRule.getScenario().onActivity { + it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 0, 0, + R8G8B8A8_UNORM) + it.mSurfaceProxy.ANativeWindowLock() + it.mSurfaceProxy.ANativeWindowUnlockAndPost() + it.mSurfaceProxy.waitUntilBufferDisplayed(1, 1 /* sec */) + } + } + + // verify buffer size is reset to default buffer size + assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize) + } + + @Test + fun testSetBuffersGeometry_0x0_rejectsBuffer() { + val trace = withSFTracing(instrumentation, TRACE_FLAGS) { + scenarioRule.getScenario().onActivity { + it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 100, 100, + R8G8B8A8_UNORM) + it.mSurfaceProxy.ANativeWindowLock() + it.mSurfaceProxy.ANativeWindowUnlockAndPost() + it.mSurfaceProxy.ANativeWindowLock() + it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 0, 0, R8G8B8A8_UNORM) + // Submit buffer one with a different size which should be rejected + it.mSurfaceProxy.ANativeWindowUnlockAndPost() + + // submit a buffer with the default buffer size + it.mSurfaceProxy.ANativeWindowLock() + it.mSurfaceProxy.ANativeWindowUnlockAndPost() + it.mSurfaceProxy.waitUntilBufferDisplayed(3, 1 /* sec */) + } + } + // Verify we reject buffers since scaling mode == NATIVE_WINDOW_SCALING_MODE_FREEZE + assertThat(trace).layer("SurfaceView", 2).doesNotExist() + + // Verify the next buffer is submitted with the correct size + assertThat(trace).layer("SurfaceView", 3).also { + it.hasBufferSize(defaultBufferSize) + it.hasScalingMode(0 /* NATIVE_WINDOW_SCALING_MODE_FREEZE */) + } + } + + @Test + fun testSetBuffersGeometry_smallerThanBuffer() { + val bufferSize = Rect(0, 0, 300, 200) + val trace = withSFTracing(instrumentation, TRACE_FLAGS) { + scenarioRule.getScenario().onActivity { + it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize.width(), + bufferSize.height(), R8G8B8A8_UNORM) + it.drawFrame() + it.mSurfaceProxy.waitUntilBufferDisplayed(1, 1 /* sec */) + } + } + + assertThat(trace).layer("SurfaceView", 1).also { + it.hasBufferSize(bufferSize) + it.hasLayerSize(defaultBufferSize) + it.hasScalingMode(1 /* NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW */) + } + } + + @Test + fun testSetBuffersGeometry_largerThanBuffer() { + val bufferSize = Rect(0, 0, 3000, 2000) + val trace = withSFTracing(instrumentation, TRACE_FLAGS) { + scenarioRule.getScenario().onActivity { + it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize.width(), + bufferSize.height(), R8G8B8A8_UNORM) + it.drawFrame() + it.mSurfaceProxy.waitUntilBufferDisplayed(1, 1 /* sec */) + } + } + + assertThat(trace).layer("SurfaceView", 1).also { + it.hasBufferSize(bufferSize) + it.hasLayerSize(defaultBufferSize) + it.hasScalingMode(1 /* NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW */) + } + } + + /** Submit buffers as fast as possible and make sure they are queued */ + @Test + fun testQueueBuffers() { + val trace = withSFTracing(instrumentation, TRACE_FLAGS) { + scenarioRule.getScenario().onActivity { + it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 100, 100, + R8G8B8A8_UNORM) + for (i in 0..100) { + it.mSurfaceProxy.ANativeWindowLock() + it.mSurfaceProxy.ANativeWindowUnlockAndPost() + } + it.mSurfaceProxy.waitUntilBufferDisplayed(100, 1 /* sec */) + } + } + for (frameNumber in 1..100) { + assertThat(trace).layer("SurfaceView", frameNumber.toLong()) + } + } + + companion object { + private const val TRACE_FLAGS = 0x1 // TRACE_CRITICAL + private const val R8G8B8A8_UNORM = 1 + + @JvmStatic + @Parameterized.Parameters(name = "blast={0}") + fun data(): Collection<Array<Any>> { + return listOf( + arrayOf(false), // First test: submit buffers via bufferqueue + arrayOf(true) // Second test: submit buffers via blast adapter + ) + } + } +} \ No newline at end of file