• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 <gui/SyncScreenCaptureListener.h>
19 #include <ui/Rect.h>
20 #include <utils/String8.h>
21 #include <functional>
22 #include "TransactionUtils.h"
23 
24 namespace android {
25 
26 namespace {
27 
28 // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
29 // individual pixel values for testing purposes.
30 class ScreenCapture : public RefBase {
31 public:
captureDisplay(DisplayCaptureArgs & captureArgs,ScreenCaptureResults & captureResults)32     static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
33                                    ScreenCaptureResults& captureResults) {
34         const auto sf = ComposerService::getComposerService();
35         SurfaceComposerClient::Transaction().apply(true);
36 
37         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
38         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
39         status_t status = sf->captureDisplay(captureArgs, captureListener);
40 
41         if (status != NO_ERROR) {
42             return status;
43         }
44         captureResults = captureListener->waitForResults();
45         return captureResults.result;
46     }
47 
captureScreen(std::unique_ptr<ScreenCapture> * sc)48     static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
49         captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
50     }
51 
captureScreen(std::unique_ptr<ScreenCapture> * sc,sp<IBinder> displayToken)52     static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
53         DisplayCaptureArgs args;
54         args.displayToken = displayToken;
55         captureDisplay(sc, args);
56     }
57 
captureDisplay(std::unique_ptr<ScreenCapture> * sc,DisplayCaptureArgs & captureArgs)58     static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
59                                DisplayCaptureArgs& captureArgs) {
60         ScreenCaptureResults captureResults;
61         ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
62         *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
63     }
64 
captureLayers(LayerCaptureArgs & captureArgs,ScreenCaptureResults & captureResults)65     static status_t captureLayers(LayerCaptureArgs& captureArgs,
66                                   ScreenCaptureResults& captureResults) {
67         const auto sf = ComposerService::getComposerService();
68         SurfaceComposerClient::Transaction().apply(true);
69 
70         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
71         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
72         status_t status = sf->captureLayers(captureArgs, captureListener);
73         if (status != NO_ERROR) {
74             return status;
75         }
76         captureResults = captureListener->waitForResults();
77         return captureResults.result;
78     }
79 
captureLayers(std::unique_ptr<ScreenCapture> * sc,LayerCaptureArgs & captureArgs)80     static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
81         ScreenCaptureResults captureResults;
82         ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
83         *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
84     }
85 
86     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
87         ASSERT_NE(nullptr, mOutBuffer);
88         ASSERT_NE(nullptr, mPixels);
89         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
90         TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
91     }
92 
93     void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
94         ASSERT_NE(nullptr, mOutBuffer);
95         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
96         const bool leftBorder = rect.left > 0;
97         const bool topBorder = rect.top > 0;
98         const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
99         const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
100 
101         if (topBorder) {
102             Rect top(rect.left, rect.top - 1, rect.right, rect.top);
103             if (leftBorder) {
104                 top.left -= 1;
105             }
106             if (rightBorder) {
107                 top.right += 1;
108             }
109             expectColor(top, color, tolerance);
110         }
111         if (leftBorder) {
112             Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
113             expectColor(left, color, tolerance);
114         }
115         if (rightBorder) {
116             Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
117             expectColor(right, color, tolerance);
118         }
119         if (bottomBorder) {
120             Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
121             if (leftBorder) {
122                 bottom.left -= 1;
123             }
124             if (rightBorder) {
125                 bottom.right += 1;
126             }
127             expectColor(bottom, color, tolerance);
128         }
129     }
130 
131     void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
132                         const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
133                         uint8_t tolerance = 0) {
134         ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
135 
136         const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
137         const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
138         // avoid checking borders due to unspecified filtering behavior
139         const int32_t offsetX = filtered ? 2 : 0;
140         const int32_t offsetY = filtered ? 2 : 0;
141         expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
142                     tolerance);
143         expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
144                     tolerance);
145         expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
146                     tolerance);
147         expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
148                     bottomRight, tolerance);
149     }
150 
checkPixel(uint32_t x,uint32_t y,uint8_t r,uint8_t g,uint8_t b)151     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
152         ASSERT_NE(nullptr, mOutBuffer);
153         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
154         const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
155         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
156             String8 err(String8::format("pixel @ (%3d, %3d): "
157                                         "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
158                                         x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
159             EXPECT_EQ(String8(), err) << err.string();
160         }
161     }
162 
getPixelColor(uint32_t x,uint32_t y)163     Color getPixelColor(uint32_t x, uint32_t y) {
164         if (!mOutBuffer || mOutBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_RGBA_8888) {
165             return {0, 0, 0, 0};
166         }
167 
168         const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
169         return {pixel[0], pixel[1], pixel[2], pixel[3]};
170     }
171 
expectFGColor(uint32_t x,uint32_t y)172     void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
173 
expectBGColor(uint32_t x,uint32_t y)174     void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
175 
expectChildColor(uint32_t x,uint32_t y)176     void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
177 
ScreenCapture(const sp<GraphicBuffer> & outBuffer)178     explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
179         if (mOutBuffer) {
180             mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
181         }
182     }
183 
~ScreenCapture()184     ~ScreenCapture() {
185         if (mOutBuffer) mOutBuffer->unlock();
186     }
187 
188 private:
189     sp<GraphicBuffer> mOutBuffer;
190     uint8_t* mPixels = nullptr;
191 };
192 } // namespace
193 } // namespace android
194