Dịch vụ khung đơn giản này cho phép nhà cung cấp các quy trình sử dụng SurfaceFlinger/EGL trong triển khai HAL mà không liên kết libgui. AOSP cung cấp phương thức triển khai mặc định của dịch vụ này, hoạt động tốt. Tuy nhiên, nhà cung cấp cũng phải triển khai các API để cung cấp dịch vụ này trên nền tảng của họ.
package android.frameworks.automotive.display@1.0; import android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer; interface IAutomotiveDisplayProxyService { /** * Gets an IGraphicBufferProducer instance from the service. * * @param id Target's stable display identifier * * @return igbp Returns an IGraphicBufferProducer object, that can be * converted to an ANativeWindow object. */ getIGraphicBufferProducer(uint64_t id) generates (IGraphicBufferProducer igbp); /** * Sets the ANativeWindow, which is associated with the * IGraphicBufferProducer, to be visible and to take over the display. * * @param id Target display ID * * @return success Returns true on success. */ showWindow(uint64_t id) generates (bool success); /** * Sets the ANativeWindow, which is associated with the * IGraphicBufferProducer, to be invisible and to release the control * over display. * * @param id Target display ID * * @return success Returns true on success. */ hideWindow(uint64_t id) generates (bool success); /** * Returns the stable identifiers of all available displays. * * @return ids A list of stable display identifiers. */ getDisplayIdList() generates (vec<uint64_t> ids); /** * Returns the descriptor of the target display. * * @param id Stable ID of a target display. * @return cfg DisplayConfig of the active display. * @return state Current state of the active display. */ getDisplayInfo(uint64_t id) generates (HwDisplayConfig cfg, HwDisplayState state); }
Để sử dụng dịch vụ này:
- Tải
IAutomotiveDisplayProxyService
.android::sp<IAutomotiveDisplayProxyService> windowProxyService = IAutomotiveDisplayProxyService::getService("default"); if (windowProxyService == nullptr) { LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting."; return 1; }
- Truy xuất thông tin màn hình đang hoạt động từ dịch vụ để xác định độ phân giải.
// We use the first display in the list as the primary. pWindowProxy->getDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) { DisplayConfig *pConfig = (DisplayConfig*)dpyConfig.data(); mWidth = pConfig->resolution.getWidth(); mHeight = pConfig->resolution.getHeight(); ui::DisplayState* pState = (ui::DisplayState*)dpyState.data(); if (pState->orientation != ui::ROTATION_0 && pState->orientation != ui::ROTATION_180) { // rotate std::swap(mWidth, mHeight); } LOG(DEBUG) << "Display resolution is " << mWidth << " x " << mHeight; });
- Truy xuất
IGraphicBufferProducer
phần cứng (hoặc HIDL GraphicBufferProducer (HGBP) từIAutomotiveDisplayProxyService
:mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId); if (mGfxBufferProducer == nullptr) { LOG(ERROR) << "Failed to get IGraphicBufferProducer from " << "IAutomotiveDisplayProxyService."; return false; }
- Nhận
SurfaceHolder
từ một HGBP đã truy xuất bằng cách sử dụng APIlibbufferqueueconverter
:mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer); if (mSurfaceHolder == nullptr) { LOG(ERROR) << "Failed to get a Surface from HGBP."; return false; }
- Chuyển đổi
SurfaceHolder
thành một cửa sổ gốc bằng cách sử dụng hàm APIlibbufferqueueconverter
:mWindow = getNativeWindow(mSurfaceHolder.get()); if (mWindow == nullptr) { LOG(ERROR) << "Failed to get a native window from Surface."; return false; }
- Tạo bề mặt cửa sổ EGL với một cửa sổ gốc rồi kết xuất:
// Set up our OpenGL ES context associated with the default display mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mDisplay == EGL_NO_DISPLAY) { LOG(ERROR) << "Failed to get egl display"; return false; } ... // Create the EGL render target surface mSurface = eglCreateWindowSurface(mDisplay, egl_config, mWindow, nullptr); if (mSurface == EGL_NO_SURFACE) { LOG(ERROR) << "eglCreateWindowSurface failed."; return false; } ...
- Gọi
IAutomotiveDisplayProxyService::showWindow()
tới hiển thị khung hiển thị được kết xuất trên màn hình. Dịch vụ này có mức độ ưu tiên cao nhất và do đó, luôn giành quyền kiểm soát màn hình từ chủ sở hữu hiện tại:mAutomotiveDisplayProxyService->showWindow();
Xem service.cpp
và GlWrapper.cpp
trong $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/
cho
thêm thông tin chi tiết về việc triển khai.
Việc triển khai EVS HAL (Lớp trừu tượng phần cứng) cần có các thư viện bổ sung hiển thị trong in đậm bên dưới.
cc_binary { name: "android.hardware.automotive.evs@1.1-sample", vendor: true, srcs: [ ... ], shared_libs: [ ... "libbufferqueueconverter", "android.hidl.token@1.0-utils", "android.frameworks.automotive.display@1.0", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", ],
Hỗ trợ nhiều màn hình
Hiển thị liệt kê thiết bị và truy xuất thông tin hiển thị
Giống như việc liệt kê thiết bị máy ảnh, khung EVS cung cấp một phương thức để
liệt kê các màn hình có sẵn.
mã nhận dạng hiển thị tĩnh mã hoá một mã nhận dạng dài một kiểu, mã hiển thị
thông tin cổng ở byte dưới và Extended Display IDentification
Data
ở bit trên.
IAutomotiveDisplayProxyService::getDisplayIdList()
trả về một danh sách
mã hiển thị của màn hình thực tại địa phương, có sẵn cho dịch vụ EVS,
và IEvsEnumerator::getDisplayIdList()
trả về danh sách màn hình
cổng phát hiện thấy mà hiển thị sẽ được kết nối. Mã đầu tiên trong danh sách luôn là
màn hình chính.
interface IEvsEnumerator extends @1.0::IEvsEnumerator { ... /** * Returns a list of all EVS displays available to the system * * @return displayIds Identifiers of available displays. */ getDisplayIdList() generates (vec<uint8_t> displayIds); };
Mở thiết bị hiển thị đích
Ứng dụng EVS gọi IEvsEnumerator::openDisplay_1_1() với màn hình đích số cổng:
android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId); if (pDisplay.get() == nullptr) { LOG(ERROR) << "EVS Display unavailable. Exiting."; return 1; }
Lưu ý: Mỗi lần bạn chỉ có thể sử dụng một màn hình. tức là ứng dụng EVS hiện tại sẽ mất màn hình khi một ứng dụng EVS khác yêu cầu mở màn hình, ngay cả khi chúng không giống nhau.