blob: d2052310332c1c960fc2b11cc4764592aafd28fb [file] [log] [blame]
//
// Copyright (C) 2019 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.
//
#include <utility>
#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
#include "AutomotiveDisplayProxyService.h"
namespace android {
namespace frameworks {
namespace automotive {
namespace display {
namespace V1_0 {
namespace implementation {
Return<sp<IGraphicBufferProducer>>
AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) {
auto it = mDisplays.find(id);
sp<IBinder> displayToken = nullptr;
sp<SurfaceControl> surfaceControl = nullptr;
if (it == mDisplays.end()) {
if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
}
if (displayToken == nullptr) {
ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
return nullptr;
}
// Get the resolution from stored display state.
ui::DisplayMode displayMode = {};
auto err = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
if (err != NO_ERROR) {
ALOGE("Failed to get display mode of %lX. "
"This display will be ignored.", (unsigned long)id);
return nullptr;
}
ui::DisplayState displayState = {};
err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
if (err != NO_ERROR) {
ALOGE("Failed to get current display status of %lX. "
"This display will be ignored.", (unsigned long)id);
return nullptr;
}
auto displayWidth = displayMode.resolution.getWidth();
auto displayHeight = displayMode.resolution.getHeight();
if ((displayState.orientation != ui::ROTATION_0) &&
(displayState.orientation != ui::ROTATION_180)) {
std::swap(displayWidth, displayHeight);
}
sp<android::SurfaceComposerClient> surfaceClient = new SurfaceComposerClient();
err = surfaceClient->initCheck();
if (err != NO_ERROR) {
ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
return nullptr;
}
// Create a SurfaceControl instance
surfaceControl = surfaceClient->createSurface(
String8::format("AutomotiveDisplay::%lX", (unsigned long)id),
displayWidth, displayHeight,
PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
if (surfaceControl == nullptr || !surfaceControl->isValid()) {
ALOGE("Failed to create SurfaceControl.");
return nullptr;
}
// Store
DisplayDesc descriptor = {displayToken, surfaceControl};
mDisplays.insert_or_assign(id, std::move(descriptor));
} else {
displayToken = it->second.token;
surfaceControl = it->second.surfaceControl;
}
// SurfaceControl::getSurface is guaranteed to be not null.
auto targetSurface = surfaceControl->getSurface();
return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
B2HGraphicBufferProducer(targetSurface->getIGraphicBufferProducer());
}
Return<bool> AutomotiveDisplayProxyService::showWindow(uint64_t id) {
auto it = mDisplays.find(id);
if (it == mDisplays.end()) {
ALOGE("Given display token is invalid or unknown.");
return false;
}
ui::DisplayState displayState;
auto err = SurfaceComposerClient::getDisplayState(it->second.token, &displayState);
if (err != NO_ERROR) {
ALOGE("Failed to get current state of the display 0x%lX", (unsigned long)id);
return false;
}
SurfaceComposerClient::Transaction t;
t.setDisplayLayerStack(it->second.token, displayState.layerStack);
t.setLayerStack(it->second.surfaceControl, displayState.layerStack);
status_t status = t.setLayer(it->second.surfaceControl, 0x7FFFFFFF)
.show(it->second.surfaceControl)
.apply();
return status == NO_ERROR;
}
Return<bool> AutomotiveDisplayProxyService::hideWindow(uint64_t id) {
auto it = mDisplays.find(id);
if (it == mDisplays.end()) {
ALOGE("Given display token is invalid or unknown.");
return false;
}
status_t status = SurfaceComposerClient::Transaction{}
.hide(it->second.surfaceControl)
.apply();
return status == NO_ERROR;
}
Return<void> AutomotiveDisplayProxyService::getDisplayIdList(getDisplayIdList_cb _cb) {
hardware::hidl_vec<uint64_t> ids;
// Get stable IDs of all available displays and get their tokens and
// descriptors.
auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
ids.resize(displayIds.size());
for (auto i = 0; i < displayIds.size(); ++i) {
ids[i] = displayIds[i].value;
}
_cb(ids);
return hardware::Void();
}
Return<void> AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDisplayInfo_cb _cb) {
HwDisplayConfig activeConfig;
HwDisplayState activeState;
sp<IBinder> displayToken;
if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
}
if (displayToken == nullptr) {
ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
} else {
ui::DisplayMode displayMode = {};
auto err = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
if (err != NO_ERROR) {
ALOGW("Failed to get display mode of %lX. "
"This display will be ignored.", (unsigned long)id);
}
ui::DisplayState displayState = {};
err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
if (err != NO_ERROR) {
ALOGW("Failed to get current display status of %lX. "
"This display will be ignored.", (unsigned long)id);
}
activeConfig.setToExternal((uint8_t*)&displayMode, sizeof(ui::DisplayMode));
activeState.setToExternal((uint8_t*)&displayState, sizeof(DisplayState));
}
_cb(activeConfig, activeState);
return hardware::Void();
}
} // namespace implementation
} // namespace V1_0
} // namespace display
} // namespace automotive
} // namespace frameworks
} // namespace android