/*---------------------------------------------------------------------------- * Copyright (c) TJD Technologies Co., Ltd. 2024. All rights reserved. * * Description: * * Author: huangshuyi * * Create: 2024-7 *--------------------------------------------------------------------------*/ #include "TjdUiAppFloatWindowBlend.h" #include "TjdUiAppIds.h" #include "TjdUiAppMainView.h" #include "TjdUiImageIds.h" #include "cmath" #include "common/image_cache_manager.h" #include "common/screen.h" #include "components/root_view.h" #include "dock/vibrator_manager.h" #include "draw/draw_utils.h" #include "engines/gfx/lite_m_gfx_engine.h" #include "gfx_utils/heap_base.h" #include "imgdecode/image_load.h" #include "sql_setting.h" #include "sys_config.h" #include using namespace OHOS; #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制 #define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开 #define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开 #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #endif namespace TJD { #define FLOAT_WINDOW_BIN_PATH TJD_IMAGE_PATH "/img_main_floatwindow.bin" #define IMAGE_WINDOW_WIDTH 76 #define IMAGE_ICON_WIDTH (76) #define FLOATWINDOW_IMAGE_BG_X 218 #define FLOATWINDOW_IMAGE_BG_Y 195 #define FLOATWINDOW_IMAGE_BG_WIDTH 228 #define FLOATWINDOW_IMAGE_BG_HEIGHT 250 #define FLOAT_WINDOW_VIEWID "floatWindow" struct iconFixInfo { TjdUiAppViewId sliceId; //点击进入的Slice的ID int imageId; const char *name; }; struct iconInfo { iconFixInfo fixInfo; double angle; Rect area; // 默认构造函数 iconInfo() : fixInfo{TJD_APP_VIEW_INVALID, 0, nullptr}, angle(0.0), area() {} }; static uint8_t displayNum = 4; static bool needCycle_ = false; static uint8_t isInit = 0; static const iconFixInfo g_fixInfoArray[] = { {TJD_APP_VIEW_HR, IMG_MAIN_FLOATWINDOW_HEARTRATE, "hr"}, {TJD_APP_VIEW_SPO2, IMG_MAIN_FLOATWINDOW_SPO2, "spo2"}, {TJD_APP_VIEW_SPORT, IMG_MAIN_FLOATWINDOW_SPORT, "sport"}, {TJD_APP_VIEW_PLAYER, IMG_MAIN_FLOATWINDOW_MUSIC, "music"}, {TJD_APP_VIEW_SLEEP, IMG_MAIN_FLOATWINDOW_SLEEP, "sleep"}, {TJD_APP_VIEW_STRESS, IMG_MAIN_FLOATWINDOW_PRESSURE, "pressure"}, {TJD_APP_VIEW_BREATHING, IMG_MAIN_FLOATWINDOW_BREATHE, "breathe"}, {TJD_APP_VIEW_SPORT_RECORD, IMG_MAIN_FLOATWINDOW_SPORT_RECORD, "sport_record"}, {TJD_APP_VIEW_DAILYDATA, IMG_MAIN_FLOATWINDOW_DATA, "data"}, {TJD_APP_VIEW_PHONE, IMG_MAIN_FLOATWINDOW_PHONE, "phone"}, {TJD_APP_VIEW_MESSAGE_TOTAL, IMG_MAIN_FLOATWINDOW_MESSAGE, "message"}, {TJD_APP_VIEW_WEATHER, IMG_MAIN_FLOATWINDOW_WEATHER, "weather"}, {TJD_APP_VIEW_TIMER, IMG_MAIN_FLOATWINDOW_TIMER, "timer"}, {TJD_APP_VIEW_STOPWATCH, IMG_MAIN_FLOATWINDOW_STOPWATCH, "stopwatch"}, {TJD_APP_VIEW_ALARM, IMG_MAIN_FLOATWINDOW_CLOCK, "alarm"}, {TJD_APP_VIEW_CALCULATOR, IMG_MAIN_FLOATWINDOW_CALCULATOR, "calculator"}, {TJD_APP_VIEW_CALENDAR, IMG_MAIN_FLOATWINDOW_CALENDAR, "calendar"}, {TJD_APP_VIEW_COMPASS, IMG_MAIN_FLOATWINDOW_COMPASS, "compass"}, {TJD_APP_VIEW_RECORD, IMG_MAIN_FLOATWINDOW_RECORDING, "recording"}, {TJD_APP_VIEW_CAMERA, IMG_MAIN_FLOATWINDOW_CAMERA, "camera"}, {TJD_APP_VIEW_ALBUM, IMG_MAIN_FLOATWINDOW_PHOTO, "album"}, {TJD_APP_VIEW_EBOOK, IMG_MAIN_FLOATWINDOW_BOOK, "ebook"}, {TJD_APP_VIEW_BUSINESSCARD, IMG_MAIN_FLOATWINDOW_CARD, "businesscard"}, {TJD_APP_VIEW_WALLET, IMG_MAIN_FLOATWINDOW_WALLET, "wallet"}, {TJD_APP_VIEW_VIDEO_CTRL, IMG_MAIN_FLOATWINDOW_VIDEO, "video"}, {TJD_APP_VIEW_FEMALE, IMG_MAIN_FLOATWINDOW_PHYSIOLOGY, "physiology"}, {TJD_APP_VIEW_VOICE_ASSISTANT, IMG_MAIN_FLOATWINDOW_AI, "ai"}, {TJD_APP_VIEW_GAME, IMG_MAIN_FLOATWINDOW_GAME, "game"}, {TJD_APP_VIEW_SETTING, IMG_MAIN_FLOATWINDOW_SET, "setting"}, {TJD_APP_VIEW_LUCKY_CLOVER, IMG_MAIN_FLOATWINDOW_LEFUN, "lefun"}, {TJD_APP_VIEW_LEFUN_AI, IMG_MAIN_FLOATWINDOW_LEFUNAI, "lefunai"}, {TJD_APP_VIEW_MS_GAME, IMG_MAIN_FLOATWINDOW_SOMATOSENSORY, "somatosensory"}, {TJD_APP_VIEW_ALIPAY, IMG_MAIN_FLOATWINDOW_ALIPAY, "alipay"}, {TJD_APP_VIEW_PLAY_DIAL, IMG_MAIN_FLOATWINDOW_WATCHFACE, "watchface"}, {TJD_APP_VIEW_MAIN, IMG_MAIN_FLOATWINDOW_BAIDU, "baidu"}, }; static iconInfo *iconInfoPtr = nullptr; static void CalculatePointOnCircle(double R, double angleDegrees, double &x, double &y, uint8_t isAbsCoor) { double adjustedAngle = 90.0 - angleDegrees; if (adjustedAngle < 0) { adjustedAngle += 360.0; } double radians = angleDegrees * UI_PI / 180.0; double xRelative = R * sin(radians); double yRelative = -R * cos(radians); if (isAbsCoor) { x = Screen::GetInstance().GetWidth() / 2 + xRelative; y = Screen::GetInstance().GetWidth() / 2 + yRelative; } else { x = xRelative; y = yRelative; } } static double CalculateIconAngle(uint16_t CycleR, uint16_t iconR) { double ac = iconR; double oc = CycleR - iconR; double aoc = asin(ac / oc); double angleDegrees = aoc * (180.0 / UI_PI); return angleDegrees * 2; } double TjdUiAppFloatWindowBlend::FindCorrectIcon(void) { double iconStartAngle; double iconEndAngle; double diffAngle = 0; const double iconGapAngle = angleReserve - angleIcon; for (uint8_t elem : iconList) { // printf("icon index:%d,name:%s,angle:%f\n", elem, imageIconArray[elem].name, imageIconArray[elem].angle); iconStartAngle = iconInfoPtr[elem].angle - angleIcon / 2; iconEndAngle = iconInfoPtr[elem].angle + angleIcon / 2; if (startAngle > iconStartAngle && startAngle <= iconEndAngle) { if (startAngle > iconInfoPtr[elem].angle) { diffAngle = -(iconEndAngle - startAngle + iconGapAngle); } else { diffAngle = startAngle - iconStartAngle; } // printf("find correct icon:%s is need correct, diff angle:%f\n", imageIconArray[elem].name, diffAngle); return diffAngle; } } return startAngle - (iconInfoPtr[iconList.front()].angle - angleIcon / 2); } bool TjdUiAppFloatWindowBlend::OnDrag(OHOS::UIView &view, const OHOS::DragEvent &event) { if (floatWindowAnimator_.GetState() != OHOS::Animator::STOP) { StopFloatWindowAnimator(); } if (IsFloatWindowVisible() == true) { int16_t yDiff = event.GetDeltaY(); RefreshDelta(yDiff); UpdateFuchuang(yDiff, 0, false); return true; } return false; } bool TjdUiAppFloatWindowBlend::OnDragEnd(OHOS::UIView &view, const OHOS::DragEvent &event) { if (IsFloatWindowVisible() == true) { OHOS::Point last = event.GetPreLastPoint(); OHOS::Point current = event.GetLastPoint(); if ((last.x == current.x) && (last.y == current.y)) { last = current; current = event.GetCurrentPos(); } DragThrowAnimator(current, last, event.GetDragDirection()); } return true; } bool TjdUiAppFloatWindowBlend::OnRotate(OHOS::UIView &view, const OHOS::RotateEvent &event) { if (floatWindowAnimator_.GetState() != OHOS::Animator::STOP) { StopFloatWindowAnimator(); } if (IsFloatWindowVisible() == true) { lastRotate_ = event.GetRotate(); RefreshDelta(lastRotate_); UpdateFuchuang(lastRotate_, 0, false); int16_t x = FLOATWINDOW_IMAGE_BG_X + FLOATWINDOW_IMAGE_BG_WIDTH - IMAGE_WINDOW_WIDTH / 2; // 218 + 228 - 38 = // 408 int16_t y = FLOATWINDOW_IMAGE_BG_Y + IMAGE_WINDOW_WIDTH / 2; // 195 + 38 = 230 const Point point = {x, y}; int curImageId = 0; for (uint8_t elem : iconList) { if (iconInfoPtr[elem].area.IsContains(point)) { curImageId = iconInfoPtr[elem].fixInfo.imageId; break; } } if (lastImageId_ != -1 && curImageId != 0 && curImageId != lastImageId_) { #if ENABLE_VIBRATOR OHOS::VibratorFunc vibratorFunc = OHOS::VibratorManager::GetInstance()->GetVibratorFunc(); vibratorFunc(OHOS::VibratorType::VIBRATOR_TYPE_ONE); #endif } lastImageId_ = curImageId; return true; } return false; } bool TjdUiAppFloatWindowBlend::OnRotateEnd(OHOS::UIView &view, const OHOS::RotateEvent &event) { if (IsFloatWindowVisible() == true) { DragThrowAnimator({0, 0}, {0, 0}, lastRotate_ > 0 ? OHOS::DragEvent::DIRECTION_TOP_TO_BOTTOM : OHOS::DragEvent::DIRECTION_BOTTOM_TO_TOP); } return true; } bool TjdUiAppFloatWindowBlend::OnClick(OHOS::UIView &view, const OHOS::ClickEvent &event) { std::string viewId = view.GetViewId(); if (viewId == FLOAT_WINDOW_VIEWID) { HideFloatWindow(); } else { const Point point = {event.GetCurrentPos().x, event.GetCurrentPos().y}; for (uint8_t elem : iconList) { if (iconInfoPtr[elem].area.IsContains(point)) { OHOS::NativeAbility::GetInstance().ChangeSlice(iconInfoPtr[elem].fixInfo.sliceId); break; } } } return true; } void TjdUiAppFloatWindowBlend::HideFloatWindow() { TjdUiAppMainView *mainView = TjdUiAppMainView::GetInstance(); if (mainView == nullptr) { return; } SetVisible(false); ClearBackgroundBlur(); ClearFocus(); // auto wfBase = dynamic_cast(mainView->GetViewByCardId(TJD_MAIN_PAGE_WATCH_FACE)); // if (wfBase->IsDialView()) { // auto *dial = wfBase->GetDialViewGroup(); // if (dial != nullptr) { // dial->OnActive(); // } // } else { // wfBase->OnActive(); // } } void TjdUiAppFloatWindowBlend::ShowFloatWindow() { TjdUiAppMainView *mainView = TjdUiAppMainView::GetInstance(); if (mainView == nullptr) { return; } // auto wfBase = dynamic_cast(mainView->GetViewByCardId(TJD_MAIN_PAGE_WATCH_FACE)); // if (wfBase->IsDialView()) { // auto *dial = wfBase->GetDialViewGroup(); // if (dial != nullptr) { // dial->OnInactive(); // } // } else { // wfBase->OnInactive(); // } SetVisible(true); OHOS::RootView::GetInstance()->ClearBlurView(OHOS::RootView::GetInstance()->GetBlurView()); SetBackgroundBlur(32); SetFullScreenBlur(false); OHOS::FocusManager::GetInstance()->ClearFocus(); RequestFocus(); // TjdUiAppMainPageWf::GetInstance()->HideSystemViewIcon(); mainView->GetWfCommon()->HideSystemViewIcon(); } bool TjdUiAppFloatWindowBlend::IsFloatWindowVisible(void) { return IsVisible(); } TjdUiAppFloatWindowBlend::TjdUiAppFloatWindowBlend() : floatWindowAnimator_(&floatWindowAnimatorCallback_, nullptr, 0, true) { floatWindowAnimatorCallback_.SetFloatWindowBlend(this); uint8_t sliceNum; isInit = 0; const uint16_t *sliceId = sql_setting_get_floating_window_map(&sliceNum); needCycle_ = false; if (sliceNum <= 4) { sliceNum = 4; needCycle_ = true; } if (sliceNum == 4) { iconInfoPtr = new iconInfo[sliceNum + 1]; } else { iconInfoPtr = new iconInfo[sliceNum]; } for (uint8_t i = 0; i < sliceNum; i++) { uint8_t m = sizeof(g_fixInfoArray) / sizeof(g_fixInfoArray[0]); uint8_t j; for (j = 0; j < m; j++) { if (sliceId[i] == g_fixInfoArray[j].sliceId) { iconInfoPtr[i].fixInfo = g_fixInfoArray[j]; break; } } if (j == m) { iconInfoPtr[i].fixInfo = g_fixInfoArray[i]; } } if (sliceNum == 4) { sliceNum = 5; iconInfoPtr[4].fixInfo = iconInfoPtr[0].fixInfo; } SetIntercept(true); SetViewId(FLOAT_WINDOW_VIEWID); SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT); SetDirection(1); SetPosition(0, 0); SetWidth(Screen::GetInstance().GetWidth()); SetHeight(Screen::GetInstance().GetHeight()); SetOnDragListener(this); SetOnClickListener(this); SetOnRotateListener(this); imageFloatWindow = new UIImageView(); imageFloatWindow->SetOnClickListener(this); imageFloatWindow->SetTouchable(true); imageFloatWindow->SetIntercept(true); Add(imageFloatWindow); imageFloatWindow->SetPosition(FLOATWINDOW_IMAGE_BG_X, FLOATWINDOW_IMAGE_BG_Y); ImageInfo *bgImgInfo; bgImgInfo = ImageCacheManager::GetInstance().LoadOneInMultiRes(IMG_MAIN_FLOATWINDOW_BG, FLOAT_WINDOW_BIN_PATH); finalImgInfo = new ImageInfo(); finalImgInfo->cacheNode = nullptr; finalImgInfo->header.width = bgImgInfo->header.width; finalImgInfo->header.height = bgImgInfo->header.height; finalImgInfo->header.colorMode = ARGB8888; finalImgInfo->header.compressMode = COMPRESS_MODE_NONE; finalImgInfo->dataSize = ALIGN_BYTE(finalImgInfo->header.width, BYTE_ALIGNMENT) * finalImgInfo->header.height * DrawUtils::GetByteSizeByColorMode(ARGB8888); finalImgInfo->data = reinterpret_cast(ImageCacheMalloc(*finalImgInfo)); uint8_t *non_const_data = const_cast(finalImgInfo->data); for (uint32_t i = 0; i < finalImgInfo->dataSize; i += 4) { non_const_data[i] = 0x96; non_const_data[i + 1] = 0x97; non_const_data[i + 2] = 0x97; non_const_data[i + 3] = 0x0; } // memset(const_cast(finalImgInfo->data), (uint32_t)0x00ffffff, finalImgInfo->dataSize / 4); finalImgInfo->phyAddr = finalImgInfo->data; // clang-format off Rect dstRect(0, 0, finalImgInfo->header.width - 1, finalImgInfo->header.height - 1); bgDstBufferInfo.mode = ARGB8888; bgDstBufferInfo.width = bgImgInfo->header.width; bgDstBufferInfo.height = bgImgInfo->header.height; bgDstBufferInfo.stride = ALIGN_BYTE(bgDstBufferInfo.width, BYTE_ALIGNMENT) * DrawUtils::GetByteSizeByColorMode(ARGB8888); bgDstBufferInfo.phyAddr = const_cast(finalImgInfo->data); bgDstBufferInfo.virAddr = const_cast(finalImgInfo->data); bgDstBufferInfo.compressMode = COMPRESS_MODE_NONE; bgDstBufferInfo.rect = dstRect; bgDstBufferInfo.color = 0; bgSrcBufferInfo.mode = (ColorMode)bgImgInfo->header.colorMode; bgSrcBufferInfo.width = bgImgInfo->header.width; bgSrcBufferInfo.height = bgImgInfo->header.height; bgSrcBufferInfo.stride = ALIGN_BYTE(bgSrcBufferInfo.width, BYTE_ALIGNMENT) * DrawUtils::GetByteSizeByColorMode(bgSrcBufferInfo.mode); bgSrcBufferInfo.phyAddr = const_cast(bgImgInfo->data); bgSrcBufferInfo.virAddr = const_cast(bgImgInfo->data); bgSrcBufferInfo.compressMode = bgImgInfo->header.compressMode; Rect bgSrcRect(0, 0, bgSrcBufferInfo.width - 1, bgSrcBufferInfo.height - 1); bgSrcBufferInfo.rect = bgSrcRect; bgSrcBufferInfo.color = 0; BlendOption opt1; opt1.opacity = OPA_OPAQUE; opt1.mode = BlendMode::BLEND_SRC_OVER; // clang-format on BaseGfxEngine::GetInstance()->Blit(bgDstBufferInfo, {0, 0}, bgSrcBufferInfo, bgSrcRect, opt1); #if ENABLE_VGU_ENGINE LiteMGfxEngine::GetInstance()->SyncHwDraw(); #endif // clang-format off arcCenterX = Screen::GetInstance().GetWidth() / 2; arcCenterY = Screen::GetInstance().GetHeight() / 2; arcOuterRedius = Screen::GetInstance().GetWidth() / 2 - 20; angleIcon = CalculateIconAngle(arcOuterRedius, IMAGE_WINDOW_WIDTH / 2); startAngle = acos(MATH_ABS((arcCenterY - FLOATWINDOW_IMAGE_BG_Y)) / (arcOuterRedius - IMAGE_WINDOW_WIDTH / 2)) * 180 / UI_PI; endAngle = 180 + asin(MATH_ABS((arcCenterX - FLOATWINDOW_IMAGE_BG_X)) / (arcOuterRedius - IMAGE_WINDOW_WIDTH / 2)) * 180 / UI_PI; angleReserve = (endAngle - startAngle - angleIcon) / (displayNum - 1); // clang-format on uint8_t cnt = sliceNum; iconList.clear(); for (uint8_t i = 0; i < cnt; i++) { iconList.push_back(i); } UpdateFuchuang(0, 0, false); imageFloatWindow->SetSrc(finalImgInfo); } TjdUiAppFloatWindowBlend::~TjdUiAppFloatWindowBlend() { ClearFocus(); ClearBackgroundBlur(); if (finalImgInfo) { ImageCacheFree(*finalImgInfo); delete finalImgInfo; finalImgInfo = nullptr; } if (iconInfoPtr) { delete[] iconInfoPtr; iconInfoPtr = nullptr; } } void TjdUiAppFloatWindowBlend::UpdateFuchuang(int16_t diffy, double angle, bool isUsedAngle) { double angleDiff; if (isUsedAngle) { angleDiff = angle; const double EPSILON = 1e-6; if (angleDiff < EPSILON) { diffy = -1; } else { diffy = 1; } } else { angleDiff = diffy * 0.4; } if (LiteMGfxEngine::GetInstance()->IsAsyncModeEnabled()) { LiteMGfxEngine::GetInstance()->Flush(Rect(0, 0, 0, 0)); } Rect bgSrcRect(0, 0, bgSrcBufferInfo.width - 1, bgSrcBufferInfo.height - 1); BlendOption opt1; opt1.opacity = OPA_OPAQUE; opt1.mode = BlendMode::BLEND_SRC_OVER; BaseGfxEngine::GetInstance()->Blit(bgDstBufferInfo, {0, 0}, bgSrcBufferInfo, bgSrcRect, opt1); int16_t IconX, IconY; double x_temp, y_temp; int16_t iconContainerOffsetX; int16_t iconContainerOffsetY; iconContainerOffsetX = FLOATWINDOW_IMAGE_BG_X - arcCenterX; iconContainerOffsetY = FLOATWINDOW_IMAGE_BG_Y - arcCenterY; if (MATH_ABS(angleDiff) > angleReserve) { if (angleDiff < 0) { angleDiff = -angleReserve + 10; } else { angleDiff = angleReserve - 10; } } for (uint8_t elem : iconList) { BufferInfo logoBufferInfo; ImageInfo *imgInfo = ImageCacheManager::GetInstance().LoadOneInMultiRes(iconInfoPtr[elem].fixInfo.imageId, FLOAT_WINDOW_BIN_PATH); logoBufferInfo.mode = (ColorMode)imgInfo->header.colorMode; logoBufferInfo.width = imgInfo->header.width; logoBufferInfo.height = imgInfo->header.height; uint16_t fgWidth = imgInfo->header.width; uint16_t fgHeight = imgInfo->header.height; logoBufferInfo.stride = ALIGN_BYTE(logoBufferInfo.width, BYTE_ALIGNMENT) * DrawUtils::GetByteSizeByColorMode(logoBufferInfo.mode); logoBufferInfo.phyAddr = const_cast(imgInfo->data); logoBufferInfo.virAddr = const_cast(imgInfo->data); logoBufferInfo.compressMode = imgInfo->header.compressMode; Rect logoBufferInfoRect(0, 0, logoBufferInfo.width - 1, logoBufferInfo.height - 1); BlendOption opt2; opt2.opacity = OPA_OPAQUE; opt2.mode = BlendMode::BLEND_SRC_ATOP; Rect srcInDstRect; // if (isInit == 0) { iconInfoPtr[elem].angle = startAngle + angleIcon / 2 + angleReserve * elem; } else { iconInfoPtr[elem].angle += angleDiff; } if (iconInfoPtr[elem].angle < startAngle - angleIcon / 2 || iconInfoPtr[elem].angle > endAngle + angleIcon / 2) { // continue; } CalculatePointOnCircle(arcOuterRedius - IMAGE_WINDOW_WIDTH / 2, iconInfoPtr[elem].angle, x_temp, y_temp, 1); IconX = (int16_t)x_temp - IMAGE_ICON_WIDTH / 2 - FLOATWINDOW_IMAGE_BG_X; IconY = (int16_t)y_temp - IMAGE_ICON_WIDTH / 2 - FLOATWINDOW_IMAGE_BG_Y; //如果图标完全超出背景图范围 if (IconX < -IMAGE_ICON_WIDTH || IconY < -IMAGE_ICON_WIDTH) { continue; } uint16_t real_w, real_h; real_w = logoBufferInfo.width; real_h = logoBufferInfo.height; logoBufferInfo.rect.SetX(0); logoBufferInfo.rect.SetY(0); if (IconX < 0) { real_w = real_w + IconX; logoBufferInfo.rect.SetX(MATH_ABS(IconX)); IconX = 0; } if (IconY < 0) { real_h = real_h + IconY; logoBufferInfo.rect.SetY(MATH_ABS(IconY)); IconY = 0; } if (real_w == 0 || real_h == 0) { continue; } logoBufferInfo.rect.SetWidth(real_w); logoBufferInfo.rect.SetHeight(real_h); uint16_t absX = x_temp - IMAGE_ICON_WIDTH / 2; uint16_t absY = y_temp - IMAGE_ICON_WIDTH / 2; iconInfoPtr[elem].area.SetRect(absX, (uint16_t)absY, (uint16_t)absX + IMAGE_ICON_WIDTH - 1, (uint16_t)absY + IMAGE_ICON_WIDTH - 1); srcInDstRect.SetX(IconX); srcInDstRect.SetY(IconY); srcInDstRect.SetWidth(real_w); srcInDstRect.SetHeight(real_h); BaseGfxEngine::GetInstance()->Blit(bgDstBufferInfo, {0, 0}, logoBufferInfo, srcInDstRect, opt2); } isInit = 1; #if ENABLE_VGU_ENGINE LiteMGfxEngine::GetInstance()->SyncHwDraw(); #endif imageFloatWindow->Invalidate(); #if 1 if (diffy < 0) { if ((iconInfoPtr[iconList.front()].angle + angleIcon / 2) < startAngle) { double angleLast = iconInfoPtr[iconList.back()].angle; iconInfoPtr[iconList.front()].angle = angleLast + angleReserve; iconList.splice(iconList.end(), iconList, iconList.begin()); if (needCycle_ == true) { iconInfoPtr[iconList.back()].fixInfo = iconInfoPtr[iconList.front()].fixInfo; } } } else if (diffy > 0) { auto it = iconList.begin(); std::advance(it, displayNum - 1); if ((iconInfoPtr[*it].angle + angleIcon / 2) > endAngle) { double angleFirst = iconInfoPtr[iconList.front()].angle; iconInfoPtr[iconList.back()].angle = angleFirst - angleReserve; auto lastElementIt = std::prev(iconList.end()); iconList.splice(iconList.begin(), iconList, lastElementIt); if (needCycle_ == true) { it = iconList.begin(); std::advance(it, displayNum - 1); iconInfoPtr[iconList.front()].fixInfo = iconInfoPtr[iconList.back()].fixInfo; } } } #endif } void TjdUiAppFloatWindowBlend::FloatWindowAnimatorCallback::Callback(OHOS::UIView *view) { if (instance_ == nullptr) { return; } if (instance_->SlideOrAutoAlign_ == 1) { curtTime_++; if (curtTime_ <= dragTimes_) { double f = CubicEaseOut1(startValueY_, endValueY_, curtTime_, dragTimes_); instance_->UpdateFuchuang(0, f - previousValueY_, true); previousValueY_ = f; } else { instance_->StopFloatWindowAnimator(); } } else { curtTime_++; if (curtTime_ <= dragTimes_) { bool needStopY = false; if (startValueY__ != endValueY__) { int16_t actY = easingFunc_(startValueY__, endValueY__, curtTime_, dragTimes_); instance_->UpdateFuchuang(actY - previousValueY__, 0, false); if (IsNeedReCalculateDragEnd()) { double angle = instance_->FindCorrectIcon(); instance_->StartAutoAlignAnimator(angle); } previousValueY__ = actY; } else { needStopY = true; } if (needStopY) { instance_->StopFloatWindowAnimator(); } } else { instance_->StopFloatWindowAnimator(); } } } void TjdUiAppFloatWindowBlend::FloatWindowAnimatorCallback::OnStop(OHOS::UIView &view) { int16_t x = FLOATWINDOW_IMAGE_BG_X + FLOATWINDOW_IMAGE_BG_WIDTH - IMAGE_WINDOW_WIDTH / 2; // 218 + 228 - 38 = // 408 int16_t y = FLOATWINDOW_IMAGE_BG_Y + IMAGE_WINDOW_WIDTH / 2; // 195 + 38 = 230 const Point point = {x, y}; int curImageId = 0; for (uint8_t elem : instance_->iconList) { if (iconInfoPtr[elem].area.IsContains(point)) { instance_->lastImageId_ = iconInfoPtr[elem].fixInfo.imageId; break; } } } bool TjdUiAppFloatWindowBlend::FloatWindowAnimatorCallback::IsNeedReCalculateDragEnd() { int16_t animationLess = 0; animationLess = endValueY__ - previousValueY__; if ((MATH_ABS(animationLess) > 10)) { return false; } return true; } double TjdUiAppFloatWindowBlend::FloatWindowAnimatorCallback::CubicEaseOut1(double startPos, double endPos, uint16_t curTime, uint16_t durationTime) { if (curTime < durationTime) { float t = static_cast(curTime) / durationTime; float x = 1.0f - powf(1.0f - t, 3.0f); // 计算1 - (1 - t)^3 return startPos + x * (endPos - startPos); } return endPos; } void TjdUiAppFloatWindowBlend::StartSlideAnimator(int16_t dragDistanceY) { SlideOrAutoAlign_ = 0; int16_t dragTimes = MATH_ABS(dragDistanceY) / DRAG_TIMES_COEFFICIENT; if (dragTimes < MIN_DRAG_TIMES) { dragTimes = MIN_DRAG_TIMES; } floatWindowAnimatorCallback_.ResetCallback(); floatWindowAnimatorCallback_.SetDragStartValue(static_cast(0)); floatWindowAnimatorCallback_.SetDragEndValue(dragDistanceY); floatWindowAnimatorCallback_.SetDragTimes(dragTimes * DRAG_ACC_FACTOR / GetDragACCLevel()); floatWindowAnimator_.Start(); } void TjdUiAppFloatWindowBlend::StartAutoAlignAnimator(double diffAngle) { SlideOrAutoAlign_ = 1; int16_t dragTimes = MATH_ABS(diffAngle); if (dragTimes < MIN_DRAG_TIMES) { dragTimes = MIN_DRAG_TIMES; } floatWindowAnimatorCallback_.ResetCallback(); floatWindowAnimatorCallback_.SetDragStartValue(static_cast(0)); floatWindowAnimatorCallback_.SetDragEndValue(diffAngle); floatWindowAnimatorCallback_.SetDragTimes(dragTimes); floatWindowAnimator_.Start(); } void TjdUiAppFloatWindowBlend::StopFloatWindowAnimator() { floatWindowAnimator_.Stop(); } } // namespace TJD