blob: d73506b86fb45dc814cb850ce1c3f59cadefd39e [file] [log] [blame]
Valerie Haue9137b72019-08-27 13:22:18 -07001/*
2 * Copyright (C) 2019 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#pragma once
17
18#include <ui/Rect.h>
19#include <utils/String8.h>
20#include "TransactionUtils.h"
21
22namespace android {
23
24namespace {
25
26// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
27// individual pixel values for testing purposes.
28class ScreenCapture : public RefBase {
29public:
30 static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
31 captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
32 }
33
34 static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
35 const auto sf = ComposerService::getComposerService();
36 SurfaceComposerClient::Transaction().apply(true);
37
chaviwd2432892020-07-24 17:42:39 -070038 DisplayCaptureArgs args;
39 args.displayToken = displayToken;
40
41 ScreenCaptureResults captureResults;
42 ASSERT_EQ(NO_ERROR, sf->captureDisplay(args, captureResults));
43 *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
Valerie Haue9137b72019-08-27 13:22:18 -070044 }
45
46 static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
47 Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
48 sp<ISurfaceComposer> sf(ComposerService::getComposerService());
49 SurfaceComposerClient::Transaction().apply(true);
50
chaviw3efadb12020-07-27 10:07:15 -070051 LayerCaptureArgs args;
52 args.layerHandle = parentHandle;
53 args.sourceCrop = crop;
54 args.frameScale = frameScale;
55 args.childrenOnly = false;
56
57 ScreenCaptureResults captureResults;
58 ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
59 *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
Valerie Haue9137b72019-08-27 13:22:18 -070060 }
61
62 static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
63 Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
64 sp<ISurfaceComposer> sf(ComposerService::getComposerService());
65 SurfaceComposerClient::Transaction().apply(true);
66
chaviw3efadb12020-07-27 10:07:15 -070067 LayerCaptureArgs args;
68 args.layerHandle = parentHandle;
69 args.sourceCrop = crop;
70 args.frameScale = frameScale;
71 args.childrenOnly = true;
72
73 ScreenCaptureResults captureResults;
74 ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
75 *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
Valerie Haue9137b72019-08-27 13:22:18 -070076 }
77
78 static void captureChildLayersExcluding(
79 std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
80 std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
81 sp<ISurfaceComposer> sf(ComposerService::getComposerService());
82 SurfaceComposerClient::Transaction().apply(true);
83
chaviw3efadb12020-07-27 10:07:15 -070084 LayerCaptureArgs args;
85 args.layerHandle = parentHandle;
86 args.pixelFormat = ui::PixelFormat::RGBA_8888;
87 args.sourceCrop = Rect::EMPTY_RECT;
88 args.excludeHandles = excludeLayers;
89 args.frameScale = 1.0f;
90 args.childrenOnly = true;
91
92 ScreenCaptureResults captureResults;
93 ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
94 *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
Valerie Haue9137b72019-08-27 13:22:18 -070095 }
96
97 void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
98 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
Valerie Haue271df92019-09-06 09:23:22 -070099 TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
Valerie Haue9137b72019-08-27 13:22:18 -0700100 }
101
102 void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
103 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
104 const bool leftBorder = rect.left > 0;
105 const bool topBorder = rect.top > 0;
106 const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
107 const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
108
109 if (topBorder) {
110 Rect top(rect.left, rect.top - 1, rect.right, rect.top);
111 if (leftBorder) {
112 top.left -= 1;
113 }
114 if (rightBorder) {
115 top.right += 1;
116 }
117 expectColor(top, color, tolerance);
118 }
119 if (leftBorder) {
120 Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
121 expectColor(left, color, tolerance);
122 }
123 if (rightBorder) {
124 Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
125 expectColor(right, color, tolerance);
126 }
127 if (bottomBorder) {
128 Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
129 if (leftBorder) {
130 bottom.left -= 1;
131 }
132 if (rightBorder) {
133 bottom.right += 1;
134 }
135 expectColor(bottom, color, tolerance);
136 }
137 }
138
139 void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
140 const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
141 uint8_t tolerance = 0) {
142 ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
143
144 const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
145 const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
146 // avoid checking borders due to unspecified filtering behavior
147 const int32_t offsetX = filtered ? 2 : 0;
148 const int32_t offsetY = filtered ? 2 : 0;
149 expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
150 tolerance);
151 expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
152 tolerance);
153 expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
154 tolerance);
155 expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
156 bottomRight, tolerance);
157 }
158
159 void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
160 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
161 const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
162 if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
163 String8 err(String8::format("pixel @ (%3d, %3d): "
164 "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
165 x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
166 EXPECT_EQ(String8(), err) << err.string();
167 }
168 }
169
170 void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
171
172 void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
173
174 void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
175
176 explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
177 mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
178 }
179
180 ~ScreenCapture() { mOutBuffer->unlock(); }
181
182private:
183 sp<GraphicBuffer> mOutBuffer;
184 uint8_t* mPixels = nullptr;
185};
186} // namespace
187} // namespace android