blob: b713334f999509be83d45ca3a889204e6489204c [file] [log] [blame]
/*
* 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.
*/
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
#include "DisplayTransactionTestHelpers.h"
namespace android {
namespace {
class HandleTransactionLockedTest : public DisplayTransactionTest {
public:
template <typename Case>
void setupCommonPreconditions();
template <typename Case, bool connected>
static void expectHotplugReceived(mock::EventThread*);
template <typename Case>
void setupCommonCallExpectationsForConnectProcessing();
template <typename Case>
void setupCommonCallExpectationsForDisconnectProcessing();
template <typename Case>
void processesHotplugConnectCommon();
template <typename Case>
void ignoresHotplugConnectCommon();
template <typename Case>
void processesHotplugDisconnectCommon();
template <typename Case>
void verifyDisplayIsConnected(const sp<IBinder>& displayToken);
template <typename Case>
void verifyPhysicalDisplayIsConnected();
void verifyDisplayIsNotConnected(const sp<IBinder>& displayToken);
};
template <typename Case>
void HandleTransactionLockedTest::setupCommonPreconditions() {
// Wide color displays support is configured appropriately
Case::WideColorSupport::injectConfigChange(this);
// SurfaceFlinger will use a test-controlled factory for BufferQueues
injectFakeBufferQueueFactory();
// SurfaceFlinger will use a test-controlled factory for native window
// surfaces.
injectFakeNativeWindowSurfaceFactory();
}
template <typename Case, bool connected>
void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
const auto convert = [](auto physicalDisplayId) {
return std::make_optional(DisplayId{physicalDisplayId});
};
EXPECT_CALL(*eventThread,
onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
.Times(1);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
Case::Display::setupHwcHotplugCallExpectations(this);
Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this);
Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
Case::Display::setupHwcGetActiveConfigCallExpectations(this);
Case::WideColorSupport::setupComposerCallExpectations(this);
Case::HdrSupport::setupComposerCallExpectations(this);
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
expectHotplugReceived<Case, true>(mEventThread);
expectHotplugReceived<Case, true>(mSFEventThread);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
expectHotplugReceived<Case, false>(mEventThread);
expectHotplugReceived<Case, false>(mSFEventThread);
}
template <typename Case>
void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
// The display device should have been set up in the list of displays.
ASSERT_TRUE(hasDisplayDevice(displayToken));
const auto& device = getDisplayDevice(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
std::optional<DisplayDeviceState::Physical> expectedPhysical;
if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
expectedPhysical = {.id = *displayId,
.type = *connectionType,
.hwcDisplayId = *hwcDisplayId};
}
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
EXPECT_EQ(expectedPhysical, current.physical);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
EXPECT_EQ(expectedPhysical, draw.physical);
}
template <typename Case>
void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
// HWComposer should have an entry for the display
EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
// SF should have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1);
auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
verifyDisplayIsConnected<Case>(displayToken);
}
void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
EXPECT_FALSE(hasDisplayDevice(displayToken));
EXPECT_FALSE(hasCurrentDisplayState(displayToken));
EXPECT_FALSE(hasDrawingDisplayState(displayToken));
}
template <typename Case>
void HandleTransactionLockedTest::processesHotplugConnectCommon() {
// --------------------------------------------------------------------
// Preconditions
setupCommonPreconditions<Case>();
// A hotplug connect event is enqueued for a display
Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// --------------------------------------------------------------------
// Call Expectations
setupCommonCallExpectationsForConnectProcessing<Case>();
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
verifyPhysicalDisplayIsConnected<Case>();
// --------------------------------------------------------------------
// Cleanup conditions
EXPECT_CALL(*mComposer,
setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
.WillOnce(Return(Error::NONE));
EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
}
template <typename Case>
void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
// --------------------------------------------------------------------
// Preconditions
setupCommonPreconditions<Case>();
// A hotplug connect event is enqueued for a display
Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// HWComposer should not have an entry for the display
EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
}
template <typename Case>
void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
// --------------------------------------------------------------------
// Preconditions
setupCommonPreconditions<Case>();
// A hotplug disconnect event is enqueued for a display
Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
// The display is already completely set up.
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
// --------------------------------------------------------------------
// Call Expectations
EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
.Times(0);
setupCommonCallExpectationsForDisconnectProcessing<Case>();
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// HWComposer should not have an entry for the display
EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
// SF should not have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
}
TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
}
TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
processesHotplugConnectCommon<SimpleExternalDisplayCase>();
}
TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
// Inject both a primary and external display.
PrimaryDisplayVariant::injectHwcDisplay(this);
ExternalDisplayVariant::injectHwcDisplay(this);
// TODO: This is an unnecessary call.
EXPECT_CALL(*mComposer,
getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
.WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
Return(Error::NONE)));
ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
}
TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
using Case = SimplePrimaryDisplayCase;
// --------------------------------------------------------------------
// Preconditions
setupCommonPreconditions<Case>();
// A hotplug connect event is enqueued for a display
Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// A hotplug disconnect event is also enqueued for the same display
Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
// --------------------------------------------------------------------
// Call Expectations
setupCommonCallExpectationsForConnectProcessing<Case>();
setupCommonCallExpectationsForDisconnectProcessing<Case>();
EXPECT_CALL(*mComposer,
setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
.WillOnce(Return(Error::NONE));
EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// HWComposer should not have an entry for the display
EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
// SF should not have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
using Case = SimplePrimaryDisplayCase;
// --------------------------------------------------------------------
// Preconditions
setupCommonPreconditions<Case>();
// The display is already completely set up.
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
// A hotplug disconnect event is enqueued for a display
Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
// A hotplug connect event is also enqueued for the same display
Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// --------------------------------------------------------------------
// Call Expectations
setupCommonCallExpectationsForConnectProcessing<Case>();
setupCommonCallExpectationsForDisconnectProcessing<Case>();
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
// A new display should be connected in its place
verifyPhysicalDisplayIsConnected<Case>();
// --------------------------------------------------------------------
// Cleanup conditions
EXPECT_CALL(*mComposer,
setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
.WillOnce(Return(Error::NONE));
EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
// Preconditions
// The HWC supports at least one virtual display
injectMockComposer(1);
setupCommonPreconditions<Case>();
// A virtual display was added to the current state, and it has a
// surface(producer)
sp<BBinder> displayToken = new BBinder();
DisplayDeviceState state;
state.isSecure = static_cast<bool>(Case::Display::SECURE);
sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
state.surface = surface;
mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR)));
EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT),
Return(NO_ERROR)));
EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
Case::WideColorSupport::setupComposerCallExpectations(this);
Case::HdrSupport::setupComposerCallExpectations(this);
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// The display device should have been set up in the list of displays.
verifyDisplayIsConnected<Case>(displayToken);
// --------------------------------------------------------------------
// Cleanup conditions
EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
.WillOnce(Return(Error::NONE));
EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
// Cleanup
mFlinger.mutableCurrentState().displays.removeItem(displayToken);
mFlinger.mutableDrawingState().displays.removeItem(displayToken);
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
// Preconditions
// The HWC supports at least one virtual display
injectMockComposer(1);
setupCommonPreconditions<Case>();
// A virtual display was added to the current state, but it does not have a
// surface.
sp<BBinder> displayToken = new BBinder();
DisplayDeviceState state;
state.isSecure = static_cast<bool>(Case::Display::SECURE);
mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// There will not be a display device set up.
EXPECT_FALSE(hasDisplayDevice(displayToken));
// The drawing display state will be set from the current display state.
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
// Preconditions
// A virtual display is set up but is removed from the current state.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
mFlinger.mutableHwcDisplayData().try_emplace(displayId);
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
mFlinger.mutableCurrentState().displays.removeItem(existing.token());
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
}
TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr uint32_t oldLayerStack = 0u;
constexpr uint32_t newLayerStack = 123u;
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
// There is a change to the layerStack state
display.mutableDrawingDisplayState().layerStack = oldLayerStack;
display.mutableCurrentDisplayState().layerStack = newLayerStack;
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
}
TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr ui::Rotation oldTransform = ui::ROTATION_0;
constexpr ui::Rotation newTransform = ui::ROTATION_180;
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
// There is a change to the orientation state
display.mutableDrawingDisplayState().orientation = oldTransform;
display.mutableCurrentDisplayState().orientation = newTransform;
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
}
TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
using Case = NonHwcVirtualDisplayCase;
const Rect oldLayerStackRect(0, 0, 0, 0);
const Rect newLayerStackRect(0, 0, 123, 456);
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
// There is a change to the layerStackSpaceRect state
display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect;
display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect;
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
}
TEST_F(HandleTransactionLockedTest, processesDisplayRectChanges) {
using Case = NonHwcVirtualDisplayCase;
const Rect oldDisplayRect(0, 0);
const Rect newDisplayRect(123, 456);
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
// There is a change to the layerStackSpaceRect state
display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldDisplayRect;
display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newDisplayRect;
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
EXPECT_EQ(newDisplayRect, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
}
TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr int oldWidth = 0;
constexpr int oldHeight = 10;
constexpr int newWidth = 123;
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
// Setup injection expectations
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
display.inject();
// There is a change to the layerStackSpaceRect state
display.mutableDrawingDisplayState().width = oldWidth;
display.mutableDrawingDisplayState().height = oldHeight;
display.mutableCurrentDisplayState().width = newWidth;
display.mutableCurrentDisplayState().height = oldHeight;
// --------------------------------------------------------------------
// Call Expectations
EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(newWidth, oldHeight))).Times(1);
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
}
TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr int oldWidth = 0;
constexpr int oldHeight = 10;
constexpr int newHeight = 123;
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
// Setup injection expectations
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
display.inject();
// There is a change to the layerStackSpaceRect state
display.mutableDrawingDisplayState().width = oldWidth;
display.mutableDrawingDisplayState().height = oldHeight;
display.mutableCurrentDisplayState().width = oldWidth;
display.mutableCurrentDisplayState().height = newHeight;
// --------------------------------------------------------------------
// Call Expectations
EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(oldWidth, newHeight))).Times(1);
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
}
TEST_F(HandleTransactionLockedTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr uint32_t kOldWidth = 567;
constexpr uint32_t kOldHeight = 456;
const auto kOldSize = Rect(kOldWidth, kOldHeight);
constexpr uint32_t kNewWidth = 234;
constexpr uint32_t kNewHeight = 123;
const auto kNewSize = Rect(kNewWidth, kNewHeight);
// --------------------------------------------------------------------
// Preconditions
// A display is set up
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
// Setup injection expectations
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillOnce(DoAll(SetArgPointee<1>(kOldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(kOldHeight), Return(0)));
display.inject();
// There is a change to the layerStackSpaceRect state
display.mutableDrawingDisplayState().width = kOldWidth;
display.mutableDrawingDisplayState().height = kOldHeight;
display.mutableDrawingDisplayState().layerStackSpaceRect = kOldSize;
display.mutableDrawingDisplayState().orientedDisplaySpaceRect = kOldSize;
display.mutableCurrentDisplayState().width = kNewWidth;
display.mutableCurrentDisplayState().height = kNewHeight;
display.mutableCurrentDisplayState().layerStackSpaceRect = kNewSize;
display.mutableCurrentDisplayState().orientedDisplaySpaceRect = kNewSize;
// --------------------------------------------------------------------
// Call Expectations
EXPECT_CALL(*displaySurface, resizeBuffers(kNewSize.getSize())).Times(1);
// --------------------------------------------------------------------
// Invocation
mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
EXPECT_EQ(display.mutableDisplayDevice()->getBounds(), kNewSize);
EXPECT_EQ(display.mutableDisplayDevice()->getWidth(), kNewWidth);
EXPECT_EQ(display.mutableDisplayDevice()->getHeight(), kNewHeight);
EXPECT_EQ(display.mutableDisplayDevice()->getOrientedDisplaySpaceRect(), kNewSize);
EXPECT_EQ(display.mutableDisplayDevice()->getLayerStackSpaceRect(), kNewSize);
}
} // namespace
} // namespace android