1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.test 17 18 import android.annotation.ColorInt 19 import android.graphics.Bitmap 20 import android.graphics.Color 21 import android.graphics.Rect 22 import android.util.Log 23 import androidx.test.ext.junit.rules.ActivityScenarioRule 24 import android.tools.common.flicker.subject.layers.LayerSubject 25 import android.tools.common.traces.surfaceflinger.LayersTrace 26 import android.tools.device.traces.io.ResultWriter 27 import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor 28 import android.tools.device.traces.monitors.withSFTracing 29 import junit.framework.Assert 30 import org.junit.After 31 import org.junit.Before 32 import org.junit.Rule 33 import java.io.FileOutputStream 34 import java.io.IOException 35 import java.util.concurrent.CountDownLatch 36 37 open class SurfaceTracingTestBase(useBlastAdapter: Boolean) : 38 SurfaceViewBufferTestBase(useBlastAdapter) { 39 @get:Rule 40 var scenarioRule: ActivityScenarioRule<MainActivity> = 41 ActivityScenarioRule<MainActivity>(MainActivity::class.java) 42 43 @Before 44 override fun setup() { 45 super.setup() 46 stopLayerTrace() 47 addSurfaceView() 48 } 49 50 @After 51 override fun teardown() { 52 super.teardown() 53 scenarioRule.getScenario().close() 54 } 55 56 fun withTrace(predicate: (it: MainActivity) -> Unit): LayersTrace { 57 return withSFTracing(TRACE_FLAGS) { 58 scenarioRule.getScenario().onActivity { 59 predicate(it) 60 } 61 } 62 } 63 64 fun withTrace(predicate: () -> Unit): LayersTrace { 65 return withSFTracing(TRACE_FLAGS) { 66 predicate() 67 } 68 } 69 70 fun runOnUiThread(predicate: (it: MainActivity) -> Unit) { 71 scenarioRule.getScenario().onActivity { 72 predicate(it) 73 } 74 } 75 76 private fun addSurfaceView() { 77 lateinit var surfaceReadyLatch: CountDownLatch 78 scenarioRule.getScenario().onActivity { 79 surfaceReadyLatch = it.addSurfaceView(defaultBufferSize) 80 } 81 surfaceReadyLatch.await() 82 // sleep to finish animations 83 instrumentation.waitForIdleSync() 84 } 85 86 private fun stopLayerTrace() { 87 LayersTraceMonitor().stop(ResultWriter()) 88 } 89 90 fun checkPixels(bounds: Rect, @ColorInt color: Int) { 91 val screenshot = instrumentation.getUiAutomation().takeScreenshot() 92 val pixels = IntArray(screenshot.width * screenshot.height) 93 screenshot.getPixels(pixels, 0, screenshot.width, 0, 0, screenshot.width, screenshot.height) 94 for (i in bounds.left + 10..bounds.right - 10) { 95 for (j in bounds.top + 10..bounds.bottom - 10) { 96 val actualColor = pixels[j * screenshot.width + i] 97 if (actualColor != color) { 98 val screenshotPath = instrumentation.targetContext 99 .getExternalFilesDir(null)?.resolve("screenshot.png") 100 try { 101 FileOutputStream(screenshotPath).use { out -> 102 screenshot.compress(Bitmap.CompressFormat.PNG, 100, out) 103 } 104 Log.e("SurfaceViewBufferTests", "Bitmap written to $screenshotPath") 105 } catch (e: IOException) { 106 Log.e("SurfaceViewBufferTests", "Error writing bitmap to file", e) 107 } 108 } 109 Assert.assertEquals("Checking $bounds found mismatch $i,$j", 110 Color.valueOf(color), Color.valueOf(actualColor)) 111 } 112 } 113 } 114 115 private companion object { 116 private const val TRACE_FLAGS = 117 (1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC 118 } 119 } 120