/* * Copyright (c) Hisilicon Technologies Co., Ltd.. 2016-2019. All rights reserved. * Description: bootvideo ui controls */ #include "BootvideoUI.h" #include #include #include #include #include #include #include #include #include #include "BootvideoConfiger.h" #undef LOG_TAG #define LOG_TAG "BootVideo" namespace android { using std::string; using std::unique_ptr; using std::make_unique; using namespace dolgles; const string BaseView::VIEW_PNG_PATH = "/system/product/etc/"; const string MuteView::MUTE_PNG_NAME = "boot_video_mute.png"; const string VolumeBarView::VOLUME_PNG_NAME = "boot_video_panel.png"; const string CountDownView::COUNTDOWN_BG_NAME = "boot_video_count_bg.png"; const string CountDownView::COUNTDOWN_CH_NAME = "boot_video_count_ch.png"; const string CountDownView::COUNTDOWN_EN_NAME = "boot_video_count_en.png"; pthread_mutex_t g_mtxView = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t g_mtxFinish = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t g_mtxReady = PTHREAD_MUTEX_INITIALIZER; Mutex g_mtxSideBand; Condition g_mCdtSideBand; static sem_t g_uiLock; static bool InitUiLock() { if (sem_init(&g_uiLock, 0, 0) < 0) { ALOGE("InitUiLock: create g_uiLock semaphore failure"); return false; } return true; } static void DestroyUiLock() { sem_destroy(&g_uiLock); } static void WaitUiLock() { if (sem_wait(&g_uiLock) < 0) { ALOGE("WaitUiLock: waiting g_uiLock semaphore failure"); } } static bool PostUiLock() { if (sem_post(&g_uiLock) < 0) { // sem_post to release lock ALOGE("PostUiLock: post g_uiLock semaphore failure"); return false; } return true; } BootvideoUI::BootvideoUI() : isGlesReady(false) { } BootvideoUI::~BootvideoUI() { } void BootvideoUI::onFirstRef() { run("BootvideoUI", ANDROID_PRIORITY_DISPLAY); return; } status_t BootvideoUI::readyToRun() { // wait surface flinger start WaitSurfaceFlinger(); // create surface bool isSuc = CreateSurface(); if (!isSuc) { ALOGE("CreateSurface: surface create failure"); return NO_ERROR; } // set player surface sideband InitSurfacePlayer(); // init ui surface of libgles InitSurfaceUI(); // set ready succes SetUIReady(); return NO_ERROR; } bool BootvideoUI::WaitSurfaceFlinger() const { int waitCount = 0; const int waitRetries = 10; // wait retries is 10 const int waitDelayUs = 50000; // wait 50ms char propertyValue[PROPERTY_VALUE_MAX] = {0}; property_get("init.svc.surfaceflinger", propertyValue, nullptr); while (strncmp(propertyValue, "running", strlen("running")) != 0) { if (((++waitCount) % waitRetries) == 0) { ALOGI("WaitSurfaceFlinger: retry[%d]", waitCount); } usleep(waitDelayUs); property_get("init.svc.surfaceflinger", propertyValue, nullptr); } return true; } int BootvideoUI::GetDisplayOrientation() const { return surface->GetDisplayOrientation(); } bool BootvideoUI::CreateSurface() { #if PLATFORM_SDK_VERSION <= __ANDROID_API_Q__ surface = new SurfaceQverUI(); #else surface = new SurfaceSverUI(); #endif surface->CreateSurface(); surfaceW = surface->surfaceW; surfaceH = surface->surfaceH; return true; } sp BootvideoUI::GetSideBand() const { Mutex::Autolock autoLock(g_mtxSideBand); if (surfacePlayer == nullptr) { g_mCdtSideBand.wait(g_mtxSideBand); } if (surfacePlayer != nullptr) { return surfacePlayer->getIGraphicBufferProducer(); } else { ALOGE("GetSideBand: surfacePlayer is NULL"); return nullptr; } } bool BootvideoUI::InitSurfacePlayer() { Mutex::Autolock autoLock(g_mtxSideBand); surfacePlayer = surface->controlPlayer->getSurface(); g_mCdtSideBand.signal(); return true; } bool BootvideoUI::InitSurfaceUI() { // get Surface surfaceUi = surface->controlUi->getSurface(); // set buffer count int ret = native_window_set_buffer_count(surfaceUi.get(), NATIVE_WINDOW_BUFFER_COUNT); ALOGE("InitSurfaceUI: native_window_set_buffer_count(%d)", ret); // create DolGLDrawSurface glesSurface = make_unique(); if (glesSurface == nullptr) { ALOGE("InitSurfaceUI: glesSurface is NULL"); return false; } glesSurface->DolCreateGLContext(); // init DolGLES ret = glesSurface->Init(DOL_ENDABLE_DRAW_TEXT | DOL_ENDABLE_BLIT | DOL_ENDABLE_DISPLAY_BITMAP | DOL_ENDABLE_DRAW_RECT | DOL_ENDABLE_DRAW_ROUND | DOL_ENDABLE_DISPLAY_FBO | DOL_ENDABLE_FBO); if (ret != DOL_NO_ERROR) { ALOGE("InitSurfaceUI: init DolGLES failure(%d)", ret); return false; } // Load font lib ret = glesSurface->DolLoadFont(TEXT_FONT_PATH, TEXT_FONT_SIZE); if (ret != DOL_NO_ERROR) { ALOGE("InitSurfaceUI: load font lib failure(%d)", ret); return false; } ret = glesSurface->DolConnectWindowSurface(surfaceUi.get()); if (ret != DOL_NO_ERROR) { ALOGE("InitSurfaceUI: create GLWindowSurface failure(%d)", ret); return false; } ALOGI("InitSurfaceUI: init DolGLES succes"); return true; } void BootvideoUI::Release() { // free gles if (glesSurface != nullptr) { glesSurface->DolDestoryGLContext(); glesSurface.reset(); glesSurface = nullptr; } // free native surfacePlayer.clear(); surfaceUi.clear(); surface->controlPlayer.clear(); surface->controlUi.clear(); } bool BootvideoUI::threadLoop() { auto configer = make_unique(); if (!configer->IsFeature(BootvideoConfiger::PROPERTY_EN_UI)) { ALOGE("threadLoop: ui feature is unable of config.xml"); return false; } // init lock of ui InitUiLock(); // draw view const int waitDelayUs = 200000; // wait 200ms bool isEnableMute = configer->IsFeature(BootvideoConfiger::PROPERTY_EN_VOLUMEMUTE); bool isEnableVolume = configer->IsFeature(BootvideoConfiger::PROPERTY_EN_VOLUMEBAR); bool isEnableCountDown = configer->IsFeature(BootvideoConfiger::PROPERTY_EN_COUNTDOWN); muteView = new MuteView(surfaceW, surfaceH, surfaceScale); volumeView = new VolumeBarView(surfaceW, surfaceH, surfaceScale); countView = new CountDownView(surfaceW, surfaceH, surfaceScale); muteView->InitView(); volumeView->InitView(); countView->InitView(); CheckViewRefresh(waitDelayUs, isEnableMute, isEnableVolume, isEnableCountDown); muteView = nullptr; volumeView = nullptr; countView = nullptr; // release resource then return Release(); // destory tick of sem DestroyUiLock(); return false; } void BootvideoUI::CheckViewRefresh(int waitDelayUs, bool isEnableMute, bool isEnableVolume, bool isEnableCountDown) { while (!CheckExit()) { usleep(waitDelayUs); WaitUiLock(); if (isEnableMute) { muteView->DrawView(glesSurface); } if (isEnableVolume) { volumeView->DrawView(glesSurface); } if (isEnableCountDown) { countView->DrawView(glesSurface); } // refresh ui surface int ret = glesSurface->DolRefreshOnSrceen(); if (ret != DOL_NO_ERROR) { ALOGE("threadLoop: DolRefreshOnSrceen failure(%d)", ret); } } ALOGE("CheckViewRefresh: finished"); } // create bitmap and decode png file bool BaseView::DecodePNG(DolBitmapInfo &bitmapInfo, const string path) { char png_header[HEAD_BYTES]; png_structp png_ptr; png_infop info_ptr; char trustPath[PATH_MAX] = {0}; if (realpath(path.c_str(), trustPath) == NULL) { ALOGE("DecodePNG: path is not canonical %s", path.c_str()); return false; } // open file and test for it being a png FILE *file = fopen(trustPath, "rb"); if (file == nullptr) { ALOGE("DecodePNG: open the png file(%s) failure", path.c_str()); return false; } fread(png_header, 1, HEAD_BYTES, file); if (png_sig_cmp((png_bytep)png_header, 0, HEAD_BYTES)) { ALOGE("DecodePNG: %s not a png file", path.c_str()); fclose(file); return false; } // initialise structures for reading a png file png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { ALOGE("DecodePNG: %s png_ptr create failure", path.c_str()); fclose(file); return false; } info_ptr = png_create_info_struct(png_ptr); // I/O initialisation methods png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, HEAD_BYTES); // Required // read png info and pixel png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); unsigned int width = 0; unsigned int height = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, nullptr, nullptr, nullptr, nullptr, nullptr); ALOGD("DecodePNG: the png file(%s) is %d * %d", trustPath, width, height); // get png rows png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr); if (row_pointers == nullptr) { ALOGE("DecodePNG: png_get_rows failure, row_pointers is NULL"); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(file); return false; } // malloc pixel, pixel has rgba(4 byte) char* rgba = nullptr; if ((width <= PNG_MAX_PIXEL) && (height <= PNG_MAX_PIXEL)) { const unsigned int rgbaSize = width * height * RGBA_BYTES; rgba = static_cast(malloc(rgbaSize)); } if (rgba == nullptr) { ALOGE("DecodePNG: malloc bits(%d*%d*4) of the png file(%s) failure", width, height, path.c_str()); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(file); return false; } unsigned int pos = 0; const unsigned int maxRow = height; const unsigned int maxCol = width * RGBA_BYTES; const int colorRed = 0; const int colorGreen = 1; const int colorBlue = 2; const int colorAlpha = 3; for (unsigned int row = 0; row < maxRow; row++) { for (unsigned int col = 0; col < maxCol; col += RGBA_BYTES) { rgba[pos++] = row_pointers[row][col + colorRed]; // colorRed rgba[pos++] = row_pointers[row][col + colorGreen]; // colorGreen rgba[pos++] = row_pointers[row][col + colorBlue]; // colorBlue rgba[pos++] = row_pointers[row][col + colorAlpha]; // colorAlpha } } // clean up after the read, and free any memory allocated png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(file); // set bitmap info bitmapInfo.bitmap = reinterpret_cast(rgba); bitmapInfo.format = CAPTION_OSD_PF_8888; bitmapInfo.srcRect = {0, 0, width, height}; return true; } // free bitmap void BaseView::FreePNG(DolBitmapInfo &bitmapInfo) { if (bitmapInfo.bitmap != nullptr) { free(bitmapInfo.bitmap); bitmapInfo.bitmap = nullptr; } } BaseView::BaseView(unsigned int tempW, unsigned int tempH, unsigned int tempScale) { w = static_cast(tempW); h = static_cast(tempH); scale = static_cast(tempScale); } BaseView::~BaseView() { } // mute view MuteView::MuteView(unsigned int tempW, unsigned int tempH, unsigned int tempScale) : BaseView(tempW, tempH, tempScale) { isAble = false; isMute = false; bitmapInfo.bitmap = nullptr; bitmapInfo.dstRect = {0, 0, 0, 0}; bitmapInfo.srcRect = {0, 0, 0, 0}; bitmapInfo.format = CAPTION_OSD_PF_8888; } void MuteView::InitView() { const unsigned short width = 192; // 192 is 1/20 of 3840, which is 4k mode const unsigned short height = 108; // 108 is 1/20 of 2160, which is 4k mode if (DecodePNG(bitmapInfo, (VIEW_PNG_PATH + MUTE_PNG_NAME).c_str())) { const unsigned int tmpW = bitmapInfo.srcRect.width > width ? width : bitmapInfo.srcRect.width; const unsigned int tmpH = bitmapInfo.srcRect.height > height ? height : bitmapInfo.srcRect.height; const unsigned int tmpS = scale < 2 ? scale : 2; // 2 is default 4k mode scale const unsigned int bitmapW = tmpW * tmpS; const unsigned int bitmapH = tmpH * tmpS; bitmapInfo.dstRect.width = bitmapW; bitmapInfo.dstRect.height = bitmapH; bitmapInfo.dstRect.x = w - bitmapW - MUTE_PNG_MARGIN; // the extreme right corner of the screen bitmapInfo.dstRect.y = h - bitmapH - MUTE_PNG_MARGIN; // at the bottom of the screen is the most } else { ALOGE("MuteView::InitView: decode bitmapInfo failure"); } } void MuteView::SetMuteInfo(const bool able, const bool mute) { isAble = able; isMute = mute; } void MuteView::DrawView(unique_ptr &gles) { if (gles == nullptr) { ALOGE("MuteView::DrawView: gles is NULL"); return; } if (bitmapInfo.bitmap == nullptr) { ALOGE("MuteView::DrawView: bitmap is NULL"); return; } if (isAble && isMute) { int ret = gles->DolDrawBitmapByBlend(FBO_HANDLE_INDEX, bitmapInfo); if (ret != DOL_NO_ERROR) { ALOGE("MuteView::DrawView: DolDisplayBitmap failure(%d)", ret); return; } } } MuteView::~MuteView() { FreePNG(bitmapInfo); } // volume bar view VolumeBarView::VolumeBarView(unsigned int tempW, unsigned int tempH, unsigned int tempScale) : BaseView(tempW, tempH, tempScale) { isAble = false; volumeValue = 0; volumeBarW = 0; volumeBarX = 0; fgColor = {0x33, 0xcc, 0xff, 0xff}; volumeRect = {0, 0, 0, 0}; barRect = {0, 0, 0, 0}; barRoundL = {0, 0, 0, 0}; barRoundR = {0, 0, 0, 0}; bitmapBG.bitmap = nullptr; bitmapBG.dstRect = {0, 0, 0, 0}; bitmapBG.srcRect = {0, 0, 0, 0}; bitmapBG.format = CAPTION_OSD_PF_8888; volumeText.text = u" "; volumeText.textLen = strlen(" "); volumeText.isBold = true; volumeText.isItalic = false; volumeText.isUnderLine = false; volumeText.justify = 0; volumeText.fontSize = 0; volumeText.bgColor = {0x00, 0x00, 0x00, 0x00}; volumeText.fgColor = fgColor; int ret = memset_s(bufW, sizeof(bufW), 0, sizeof(bufW)); if (ret != EOK) { ALOGE("VolumeBarView memset_s bufW is failure"); return; } } void VolumeBarView::InitView() { unsigned int bgW = VOLUME_BG_WIDTH_MIX * w; // view width: Fixed screen width of 0.625 unsigned int bgH = VOLUME_BG_HEIGHT * scale; // view height: fixed 92 pixel if screen is 1920*1080 unsigned int bgX = (w - bgW) * CENTRE_PARAM; // view position: horizontal centre unsigned int bgY = h - bgH - VOLUME_PNG_MARGIN; // view position: screen bottom // init bitmap background if (DecodePNG(bitmapBG, (VIEW_PNG_PATH + VOLUME_PNG_NAME).c_str())) { bitmapBG.dstRect.x = bgX; bitmapBG.dstRect.y = bgY; bitmapBG.dstRect.width = bgW; bitmapBG.dstRect.height = bgH; } else { ALOGE("VolumeBarView::InitView: decode bitmapBG failure"); } // init volume bar location const unsigned int barH = VOLUME_BAR_H_MIX * bgH - VOLUME_BAR_MARGIN; const unsigned int barW = VOLUME_BAR_W_MIX * bgW; const unsigned int barX = (w - barW) * CENTRE_PARAM - VOLUME_BAR_MARGIN; // horizontal centre const unsigned int barY = bgY + barH + VOLUME_BAR_OFFSET; const unsigned int barR = barH * CENTRE_PARAM; // round R is height / 2 barRoundL = {barX, barY + barR, barR, barR}; barRoundR = {0, barY + barR, barR, barR}; barRect = {barX, barY, 0, barH}; SetVolumeBarW(barW); SetVolumeBarX(barX); // init volume text info and location const unsigned short maxSize = VOLUME_BAR_H_MIX * VOLUME_BG_HEIGHT; const unsigned short textSize = barH > maxSize ? maxSize : barH; // text bytes max is 3, for example 100 const unsigned int textW = static_cast(textSize) * VOLUME_MAX_BYTES; const unsigned int textH = textSize; const unsigned int textX = bgX + bgW * VOLUME_TEXT_X_MIX; const unsigned int textY = bgY + (bgH - textH) * CENTRE_PARAM; // vertical center volumeText.fontSize = textSize; // text size is volume bar height volumeRect = {textX, textY, textW, textH}; } unsigned int VolumeBarView::GetVolumeBarW() { return volumeBarW; } unsigned int VolumeBarView::GetVolumeBarX() { return volumeBarX; } void VolumeBarView::SetVolumeBarW(unsigned int w) { volumeBarW = w; } void VolumeBarView::SetVolumeBarX(unsigned int x) { volumeBarX = x; } void VolumeBarView::SetVolumeInfo(const bool able, const int vol) { isAble = able; volumeValue = vol; // set volume value for (size_t i = 0; i < sizeof(std::to_string(vol).c_str()); i++) { bufW[i] = *(std::to_string(vol).c_str() + i); // utf-8 to utf-16 } volumeText.text = (const char16_t*)bufW; volumeText.textLen = sizeof(std::to_string(vol).c_str()); // set volume bar width unsigned int validBarW = (volumeValue / VOLUME_MAX_VALUE) * GetVolumeBarW(); barRect.width = validBarW; barRoundR.x = GetVolumeBarX() + validBarW; } void VolumeBarView::DrawView(unique_ptr &gles) { if (gles == nullptr) { ALOGE("VolumeBarView::DrawView: gles is NULL"); return; } if (bitmapBG.bitmap == nullptr) { ALOGE("VolumeBarView::DrawView: bitmap is NULL"); return; } if (isAble) { int ret = gles->DolDrawBitmapByBlend(FBO_HANDLE_INDEX, bitmapBG); if (ret != DOL_NO_ERROR) { ALOGE("VolumeBarView::DrawView: DolDisplayBitmap failure(%d)", ret); return; } ret = gles->DolDrawText(FBO_HANDLE_INDEX, volumeText, volumeRect); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: DolDrawText failure(%d)", ret); return; } if (volumeValue == 0) { ALOGI("CountDownView::DrawView: cancel draw volume bar"); return; } ret = gles->DolDrawRect(FBO_HANDLE_INDEX, barRect, fgColor); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: DolDrawRect failure(%d)", ret); } ret = gles->DolDrawRound(FBO_HANDLE_INDEX, barRoundL, fgColor); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: DolDrawRound left failure(%d)", ret); } ret = gles->DolDrawRound(FBO_HANDLE_INDEX, barRoundR, fgColor); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: DolDrawRound right failure(%d)", ret); } } } VolumeBarView::~VolumeBarView() { FreePNG(bitmapBG); } // count down view CountDownView::CountDownView(unsigned int tempW, unsigned int tempH, unsigned int tempScale) : BaseView(tempW, tempH, tempScale) { remainTime = 0; // remaining time rectTime = {0, 0, 0, 0}; bitmapBG.bitmap = nullptr; bitmapBG.dstRect = {0, 0, 0, 0}; bitmapBG.srcRect = {0, 0, 0, 0}; bitmapBG.format = CAPTION_OSD_PF_8888; bitmapText.bitmap = nullptr; bitmapText.dstRect = {0, 0, 0, 0}; bitmapText.srcRect = {0, 0, 0, 0}; bitmapText.format = CAPTION_OSD_PF_8888; textTime.text = u" "; textTime.textLen = strlen(" "); textTime.isBold = true; textTime.isItalic = false; textTime.isUnderLine = false; textTime.justify = 0; textTime.fontSize = 0; textTime.bgColor = {0x00, 0x00, 0x00, 0x00}; textTime.fgColor = {0xff, 0xc6, 0x00, 0xff}; int ret = memset_s(bufW, sizeof(bufW), 0, sizeof(bufW)); if (ret != EOK) { ALOGE("CountDownView memset_s bufW is failure"); return; } } void CountDownView::InitView() { const unsigned short tmpScale = scale < 2 ? scale : 2; // 2 is default scale const unsigned int viewW = COUNTDOWN_VIEW_W * tmpScale; const unsigned int viewH = COUNTDOWN_VIEW_H * tmpScale; const unsigned int viewX = w - viewW; const unsigned int viewY = 0; unsigned int textW, textH, textX, textY; // textBitmap info // init bitmap bg if (DecodePNG(bitmapBG, (VIEW_PNG_PATH + COUNTDOWN_BG_NAME).c_str())) { bitmapBG.dstRect.x = viewX; bitmapBG.dstRect.y = viewY; bitmapBG.dstRect.width = viewW; bitmapBG.dstRect.height = viewH; } else { ALOGE("CountDownView::InitView: decode bitmapBG failure"); } // init bitmap text if (DecodePNG(bitmapText, GetTextPngPath().c_str())) { // keep the src bitmap scale ratio: newW / newH = oldW / oldH textW = viewW * COUNTDOWN_TEXT_X_MIX; textH = textW * bitmapText.srcRect.height / bitmapText.srcRect.width; textX = viewX; textY = viewY + (viewH - textH) * CENTRE_PARAM; // vertical center bitmapText.dstRect.x = textX; bitmapText.dstRect.y = textY; bitmapText.dstRect.width = textW; bitmapText.dstRect.height = textH; } else { ALOGE("CountDownView::InitView: decode bitmapText failure"); textW = viewW * COUNTDOWN_TEXT_X_MIX; textH = viewH * CENTRE_PARAM; textX = viewX; textY = viewY + (viewH - textH) * CENTRE_PARAM; // vertical center } // init text time const unsigned int timeW = viewW - textW; const unsigned int timeH = textH; const unsigned int timeX = textX + textW + COUNTDOWN_TEXT_MARGIN; const unsigned int timeY = textY; // vertical center textTime.fontSize = timeH; rectTime = {timeX, timeY, timeW, timeH}; } string CountDownView::GetTextPngPath() { auto configer = make_unique(); if (configer->IsCountDownCH()) { return VIEW_PNG_PATH + COUNTDOWN_CH_NAME; } else { return VIEW_PNG_PATH + COUNTDOWN_EN_NAME; } } void CountDownView::SetRemainTime(int remain) { remainTime = remain; // clear buf int ret = memset_s(bufN, sizeof(bufN), '\0', sizeof(bufN)); // reset buf if (ret != EOK) { ALOGE("memset_s time_buf failure"); return; } // measure time_buf size int size = snprintf_s(bufN, sizeof(bufN), sizeof(bufN) - 1, "%d%s", remainTime, "s"); if (size == -1) { ALOGE("snprintf_s time_buf failure"); return; } // utf-8 to utf-16 for (size_t i = 0; i < strlen(bufN); i++) { bufW[i] = bufN[i]; } textTime.text = (const char16_t *)bufW; textTime.textLen = strlen(bufN); } void CountDownView::DrawView(unique_ptr &gles) { if (gles == nullptr) { ALOGE("MuteView::DrawView: gles is NULL"); return; } // draw bg if (bitmapBG.bitmap != nullptr) { int ret = gles->DolDrawBitmapByBlend(FBO_HANDLE_INDEX, bitmapBG); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: draw bitmapBG failure(%d)", ret); } } // draw text png if (bitmapText.bitmap != nullptr) { int ret = gles->DolDrawBitmapByBlend(FBO_HANDLE_INDEX, bitmapText); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: draw bitmapText failure(%d)", ret); } } // draw text int ret = gles->DolDrawText(FBO_HANDLE_INDEX, textTime, rectTime); if (ret != DOL_NO_ERROR) { ALOGE("CountDownView::DrawView: DolDrawText failure(%d)", ret); } } CountDownView::~CountDownView() { FreePNG(bitmapBG); FreePNG(bitmapText); } // ui exit state void BootvideoUI::SetUIFinish() { pthread_mutex_lock(&g_mtxFinish); isExitUI = true; PostUiLock(); pthread_mutex_unlock(&g_mtxFinish); } bool BootvideoUI::CheckExit() const { bool tempState = false; pthread_mutex_lock(&g_mtxFinish); tempState = isExitUI; pthread_mutex_unlock(&g_mtxFinish); return tempState; } // ui ready state void BootvideoUI::SetUIReady() { pthread_mutex_lock(&g_mtxReady); isGlesReady = true; pthread_mutex_unlock(&g_mtxReady); } bool BootvideoUI::CheckReady() const { bool tempState = false; pthread_mutex_lock(&g_mtxReady); tempState = isGlesReady; pthread_mutex_unlock(&g_mtxReady); return tempState; } void BootvideoUI::SetVolumeStatus(int needUI, int mute, int volume) const { pthread_mutex_lock(&g_mtxView); const int eventVolume = 1; // volume ui event const int eventMute = 2; // mute ui event bool ableMute = ((needUI == eventMute) ? true : false); bool ableVolume = ((needUI == eventVolume) ? true : false); if (muteView != nullptr) { muteView->SetMuteInfo(ableMute, ((mute != 0) ? true : false)); } if (volumeView != nullptr) { volumeView->SetVolumeInfo(ableVolume, volume); } PostUiLock(); pthread_mutex_unlock(&g_mtxView); } void BootvideoUI::SetCountdownTime(int time) const { pthread_mutex_lock(&g_mtxView); if (countView != nullptr) { countView->SetRemainTime(time); } PostUiLock(); pthread_mutex_unlock(&g_mtxView); } } // namespace android