Merge "Add more tests to verify blast buffer queue behaviour"
This commit is contained in:
committed by
Android (Google) Code Review
commit
460a46f942
@@ -33,6 +33,8 @@ android_test {
|
||||
"kotlinx-coroutines-android",
|
||||
"flickerlib",
|
||||
"truth-prebuilt",
|
||||
"cts-wm-util",
|
||||
"CtsSurfaceValidatorLib",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -43,6 +45,7 @@ cc_library_shared {
|
||||
],
|
||||
shared_libs: [
|
||||
"libutils",
|
||||
"libui",
|
||||
"libgui",
|
||||
"liblog",
|
||||
"libandroid",
|
||||
|
||||
@@ -23,12 +23,19 @@
|
||||
<uses-permission android:name="android.permission.DUMP" />
|
||||
<!-- Enable / Disable sv blast adapter !-->
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<!-- Readback virtual display output !-->
|
||||
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<!-- Save failed test bitmap images !-->
|
||||
<uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application android:allowBackup="false"
|
||||
android:supportsRtl="true">
|
||||
<activity android:name=".MainActivity"
|
||||
android:taskAffinity="com.android.test.MainActivity"
|
||||
android:theme="@style/AppTheme"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="SurfaceViewBufferTestApp"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@@ -36,6 +43,10 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
|
||||
android:foregroundServiceType="mediaProjection"
|
||||
android:enabled="true">
|
||||
</service>
|
||||
<uses-library android:name="android.test.runner"/>
|
||||
</application>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
extern "C" {
|
||||
int i = 0;
|
||||
static ANativeWindow* sAnw;
|
||||
static std::map<uint32_t /* slot */, ANativeWindowBuffer*> sBuffers;
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass,
|
||||
jobject surfaceObject) {
|
||||
@@ -39,11 +40,14 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env
|
||||
assert(sAnw);
|
||||
android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
|
||||
surface->enableFrameTimestamps(true);
|
||||
surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false);
|
||||
native_window_set_usage(sAnw, GRALLOC_USAGE_SW_WRITE_OFTEN);
|
||||
native_window_set_buffers_format(sAnw, HAL_PIXEL_FORMAT_RGBA_8888);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed(
|
||||
JNIEnv*, jclass, jint jFrameNumber, jint timeoutSec) {
|
||||
JNIEnv*, jclass, jlong jFrameNumber, jint timeoutMs) {
|
||||
using namespace std::chrono_literals;
|
||||
assert(sAnw);
|
||||
android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
|
||||
@@ -63,8 +67,8 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplay
|
||||
&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) {
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() >
|
||||
timeoutMs) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -99,4 +103,121 @@ JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffer
|
||||
assert(sAnw);
|
||||
return ANativeWindow_setBuffersGeometry(sAnw, w, h, format);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform(
|
||||
JNIEnv* /* env */, jclass /* clazz */, jint transform) {
|
||||
assert(sAnw);
|
||||
return native_window_set_buffers_transform(sAnw, transform);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv* /* env */,
|
||||
jclass /* clazz */,
|
||||
jint scalingMode) {
|
||||
assert(sAnw);
|
||||
android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
|
||||
return surface->setScalingMode(scalingMode);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv* /* env */,
|
||||
jclass /* clazz */,
|
||||
jint slot,
|
||||
jint timeoutMs) {
|
||||
assert(sAnw);
|
||||
ANativeWindowBuffer* anb;
|
||||
int fenceFd;
|
||||
int result = sAnw->dequeueBuffer(sAnw, &anb, &fenceFd);
|
||||
if (result != android::OK) {
|
||||
return result;
|
||||
}
|
||||
sBuffers[slot] = anb;
|
||||
android::sp<android::Fence> fence(new android::Fence(fenceFd));
|
||||
int waitResult = fence->wait(timeoutMs);
|
||||
if (waitResult != android::OK) {
|
||||
sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
|
||||
sBuffers[slot] = nullptr;
|
||||
return waitResult;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv* /* env */,
|
||||
jclass /* clazz */,
|
||||
jint slot) {
|
||||
assert(sAnw);
|
||||
assert(sBuffers[slot]);
|
||||
int result = sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
|
||||
sBuffers[slot] = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv* env,
|
||||
jclass /* clazz */, jint slot,
|
||||
jintArray jintArrayColor) {
|
||||
assert(sAnw);
|
||||
assert(sBuffers[slot]);
|
||||
|
||||
int* color = env->GetIntArrayElements(jintArrayColor, nullptr);
|
||||
|
||||
ANativeWindowBuffer* buffer = sBuffers[slot];
|
||||
android::sp<android::GraphicBuffer> graphicBuffer(static_cast<android::GraphicBuffer*>(buffer));
|
||||
const android::Rect bounds(buffer->width, buffer->height);
|
||||
android::Region newDirtyRegion;
|
||||
newDirtyRegion.set(bounds);
|
||||
|
||||
void* vaddr;
|
||||
int fenceFd = -1;
|
||||
graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
|
||||
newDirtyRegion.bounds(), &vaddr, fenceFd);
|
||||
|
||||
for (int32_t row = 0; row < buffer->height; row++) {
|
||||
uint8_t* dst = static_cast<uint8_t*>(vaddr) + (buffer->stride * row) * 4;
|
||||
for (int32_t column = 0; column < buffer->width; column++) {
|
||||
dst[0] = color[0];
|
||||
dst[1] = color[1];
|
||||
dst[2] = color[2];
|
||||
dst[3] = color[3];
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
graphicBuffer->unlockAsync(&fenceFd);
|
||||
env->ReleaseIntArrayElements(jintArrayColor, color, JNI_ABORT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv* /* env */,
|
||||
jclass /* clazz */,
|
||||
jint slot,
|
||||
jboolean freeSlot) {
|
||||
assert(sAnw);
|
||||
assert(sBuffers[slot]);
|
||||
int result = sAnw->queueBuffer(sAnw, sBuffers[slot], -1);
|
||||
if (freeSlot) {
|
||||
sBuffers[slot] = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount(
|
||||
JNIEnv* /* env */, jclass /* clazz */, jint count) {
|
||||
assert(sAnw);
|
||||
android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
|
||||
int result = native_window_set_buffer_count(sAnw, count);
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode(
|
||||
JNIEnv* /* env */, jclass /* clazz */, jboolean shared) {
|
||||
assert(sAnw);
|
||||
android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
|
||||
int result = native_window_set_shared_buffer_mode(sAnw, shared);
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh(
|
||||
JNIEnv* /* env */, jclass /* clazz */, jboolean autoRefresh) {
|
||||
assert(sAnw);
|
||||
android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
|
||||
int result = native_window_set_auto_refresh(sAnw, autoRefresh);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class BufferPresentationTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
|
||||
/** Submit buffers as fast as possible and make sure they are presented on display */
|
||||
@Test
|
||||
fun testQueueBuffers() {
|
||||
val numFrames = 100L
|
||||
val trace = withTrace {
|
||||
for (i in 1..numFrames) {
|
||||
it.mSurfaceProxy.ANativeWindowLock()
|
||||
it.mSurfaceProxy.ANativeWindowUnlockAndPost()
|
||||
}
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 1000 /* ms */))
|
||||
}
|
||||
|
||||
assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferScalingMode_outOfOrderQueueBuffer() {
|
||||
val trace = withTrace {
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(2, 5000 /* ms */))
|
||||
}
|
||||
|
||||
assertThat(trace).hasFrameSequence("SurfaceView", 1..2L)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferScalingMode_multipleDequeueBuffer() {
|
||||
val numFrames = 20L
|
||||
val trace = withTrace {
|
||||
for (count in 1..(numFrames / 2)) {
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
}
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */))
|
||||
}
|
||||
|
||||
assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferCount_queueMaxBufferCountMinusOne() {
|
||||
val numBufferCount = 8
|
||||
val numFrames = numBufferCount * 5L
|
||||
val trace = withTrace {
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetBufferCount(numBufferCount + 1))
|
||||
for (i in 1..numFrames / numBufferCount) {
|
||||
for (bufferSlot in 0..numBufferCount - 1) {
|
||||
assertEquals(0,
|
||||
it.mSurfaceProxy.SurfaceDequeueBuffer(bufferSlot, 1000 /* ms */))
|
||||
}
|
||||
|
||||
for (bufferSlot in 0..numBufferCount - 1) {
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(bufferSlot)
|
||||
}
|
||||
}
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */))
|
||||
}
|
||||
|
||||
assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.graphics.Point
|
||||
import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class BufferRejectionTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
|
||||
@Test
|
||||
fun testSetBuffersGeometry_0x0_rejectsBuffer() {
|
||||
val trace = withTrace {
|
||||
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, 500 /* ms */)
|
||||
}
|
||||
// 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)
|
||||
// scaling mode is not passed down to the layer for blast
|
||||
if (useBlastAdapter) {
|
||||
it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
|
||||
} else {
|
||||
it.hasScalingMode(ScalingMode.FREEZE.ordinal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferScalingMode_freeze() {
|
||||
val bufferSize = Point(300, 200)
|
||||
val trace = withTrace {
|
||||
it.drawFrame()
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
// Change buffer size and set scaling mode to freeze
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0),
|
||||
R8G8B8A8_UNORM)
|
||||
|
||||
// first dequeued buffer does not have the new size so it should be rejected.
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
|
||||
}
|
||||
|
||||
// verify buffer size is reset to default buffer size
|
||||
assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
|
||||
assertThat(trace).layer("SurfaceView", 2).doesNotExist()
|
||||
assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferScalingMode_freeze_withBufferRotation() {
|
||||
val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x)
|
||||
val trace = withTrace {
|
||||
it.drawFrame()
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, rotatedBufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
// Change buffer size and set scaling mode to freeze
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0),
|
||||
R8G8B8A8_UNORM)
|
||||
|
||||
// first dequeued buffer does not have the new size so it should be rejected.
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
// add a buffer transform so the buffer size is correct.
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
|
||||
}
|
||||
|
||||
// verify buffer size is reset to default buffer size
|
||||
assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
|
||||
assertThat(trace).layer("SurfaceView", 2).doesNotExist()
|
||||
assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
|
||||
assertThat(trace).layer("SurfaceView", 3).hasBufferOrientation(Transform.ROT_90.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRejectedBuffersAreReleased() {
|
||||
val bufferSize = Point(300, 200)
|
||||
val trace = withTrace {
|
||||
for (count in 0 until 5) {
|
||||
it.drawFrame()
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 1L,
|
||||
500 /* ms */), 0)
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
// Change buffer size and set scaling mode to freeze
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0),
|
||||
R8G8B8A8_UNORM)
|
||||
|
||||
// first dequeued buffer does not have the new size so it should be rejected.
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 3L,
|
||||
500 /* ms */), 0)
|
||||
}
|
||||
}
|
||||
|
||||
for (count in 0 until 5) {
|
||||
assertThat(trace).layer("SurfaceView", (count * 3) + 1L)
|
||||
.hasBufferSize(defaultBufferSize)
|
||||
assertThat(trace).layer("SurfaceView", (count * 3) + 2L)
|
||||
.doesNotExist()
|
||||
assertThat(trace).layer("SurfaceView", (count * 3) + 3L)
|
||||
.hasBufferSize(bufferSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.graphics.Point
|
||||
import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class GeometryTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
|
||||
@Test
|
||||
fun testSetBuffersGeometry_0x0_resetsBufferSize() {
|
||||
val trace = withTrace {
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, 0, 0,
|
||||
R8G8B8A8_UNORM)
|
||||
it.mSurfaceProxy.ANativeWindowLock()
|
||||
it.mSurfaceProxy.ANativeWindowUnlockAndPost()
|
||||
it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
|
||||
}
|
||||
|
||||
// verify buffer size is reset to default buffer size
|
||||
assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBuffersGeometry_smallerThanBuffer() {
|
||||
val bufferSize = Point(300, 200)
|
||||
val trace = withTrace {
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
it.drawFrame()
|
||||
it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
|
||||
}
|
||||
|
||||
assertThat(trace).layer("SurfaceView", 1).also {
|
||||
it.hasBufferSize(bufferSize)
|
||||
it.hasLayerSize(defaultBufferSize)
|
||||
it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBuffersGeometry_largerThanBuffer() {
|
||||
val bufferSize = Point(3000, 2000)
|
||||
val trace = withTrace {
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
it.drawFrame()
|
||||
it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
|
||||
}
|
||||
|
||||
assertThat(trace).layer("SurfaceView", 1).also {
|
||||
it.hasBufferSize(bufferSize)
|
||||
it.hasLayerSize(defaultBufferSize)
|
||||
it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferScalingMode_freeze() {
|
||||
val bufferSize = Point(300, 200)
|
||||
val trace = withTrace {
|
||||
it.drawFrame()
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, bufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
// Change buffer size and set scaling mode to freeze
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0),
|
||||
R8G8B8A8_UNORM)
|
||||
|
||||
// first dequeued buffer does not have the new size so it should be rejected.
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
it.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
|
||||
}
|
||||
|
||||
// verify buffer size is reset to default buffer size
|
||||
assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
|
||||
assertThat(trace).layer("SurfaceView", 2).doesNotExist()
|
||||
assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBuffersTransform_FLIP() {
|
||||
val transforms = arrayOf(Transform.FLIP_H, Transform.FLIP_V, Transform.ROT_180).withIndex()
|
||||
for ((index, transform) in transforms) {
|
||||
val trace = withTrace {
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersTransform(transform)
|
||||
it.mSurfaceProxy.ANativeWindowLock()
|
||||
it.mSurfaceProxy.ANativeWindowUnlockAndPost()
|
||||
it.mSurfaceProxy.waitUntilBufferDisplayed(index + 1L, 500 /* ms */)
|
||||
}
|
||||
|
||||
assertThat(trace).layer("SurfaceView", index + 1L).also {
|
||||
it.hasBufferSize(defaultBufferSize)
|
||||
it.hasLayerSize(defaultBufferSize)
|
||||
it.hasBufferOrientation(transform.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.graphics.Point
|
||||
import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Assume.assumeFalse
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class InverseDisplayTransformTests(useBlastAdapter: Boolean) :
|
||||
SurfaceTracingTestBase(useBlastAdapter) {
|
||||
@Before
|
||||
override fun setup() {
|
||||
scenarioRule.getScenario().onActivity {
|
||||
it.rotate90()
|
||||
}
|
||||
instrumentation.waitForIdleSync()
|
||||
super.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetBufferScalingMode_freeze_withInvDisplayTransform() {
|
||||
assumeFalse("Blast does not support buffer rejection with Inv display " +
|
||||
"transform since the only user for this hidden api is camera which does not use" +
|
||||
"fixed scaling mode.", useBlastAdapter)
|
||||
|
||||
val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x)
|
||||
val trace = withTrace {
|
||||
// Inverse display transforms are sticky AND they are only consumed by the sf after
|
||||
// a valid buffer has been acquired.
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.INVERSE_DISPLAY.value)
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, rotatedBufferSize,
|
||||
R8G8B8A8_UNORM)
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
|
||||
// Change buffer size and set scaling mode to freeze
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersGeometry(it.surface!!, Point(0, 0),
|
||||
R8G8B8A8_UNORM)
|
||||
|
||||
// first dequeued buffer does not have the new size so it should be rejected.
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90.value)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
it.mSurfaceProxy.ANativeWindowSetBuffersTransform(0)
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(1)
|
||||
assertEquals(it.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
|
||||
}
|
||||
|
||||
// verify buffer size is reset to default buffer size
|
||||
assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
|
||||
assertThat(trace).layer("SurfaceView", 2).doesNotExist()
|
||||
assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
|
||||
}
|
||||
}
|
||||
@@ -15,51 +15,80 @@
|
||||
*/
|
||||
package com.android.test
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration.ORIENTATION_LANDSCAPE
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Point
|
||||
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.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.cts.surfacevalidator.CapturedActivity
|
||||
import android.widget.FrameLayout
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
class MainActivity : Activity() {
|
||||
class MainActivity : CapturedActivity() {
|
||||
val mSurfaceProxy = SurfaceProxy()
|
||||
private var mSurfaceHolder: SurfaceHolder? = null
|
||||
private val mDrawLock = ReentrantLock()
|
||||
var mSurfaceView: SurfaceView? = null
|
||||
|
||||
val surface: Surface? get() = mSurfaceHolder?.surface
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
addSurfaceView(Rect(0, 0, 500, 200))
|
||||
addSurfaceView(Point(500, 200))
|
||||
window.decorView.apply {
|
||||
systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
}
|
||||
}
|
||||
|
||||
fun addSurfaceView(size: Rect): CountDownLatch {
|
||||
override fun getCaptureDurationMs(): Long {
|
||||
return 30000
|
||||
}
|
||||
|
||||
fun addSurfaceView(size: Point): 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)
|
||||
mSurfaceView = createSurfaceView(applicationContext, size, surfaceReadyLatch)
|
||||
layout.addView(mSurfaceView!!,
|
||||
FrameLayout.LayoutParams(size.x, size.y, Gravity.TOP or Gravity.LEFT)
|
||||
.also { it.setMargins(100, 100, 0, 0) })
|
||||
|
||||
return surfaceReadyLatch
|
||||
}
|
||||
|
||||
fun enableSeamlessRotation() {
|
||||
val p: WindowManager.LayoutParams = window.attributes
|
||||
p.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS
|
||||
window.attributes = p
|
||||
}
|
||||
|
||||
fun rotate90() {
|
||||
if (getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
|
||||
} else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSurfaceView(
|
||||
context: Context,
|
||||
size: Rect,
|
||||
size: Point,
|
||||
surfaceReadyLatch: CountDownLatch
|
||||
): SurfaceView {
|
||||
val surfaceView = SurfaceView(context)
|
||||
surfaceView.setWillNotDraw(false)
|
||||
surfaceView.holder.setFixedSize(size.width(), size.height())
|
||||
surfaceView.holder.setFixedSize(size.x, size.y)
|
||||
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
|
||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||
mDrawLock.withLock {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.annotation.ColorInt
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.server.wm.WindowManagerState.getLogicalDisplaySize
|
||||
import android.view.cts.surfacevalidator.CapturedActivity
|
||||
import android.view.cts.surfacevalidator.ISurfaceValidatorTestCase
|
||||
import android.view.cts.surfacevalidator.PixelChecker
|
||||
import android.view.cts.surfacevalidator.RectChecker
|
||||
import android.widget.FrameLayout
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
open class ScreenRecordTestBase(useBlastAdapter: Boolean) :
|
||||
SurfaceViewBufferTestBase(useBlastAdapter) {
|
||||
@get:Rule
|
||||
var mActivityRule = ActivityTestRule(MainActivity::class.java)
|
||||
|
||||
private lateinit var mActivity: MainActivity
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
mActivity = mActivityRule.launchActivity(Intent())
|
||||
lateinit var surfaceReadyLatch: CountDownLatch
|
||||
runOnUiThread {
|
||||
it.dismissPermissionDialog()
|
||||
it.setLogicalDisplaySize(getLogicalDisplaySize())
|
||||
surfaceReadyLatch = it.addSurfaceView(defaultBufferSize)
|
||||
}
|
||||
surfaceReadyLatch.await()
|
||||
// sleep to finish animations
|
||||
instrumentation.waitForIdleSync()
|
||||
}
|
||||
|
||||
@After
|
||||
override fun teardown() {
|
||||
super.teardown()
|
||||
mActivityRule.finishActivity()
|
||||
}
|
||||
|
||||
fun runOnUiThread(predicate: (it: MainActivity) -> Unit) {
|
||||
mActivityRule.runOnUiThread {
|
||||
predicate(mActivity)
|
||||
}
|
||||
}
|
||||
|
||||
fun withScreenRecording(
|
||||
boundsToCheck: Rect,
|
||||
@ColorInt color: Int,
|
||||
predicate: (it: MainActivity) -> Unit
|
||||
): CapturedActivity.TestResult {
|
||||
val testCase = object : ISurfaceValidatorTestCase {
|
||||
override fun getChecker(): PixelChecker = RectChecker(boundsToCheck, color)
|
||||
override fun start(context: Context, parent: FrameLayout) {
|
||||
predicate(mActivity)
|
||||
}
|
||||
override fun end() { /* do nothing */ }
|
||||
}
|
||||
|
||||
return mActivity.runTest(testCase)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.os.SystemClock
|
||||
import android.view.cts.surfacevalidator.PixelColor
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class SharedBufferModeScreenRecordTests(useBlastAdapter: Boolean) :
|
||||
ScreenRecordTestBase(useBlastAdapter) {
|
||||
|
||||
/** When auto refresh is set, surface flinger will wake up and refresh the display presenting
|
||||
* the latest content in the buffer.
|
||||
*/
|
||||
@Test
|
||||
fun testAutoRefresh() {
|
||||
var svBounds = Rect()
|
||||
runOnUiThread {
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetAutoRefresh(true))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0, false /* freeSlot */)
|
||||
assertEquals(0,
|
||||
it.mSurfaceProxy.waitUntilBufferDisplayed(1, 5000 /* ms */))
|
||||
|
||||
svBounds = Rect(0, 0, it.mSurfaceView!!.width, it.mSurfaceView!!.height)
|
||||
val position = Rect()
|
||||
it.mSurfaceView!!.getBoundsOnScreen(position)
|
||||
svBounds.offsetTo(position.left, position.top)
|
||||
|
||||
// wait for buffers from other layers to be latched and transactions to be processed before
|
||||
// updating the buffer
|
||||
SystemClock.sleep(4000)
|
||||
}
|
||||
|
||||
val result = withScreenRecording(svBounds, PixelColor.RED) {
|
||||
it.mSurfaceProxy.drawBuffer(0, Color.RED)
|
||||
}
|
||||
val failRatio = 1.0f * result.failFrames / (result.failFrames + result.passFrames)
|
||||
|
||||
assertTrue("Error: " + result.failFrames +
|
||||
" incorrect frames observed (out of " + (result.failFrames + result.passFrames) +
|
||||
" frames)", failRatio < 0.05)
|
||||
assertTrue("Error: Did not receive sufficient frame updates expected: >1000 actual:" +
|
||||
result.passFrames, result.passFrames > 1000)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class SharedBufferModeTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
|
||||
/** Sanity test to check each buffer is presented if its submitted with enough delay
|
||||
* for SF to present the buffers. */
|
||||
@Test
|
||||
fun testCanPresentBuffers() {
|
||||
val numFrames = 15L
|
||||
val trace = withTrace {
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
|
||||
for (i in 1..numFrames) {
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(i, 5000 /* ms */))
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
|
||||
}
|
||||
|
||||
/** Submit buffers as fast as possible testing that we are not blocked when dequeuing the buffer
|
||||
* by setting the dequeue timeout to 1ms and checking that we present the newest buffer. */
|
||||
@Test
|
||||
fun testFastQueueBuffers() {
|
||||
val numFrames = 15L
|
||||
val trace = withTrace {
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
|
||||
for (i in 1..numFrames) {
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0)
|
||||
}
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(numFrames, 5000 /* ms */))
|
||||
}
|
||||
|
||||
assertThat(trace).hasFrameSequence("SurfaceView", numFrames..numFrames)
|
||||
}
|
||||
|
||||
/** Keep overwriting the buffer without queuing buffers and check that we present the latest
|
||||
* buffer content. */
|
||||
@Test
|
||||
fun testAutoRefresh() {
|
||||
var svBounds = Rect()
|
||||
runOnUiThread {
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
|
||||
assertEquals(0, it.mSurfaceProxy.NativeWindowSetAutoRefresh(true))
|
||||
assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
|
||||
it.mSurfaceProxy.SurfaceQueueBuffer(0, false /* freeSlot */)
|
||||
assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(1, 5000 /* ms */))
|
||||
|
||||
svBounds = Rect(0, 0, it.mSurfaceView!!.width, it.mSurfaceView!!.height)
|
||||
val position = Rect()
|
||||
it.mSurfaceView!!.getBoundsOnScreen(position)
|
||||
svBounds.offsetTo(position.left, position.top)
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
it.mSurfaceProxy.drawBuffer(0, Color.RED)
|
||||
checkPixels(svBounds, Color.RED)
|
||||
it.mSurfaceProxy.drawBuffer(0, Color.GREEN)
|
||||
checkPixels(svBounds, Color.GREEN)
|
||||
it.mSurfaceProxy.drawBuffer(0, Color.BLUE)
|
||||
checkPixels(svBounds, Color.BLUE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,17 +16,46 @@
|
||||
|
||||
package com.android.test
|
||||
|
||||
import android.annotation.ColorInt
|
||||
import android.graphics.Color
|
||||
import android.graphics.Point
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
|
||||
import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
|
||||
|
||||
class SurfaceProxy {
|
||||
init {
|
||||
System.loadLibrary("surface_jni")
|
||||
}
|
||||
|
||||
external fun setSurface(surface: Any)
|
||||
external fun waitUntilBufferDisplayed(frameNumber: Int, timeoutSec: Int)
|
||||
external fun waitUntilBufferDisplayed(frameNumber: Long, timeoutMs: Int): Int
|
||||
external fun draw()
|
||||
fun drawBuffer(slot: Int, @ColorInt c: Int) {
|
||||
drawBuffer(slot, intArrayOf(Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c)))
|
||||
}
|
||||
external fun drawBuffer(slot: Int, color: IntArray)
|
||||
|
||||
// android/native_window.h functions
|
||||
external fun ANativeWindowLock()
|
||||
external fun ANativeWindowUnlockAndPost()
|
||||
fun ANativeWindowSetBuffersGeometry(surface: Any, size: Point, format: Int) {
|
||||
ANativeWindowSetBuffersGeometry(surface, size.x, size.y, format)
|
||||
}
|
||||
external fun ANativeWindowSetBuffersGeometry(surface: Any, width: Int, height: Int, format: Int)
|
||||
fun ANativeWindowSetBuffersTransform(transform: Transform) {
|
||||
ANativeWindowSetBuffersTransform(transform.value)
|
||||
}
|
||||
external fun ANativeWindowSetBuffersTransform(transform: Int)
|
||||
|
||||
// gui/Surface.h functions
|
||||
fun SurfaceSetScalingMode(scalingMode: ScalingMode) {
|
||||
SurfaceSetScalingMode(scalingMode.ordinal)
|
||||
}
|
||||
external fun SurfaceSetScalingMode(scalingMode: Int)
|
||||
external fun SurfaceDequeueBuffer(slot: Int, timeoutMs: Int): Int
|
||||
external fun SurfaceCancelBuffer(slot: Int)
|
||||
external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true)
|
||||
external fun NativeWindowSetBufferCount(count: Int): Int
|
||||
external fun NativeWindowSetSharedBufferMode(shared: Boolean): Int
|
||||
external fun NativeWindowSetAutoRefresh(autoRefresh: Boolean): Int
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.annotation.ColorInt
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.util.Log
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import com.android.server.wm.flicker.monitor.LayersTraceMonitor
|
||||
import com.android.server.wm.flicker.monitor.withSFTracing
|
||||
import com.android.server.wm.flicker.traces.layers.LayersTrace
|
||||
import junit.framework.Assert
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
open class SurfaceTracingTestBase(useBlastAdapter: Boolean) :
|
||||
SurfaceViewBufferTestBase(useBlastAdapter) {
|
||||
@get:Rule
|
||||
var scenarioRule: ActivityScenarioRule<MainActivity> =
|
||||
ActivityScenarioRule<MainActivity>(MainActivity::class.java)
|
||||
|
||||
@Before
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
stopLayerTrace()
|
||||
addSurfaceView()
|
||||
}
|
||||
|
||||
@After
|
||||
override fun teardown() {
|
||||
super.teardown()
|
||||
scenarioRule.getScenario().close()
|
||||
}
|
||||
|
||||
fun withTrace(predicate: (it: MainActivity) -> Unit): LayersTrace {
|
||||
return withSFTracing(instrumentation, TRACE_FLAGS) {
|
||||
scenarioRule.getScenario().onActivity {
|
||||
predicate(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun runOnUiThread(predicate: (it: MainActivity) -> Unit) {
|
||||
scenarioRule.getScenario().onActivity {
|
||||
predicate(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSurfaceView() {
|
||||
lateinit var surfaceReadyLatch: CountDownLatch
|
||||
scenarioRule.getScenario().onActivity {
|
||||
surfaceReadyLatch = it.addSurfaceView(defaultBufferSize)
|
||||
}
|
||||
surfaceReadyLatch.await()
|
||||
// sleep to finish animations
|
||||
instrumentation.waitForIdleSync()
|
||||
}
|
||||
|
||||
private fun stopLayerTrace() {
|
||||
val tmpDir = instrumentation.targetContext.dataDir.toPath()
|
||||
LayersTraceMonitor(tmpDir).stop()
|
||||
}
|
||||
|
||||
fun checkPixels(bounds: Rect, @ColorInt color: Int) {
|
||||
val screenshot = instrumentation.getUiAutomation().takeScreenshot()
|
||||
val pixels = IntArray(screenshot.width * screenshot.height)
|
||||
screenshot.getPixels(pixels, 0, screenshot.width, 0, 0, screenshot.width, screenshot.height)
|
||||
for (i in bounds.left + 10..bounds.right - 10) {
|
||||
for (j in bounds.top + 10..bounds.bottom - 10) {
|
||||
val actualColor = pixels[j * screenshot.width + i]
|
||||
if (actualColor != color) {
|
||||
val screenshotPath = instrumentation.targetContext
|
||||
.getExternalFilesDir(null)?.resolve("screenshot.png")
|
||||
try {
|
||||
FileOutputStream(screenshotPath).use { out ->
|
||||
screenshot.compress(Bitmap.CompressFormat.PNG, 100, out)
|
||||
}
|
||||
Log.e("SurfaceViewBufferTests", "Bitmap written to $screenshotPath")
|
||||
} catch (e: IOException) {
|
||||
Log.e("SurfaceViewBufferTests", "Error writing bitmap to file", e)
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("Checking $bounds found mismatch $i,$j",
|
||||
Color.valueOf(color), Color.valueOf(actualColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TRACE_FLAGS =
|
||||
(1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.Point
|
||||
import android.provider.Settings
|
||||
import androidx.test.InstrumentationRegistry
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TestName
|
||||
import org.junit.runners.Parameterized
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
open class SurfaceViewBufferTestBase(val useBlastAdapter: Boolean) {
|
||||
private var mInitialBlastConfig by Delegates.notNull<Boolean>()
|
||||
|
||||
val instrumentation: Instrumentation
|
||||
get() = InstrumentationRegistry.getInstrumentation()
|
||||
|
||||
@get:Rule
|
||||
var mName = TestName()
|
||||
|
||||
@Before
|
||||
open fun setup() {
|
||||
mInitialBlastConfig = getBlastAdapterSvEnabled()
|
||||
setBlastAdapterSvEnabled(useBlastAdapter)
|
||||
}
|
||||
|
||||
@After
|
||||
open fun teardown() {
|
||||
setBlastAdapterSvEnabled(mInitialBlastConfig)
|
||||
}
|
||||
|
||||
private fun getBlastAdapterSvEnabled(): Boolean {
|
||||
return Settings.Global.getInt(instrumentation.context.contentResolver,
|
||||
"use_blast_adapter_sv", 0) != 0
|
||||
}
|
||||
|
||||
private fun setBlastAdapterSvEnabled(enable: Boolean) {
|
||||
Settings.Global.putInt(instrumentation.context.contentResolver, "use_blast_adapter_sv",
|
||||
if (enable) 1 else 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@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
|
||||
)
|
||||
}
|
||||
|
||||
const val R8G8B8A8_UNORM = 1
|
||||
val defaultBufferSize = Point(640, 480)
|
||||
|
||||
// system/window.h definitions
|
||||
enum class ScalingMode() {
|
||||
FREEZE, // = 0
|
||||
SCALE_TO_WINDOW, // =1
|
||||
SCALE_CROP, // = 2
|
||||
NO_SCALE_CROP // = 3
|
||||
}
|
||||
|
||||
// system/window.h definitions
|
||||
enum class Transform(val value: Int) {
|
||||
/* flip source image horizontally */
|
||||
FLIP_H(1),
|
||||
/* flip source image vertically */
|
||||
FLIP_V(2),
|
||||
/* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
|
||||
ROT_90(4),
|
||||
/* rotate source image 180 degrees */
|
||||
ROT_180(3),
|
||||
/* rotate source image 270 degrees clock-wise */
|
||||
ROT_270(7),
|
||||
/* transforms source by the inverse transform of the screen it is displayed onto. This
|
||||
* transform is applied last */
|
||||
INVERSE_DISPLAY(0x08)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.test.taskembed
|
||||
|
||||
import android.app.Instrumentation
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
@@ -93,13 +94,15 @@ class ResizeTasksSyncTest {
|
||||
|
||||
// verify buffer size should be changed to expected values.
|
||||
assertThat(trace).layer(FIRST_ACTIVITY, frame).also {
|
||||
it.hasLayerSize(firstBounds)
|
||||
it.hasBufferSize(firstBounds)
|
||||
val firstTaskSize = Point(firstBounds.width(), firstBounds.height())
|
||||
it.hasLayerSize(firstTaskSize)
|
||||
it.hasBufferSize(firstTaskSize)
|
||||
}
|
||||
|
||||
assertThat(trace).layer(SECOND_ACTIVITY, frame).also {
|
||||
it.hasLayerSize(secondBounds)
|
||||
it.hasBufferSize(secondBounds)
|
||||
val secondTaskSize = Point(secondBounds.width(), secondBounds.height())
|
||||
it.hasLayerSize(secondTaskSize)
|
||||
it.hasBufferSize(secondTaskSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user