增加运动倒计时 3247/1 3247/head
authorxue <2144439972@qq.com>
Fri, 6 Mar 2026 02:21:06 +0000 (10:21 +0800)
committerxue <2144439972@qq.com>
Fri, 6 Mar 2026 02:21:06 +0000 (10:21 +0800)
code/sdk/application/wearable/fd272/nativeapp/nativelauncher/include/AppViewIDs.h
code/sdk/application/wearable/fd272/nativeapp/nativeui/include/sport_countdown/CountdownPresenter.h [new file with mode: 0644]
code/sdk/application/wearable/fd272/nativeapp/nativeui/include/sport_countdown/CountdownView.h [new file with mode: 0644]
code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownPresenter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/src/TraingModel.cpp
code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/training_GPS/src/TraingEphemerisNotePresenter.cpp
code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/training_GPS/src/TraingGPSnotePresenter.cpp

index 57d0eb8..1717493 100644 (file)
@@ -107,6 +107,7 @@ typedef enum : uint16_t
   VIEW_HEART,          // 心率监测
   VIEW_SAVEELE,        // 省电模式
   VIEW_SAVEBAT,        // 省电模式界面
+  VIEW_SPORT_COUNTDOWN, // 运动开始 3 秒倒计时(独立 slice)
   VIEW_TAKEPHOTOS,     // 拍照界面
   VIEW_EPHEMERIS_DOWNLOAD, // 下载星历
   // VIEW_SLEEP,          // 睡眠界面
diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/include/sport_countdown/CountdownPresenter.h b/code/sdk/application/wearable/fd272/nativeapp/nativeui/include/sport_countdown/CountdownPresenter.h
new file mode 100644 (file)
index 0000000..d48387d
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * 运动倒计时 Presenter(独立):倒计时结束根据 SetReturnSlice 跳转,不依赖 saveele
+ */
+#ifndef _COUNTDOWN_PRESENTER_H
+#define _COUNTDOWN_PRESENTER_H
+
+#include "key/include/KeyInputListener.h"
+#include "Presenter.h"
+#include "sport_countdown/CountdownView.h"
+#include "ModelListenerSample.h"
+#include "main/include/MainModel.h"
+
+namespace OHOS {
+
+class CountdownView;
+
+class CountdownPresenter : public Presenter<CountdownView>,
+                           public ModelListenerSample,
+                           public RootView::OnKeyActListener {
+ public:
+  CountdownPresenter();
+  virtual ~CountdownPresenter();
+
+  void OnStart() override;
+  void OnResume() override;
+
+  static CountdownPresenter *GetInstance();
+
+  /** 进入运动倒计时前调用,传入倒计时结束后要跳转的 slice(如 VIEW_TRAININGCRAD),0 表示回主界面 */
+  static void SetReturnSlice(int16_t sliceId);
+  /** 由 View 在 3 秒倒计时结束时调用,内部使用 */
+  static void SetCountdownFinished(bool finished);
+
+  void OnTickEvent() override;
+  void Notify() override {}
+  void ExitView(void);
+
+ private:
+  bool OnKeyAct(UIView &view, const KeyEvent &event) override;
+
+  static int16_t s_returnSliceId;
+  static bool s_countdownFinished;
+};
+
+}  // namespace OHOS
+
+#endif
diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/include/sport_countdown/CountdownView.h b/code/sdk/application/wearable/fd272/nativeapp/nativeui/include/sport_countdown/CountdownView.h
new file mode 100644 (file)
index 0000000..8753055
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * 运动倒计时 Slice(独立):仅 3 秒倒计时,时间到返回原流程(如运动界面)
+ * 不依赖 saveele,类名/文件名与 saveele 的 SaveBat* 区分,避免链接多重定义
+ */
+#ifndef _COUNTDOWN_VIEW_H
+#define _COUNTDOWN_VIEW_H
+
+#include "View.h"
+#include "components/ui_view_group.h"
+#include "components/ui_label.h"
+#include "components/ui_canvas.h"
+#include "components/ui_canvas_ext.h"
+#include "sport_countdown/CountdownPresenter.h"
+#include "hal_tick.h"
+#include "common/screen.h"
+
+namespace OHOS {
+
+enum class SportCountdownStage {
+  STAGE_GRADUAL_CIRCLE = 0,
+  STAGE_COUNTING_DOWN,
+  STAGE_FADE_OUT,
+  STAGE_NONE
+};
+
+class SportCountdownAnimatorCallback : public AnimatorCallback {
+ public:
+  explicit SportCountdownAnimatorCallback(UICanvasExt *canvas) : canvas_(canvas) {}
+  ~SportCountdownAnimatorCallback() override {}
+  void Callback(UIView *view) override;
+  void NotifyStart();
+  void CancelCountdown();
+  void SetInfo(UILabel *label, int counts);
+
+ private:
+  void CountingDown();
+  void UpdatePath(int16_t start, int16_t end, bool needDrawCircle);
+  void UpdateLable(uint32_t curTime);
+  void CircleFadeOut();
+  void GradualCircle();
+  UICanvasExt *canvas_ = nullptr;
+  UILabel *label_ = nullptr;
+  bool updateText_ = false;
+  bool firstArc_ = false;
+  SportCountdownStage stage_ = SportCountdownStage::STAGE_NONE;
+  int16_t endAngle_ = 0;
+  int16_t easeDegree_ = 0;
+  uint16_t idleTime_ = 0;
+  int16_t counts_ = 0;
+  uint32_t lastTime_ = 0;
+  uint32_t degreePerSecond_ = 0;
+  uint32_t surplusDegree = 0;
+  uint16_t lastFontSize_ = 0;  // 用于节流 SetFont,减少卡顿
+};
+
+class CountdownPresenter;
+class CountdownView : public View<CountdownPresenter> {
+ public:
+  CountdownView();
+  virtual ~CountdownView();
+  static CountdownView *GetInstance(void);
+
+  void OnStart() override;
+
+  void InitCountdownView();
+  void StartCanvas();
+  void StopCanvas();
+
+ private:
+  CountdownView(const CountdownView &) = delete;
+  CountdownView &operator=(const CountdownView &) = delete;
+
+  UIViewGroup *group_ = nullptr;
+  SportCountdownAnimatorCallback *callBack_ = nullptr;
+  Animator *countdownAnimator_ = nullptr;
+  UICanvasExt *canvas_ = nullptr;
+  UILabel *label_ = nullptr;
+};
+
+}  // namespace OHOS
+
+#endif
diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownPresenter.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownPresenter.cpp
new file mode 100644 (file)
index 0000000..45b53a7
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * 运动倒计时 Slice:仅 3 秒倒计时,时间到跳转到 SetReturnSlice 指定的 slice(如运动界面)
+ * 不依赖 saveele,完全独立在 sport_countdown 模块内
+ */
+#include "AppViewIDs.h"
+#include "key/include/KeyInputListener.h"
+#include "main/include/MainModel.h"
+#include "NativeAbility.h"
+#include "sport_countdown/CountdownPresenter.h"
+#include "sport_countdown/CountdownView.h"
+#include "wearable_log.h"
+#include "string.h"
+#include "NativeRegisterManager.h"
+
+namespace OHOS {
+
+REGIST_SLICE(VIEW_SPORT_COUNTDOWN, CountdownView, CountdownPresenter);
+
+static CountdownPresenter *g_pCountdownPresenter = nullptr;
+
+int16_t CountdownPresenter::s_returnSliceId = 0;
+bool CountdownPresenter::s_countdownFinished = false;
+
+CountdownPresenter::CountdownPresenter() {
+  g_pCountdownPresenter = this;
+}
+
+CountdownPresenter::~CountdownPresenter() {
+  g_pCountdownPresenter = nullptr;
+}
+
+CountdownPresenter *CountdownPresenter::GetInstance() {
+  return g_pCountdownPresenter;
+}
+
+void CountdownPresenter::SetReturnSlice(int16_t sliceId) {
+  s_returnSliceId = sliceId;
+}
+
+void CountdownPresenter::SetCountdownFinished(bool finished) {
+  s_countdownFinished = finished;
+}
+
+void CountdownPresenter::OnStart() {
+  Presenter<CountdownView>::OnStart();
+}
+
+void CountdownPresenter::OnResume() {
+  RootView::GetInstance()->SetOnKeyActListener(this);
+}
+
+void CountdownPresenter::ExitView(void) {
+  int16_t target = (s_returnSliceId != 0) ? s_returnSliceId : VIEW_MAIN;
+  s_returnSliceId = 0;
+  s_countdownFinished = false;
+  WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "运动倒计时结束,跳转 slice=%d", target);
+  NativeAbility::GetInstance().ChangeSlice(target);
+}
+
+void CountdownPresenter::OnTickEvent() {
+  if (s_countdownFinished) {
+    s_countdownFinished = false;
+    ExitView();
+  }
+}
+
+bool CountdownPresenter::OnKeyAct(UIView &view, const KeyEvent &event) {
+  (void)view;
+  (void)event;
+  return true;
+}
+
+}  // namespace OHOS
diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp
new file mode 100644 (file)
index 0000000..207c95f
--- /dev/null
@@ -0,0 +1,297 @@
+/**
+ * 运动倒计时 Slice:仅保留 3 秒倒计时 UI,进入即开始,结束通知 Presenter 跳转
+ * 不依赖 saveele,类名 CountdownView/SportCountdownAnimatorCallback 与 saveele 区分
+ */
+#include "sport_countdown/CountdownView.h"
+#include "sport_countdown/CountdownPresenter.h"
+#include "animator/easing_equation.h"
+#include "wearable_log.h"
+#include "common/screen.h"
+#include "custom_utils.h"
+#include "vibrator_service.h"
+#include <cstdio>
+
+namespace OHOS {
+
+const static int16_t CENTER_X = 233;
+const static int16_t CENTER_Y = 233;
+const static int16_t LABEL_X = 140;
+const static int16_t LABEL_Y = 170;
+const static int16_t RADIUS = 90;
+const static int16_t STROKE_WIDTH = 20;
+const static int16_t CIRCLE_BASE_WIDTH = 4;
+const static uint32_t LIGHT_GREEN = 0xff007700;
+const static uint16_t LABEL_FONT_SIZE = 80;
+const static uint16_t ANIMATE_TIME = 500;
+const static uint16_t SECOND_TO_MINISECOND = 1000;
+const static uint16_t CIRCLE_FADE_OUT = 200;
+const static uint16_t DEGREES_PER_CIRCLE = 360;
+
+void SportCountdownAnimatorCallback::Callback(UIView *view) {
+  (void)view;
+  switch (stage_) {
+    case SportCountdownStage::STAGE_GRADUAL_CIRCLE:
+      GradualCircle();
+      break;
+    case SportCountdownStage::STAGE_COUNTING_DOWN:
+      CountingDown();
+      break;
+    case SportCountdownStage::STAGE_FADE_OUT:
+      CircleFadeOut();
+      break;
+    default:
+      break;
+  }
+}
+
+void SportCountdownAnimatorCallback::CircleFadeOut() {
+  uint32_t diffTime = HALTick::GetInstance().GetTime() - lastTime_;
+  if (diffTime < idleTime_)
+    return;
+  canvas_->Clear();
+  uint32_t curTime = diffTime - idleTime_;
+  uint16_t width;
+  if (curTime >= CIRCLE_FADE_OUT) {
+    curTime = CIRCLE_FADE_OUT;
+    stage_ = SportCountdownStage::STAGE_NONE;
+  }
+  width = EasingEquation::QuadEaseInOut(STROKE_WIDTH, CIRCLE_BASE_WIDTH, curTime, CIRCLE_FADE_OUT);
+  Point center = {CENTER_X, CENTER_Y};
+  ColorType lightGreen;
+  lightGreen.full = LIGHT_GREEN;
+  PaintExt paint;
+  paint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+  paint.SetCapType(CAP_ROUND);
+  paint.SetAntialiased(true);
+  paint.SetStrokeColor(lightGreen);
+  paint.SetStrokeWidth(width);
+  canvas_->DrawCircle(center, RADIUS, paint);
+  uint16_t fontSize = LABEL_FONT_SIZE * width / STROKE_WIDTH;
+  uint16_t opa = (stage_ == SportCountdownStage::STAGE_NONE) ? OPA_TRANSPARENT : (OPA_OPAQUE * width / STROKE_WIDTH);
+  label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, fontSize);
+  label_->SetStyle(STYLE_TEXT_OPA, opa);
+}
+
+// 字号变化步长,避免每帧都 SetFont 触发重排/重绘,减轻卡顿
+const static uint16_t FONT_SIZE_STEP = 8;
+
+void SportCountdownAnimatorCallback::UpdateLable(uint32_t curTime) {
+  char buf[8] = {0};
+  uint16_t fontSize;
+  uint16_t opa;
+  if (curTime < ANIMATE_TIME / 2) {
+    fontSize = LABEL_FONT_SIZE - LABEL_FONT_SIZE * curTime * 2 / ANIMATE_TIME;
+    opa = OPA_OPAQUE * fontSize / LABEL_FONT_SIZE;
+    if (firstArc_)
+      fontSize = fontSize / 2;
+  } else {
+    fontSize = LABEL_FONT_SIZE * curTime * 2 / ANIMATE_TIME - LABEL_FONT_SIZE;
+    opa = OPA_OPAQUE * fontSize / LABEL_FONT_SIZE;
+    if (updateText_) {
+      int n = (endAngle_ + easeDegree_) / degreePerSecond_;
+      snprintf(buf, sizeof(buf), "%d", n > 0 ? n : 0);
+      label_->SetText(buf);
+      updateText_ = false;
+    }
+  }
+  // 仅当字号变化超过步长时再 SetFont,减少矢量字重算带来的卡顿
+  if (fontSize != lastFontSize_ &&
+      (fontSize >= lastFontSize_ + FONT_SIZE_STEP || fontSize + FONT_SIZE_STEP <= lastFontSize_ || lastFontSize_ == 0)) {
+    label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, fontSize);
+    lastFontSize_ = fontSize;
+  }
+  label_->SetStyle(STYLE_TEXT_OPA, opa);
+}
+
+void SportCountdownAnimatorCallback::UpdatePath(int16_t start, int16_t end, bool needDrawCircle) {
+  Point center = {CENTER_X, CENTER_Y};
+  ColorType lightGreen;
+  lightGreen.full = LIGHT_GREEN;
+  PaintExt paint;
+  paint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+  paint.SetStrokeWidth(STROKE_WIDTH);
+  paint.SetCapType(CAP_ROUND);
+  paint.SetAntialiased(true);
+  paint.SetStrokeColor(lightGreen);
+  canvas_->Clear();
+  if (needDrawCircle)
+    canvas_->DrawCircle(center, RADIUS, paint);
+  if (start != end) {
+    paint.SetStrokeColor(Color::Green());
+    if (end - start == DEGREES_PER_CIRCLE)
+      canvas_->DrawCircle(center, RADIUS, paint);
+    else
+      canvas_->DrawArc(center, RADIUS, start, end, paint);
+  }
+}
+
+void SportCountdownAnimatorCallback::CountingDown() {
+  uint32_t diffTime = HALTick::GetInstance().GetTime() - lastTime_;
+  if (diffTime >= SECOND_TO_MINISECOND) {
+    lastTime_ = HALTick::GetInstance().GetTime();
+    firstArc_ = (endAngle_ == DEGREES_PER_CIRCLE);
+    UpdatePath(0, endAngle_, true);
+    UpdateLable(0);
+    custom_VibratorFunc_int(0);  // 每秒振动提醒(3、2、1 各一次)
+    if (endAngle_ == 0) {
+      stage_ = SportCountdownStage::STAGE_FADE_OUT;
+      idleTime_ = SECOND_TO_MINISECOND - CIRCLE_FADE_OUT;
+      WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "运动倒计时结束");
+      CountdownPresenter::SetCountdownFinished(true);
+      return;
+    }
+    //振动提醒
+    easeDegree_ = degreePerSecond_;
+    endAngle_ -= degreePerSecond_;
+    if (endAngle_ <= surplusDegree) {
+      endAngle_ = 0;
+      easeDegree_ += surplusDegree;
+    }
+    updateText_ = true;
+  } else if (diffTime >= idleTime_) {
+    uint32_t curTime = diffTime - idleTime_;
+    int16_t arcCurr = EasingEquation::QuadEaseInOut(0, easeDegree_, curTime, ANIMATE_TIME);
+    UpdatePath(0, endAngle_ + easeDegree_ - arcCurr, true);
+    UpdateLable(curTime);
+  }
+}
+
+void SportCountdownAnimatorCallback::GradualCircle() {
+  uint32_t diffTime = HALTick::GetInstance().GetTime() - lastTime_;
+  if (diffTime >= SECOND_TO_MINISECOND) {
+    stage_ = SportCountdownStage::STAGE_COUNTING_DOWN;
+    idleTime_ = SECOND_TO_MINISECOND - ANIMATE_TIME;
+  } else if (diffTime >= idleTime_) {
+    uint32_t curTime = diffTime - idleTime_;
+    int16_t arcCurr = EasingEquation::QuadEaseInOut(0, DEGREES_PER_CIRCLE, curTime, SECOND_TO_MINISECOND - idleTime_);
+    UpdatePath(180, arcCurr + 180, false);
+  }
+}
+
+void SportCountdownAnimatorCallback::SetInfo(UILabel *label, int counts) {
+  counts_ = counts;
+  label_ = label;
+}
+
+void SportCountdownAnimatorCallback::NotifyStart() {
+  stage_ = SportCountdownStage::STAGE_GRADUAL_CIRCLE;
+  endAngle_ = DEGREES_PER_CIRCLE;
+  idleTime_ = 200;
+  degreePerSecond_ = DEGREES_PER_CIRCLE / counts_;
+  surplusDegree = DEGREES_PER_CIRCLE - degreePerSecond_ * counts_;
+  lastTime_ = HALTick::GetInstance().GetTime();
+  lastFontSize_ = LABEL_FONT_SIZE / 2;
+  label_->SetText(" ");
+  label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME_EN, lastFontSize_);
+  label_->SetStyle(STYLE_TEXT_OPA, OPA_OPAQUE);
+}
+
+void SportCountdownAnimatorCallback::CancelCountdown() {
+  stage_ = SportCountdownStage::STAGE_FADE_OUT;
+  lastTime_ = HALTick::GetInstance().GetTime();
+  idleTime_ = 0;
+  endAngle_ = 0;
+}
+
+static CountdownView *g_pCountdownView = nullptr;
+
+CountdownView::CountdownView() {
+  g_pCountdownView = this;
+  ScreenAlwaysOnCtr(OPEN_SCREEN_ALWAYS_ON);  // 运动倒计时期间常亮屏
+}
+
+CountdownView::~CountdownView() {
+  ScreenAlwaysOnCtr(CANCEL_SCREEN_ALWAYS_ON);  // 退出运动倒计时取消常亮屏
+  if (countdownAnimator_) {
+    countdownAnimator_->Stop();
+    delete countdownAnimator_;
+    countdownAnimator_ = nullptr;
+  }
+  if (callBack_) {
+    delete callBack_;
+    callBack_ = nullptr;
+  }
+  if (canvas_) {
+    delete canvas_;
+    canvas_ = nullptr;
+  }
+  if (label_) {
+    delete label_;
+    label_ = nullptr;
+  }
+  if (group_) {
+    delete group_;
+    group_ = nullptr;
+  }
+  g_pCountdownView = nullptr;
+}
+
+CountdownView *CountdownView::GetInstance() {
+  return g_pCountdownView;
+}
+
+void CountdownView::InitCountdownView() {
+  canvas_ = new UICanvasExt();
+  if (!canvas_) return;
+  canvas_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+  canvas_->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+  group_->Add(canvas_);
+
+  label_ = new UILabel();
+  if (!label_) return;
+  label_->SetPosition(LABEL_X, LABEL_Y, 180, 120);
+  label_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+  group_->Add(label_);
+
+  PaintExt paint;
+  ColorType lightGreen;
+  lightGreen.full = LIGHT_GREEN;
+  paint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+  paint.SetStrokeWidth(CIRCLE_BASE_WIDTH);
+  paint.SetAntialiased(true);
+  paint.SetStrokeColor(lightGreen);
+  canvas_->DrawCircle({CENTER_X, CENTER_Y}, RADIUS, paint);
+
+  callBack_ = new SportCountdownAnimatorCallback(canvas_);
+  if (!callBack_) return;
+  countdownAnimator_ = new Animator(callBack_, canvas_, 0, true);
+  if (!countdownAnimator_) {
+    delete callBack_;
+    callBack_ = nullptr;
+    return;
+  }
+  countdownAnimator_->Start();
+  callBack_->SetInfo(label_, 3);
+}
+
+void CountdownView::StartCanvas() {
+  if (callBack_)
+    callBack_->NotifyStart();
+}
+
+void CountdownView::StopCanvas() {
+  if (callBack_)
+    callBack_->CancelCountdown();
+}
+
+void CountdownView::OnStart() {
+  group_ = new UIViewGroup();
+  if (!group_) return;
+  group_->SetPosition(0, 0);
+  group_->SetWidth(Screen::GetInstance().GetWidth());
+  group_->SetHeight(Screen::GetInstance().GetHeight());
+  group_->SetTouchable(true);
+  group_->SetDraggable(true);
+
+  InitCountdownView();
+  AddViewToRootContainer(group_);
+
+  if (canvas_)
+    canvas_->SetVisible(true);
+  if (label_)
+    label_->SetVisible(true);
+  StartCanvas();
+  // SetViewState(true);
+}
+
+}  // namespace OHOS
index cfc1ee5..ef92ba2 100644 (file)
@@ -77,6 +77,9 @@
  #include <custom_save_runtime.h>
  
  #include "graphic_service.h"
+ #include "NativeAbility.h"
+ #include "AppViewIDs.h"
+ #include "sport_countdown/CountdownPresenter.h"
  
  #if defined(SUPPORT_GNSS)
  #include "NMEA0183.h"
@@ -1848,9 +1851,10 @@ bool TraingModel::GetMomentum() {
      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "id is error");
      return;
    }
-   // 开始训练 ->不返回
-   NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGCRAD);
-   // 配置运动项
+    // 进入运动倒计时 3 秒,结束后跳转运动卡片
+   CountdownPresenter::SetReturnSlice(VIEW_TRAININGCRAD);
+   NativeAbility::GetInstance().EnterSlice(VIEW_SPORT_COUNTDOWN);
+   // 配置运动项(先完成配置,再进 3 秒倒计时,倒计时结束进入运动界面)
    SetSportEvent(id);
    // 获取运动项目
    ExerciseClass type = GetSportId();
@@ -3288,14 +3292,20 @@ bool TraingModel::LoadGPSData(const std::string &filePath) {
  #endif
  }
  
- /*
-  * @brief 位置服务定时器回调函数
-  */
- static void gnss_timer_callback(int data) {
-   WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "gnss_timer_callback %d", data);
-   GraphicService::GetInstance()->PostGraphicEvent(
-       std::bind(gnss_timer_callbackProc, data));
- }
+/*
+ * @brief 位置服务定时器回调函数
+ * 倒计时期间定时器照常触发,但不投递到 GUI、不执行逻辑,避免与倒计时动画抢线程
+ */
+static void gnss_timer_callback(int data) {
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "gnss_timer_callback %d", data);
+#if defined(SUPPORT_GNSS)
+  if (NativeAbility::GetInstance().GetCurSliceId() == VIEW_SPORT_COUNTDOWN) {
+    return;  // 当前在运动倒计时 slice,只正常定时,不操作
+  }
+#endif
+  GraphicService::GetInstance()->PostGraphicEvent(
+      std::bind(gnss_timer_callbackProc, data));
+}
  
  /*
   *  @brief 开启位置服务定时器函数
index 605649c..b04029d 100644 (file)
@@ -2,6 +2,7 @@
 #include "components/ui_label_ext.h"
 #include "ui_resource_string.h"
 #include "NativeAbility.h"
+#include "sport_countdown/CountdownPresenter.h"
 
 #include <iostream>
 #include <chrono>
@@ -71,10 +72,8 @@ namespace OHOS
         // 根据控件id查找是哪个控件触发了点击回调
         if (strcmp(view.GetViewId(), BUTTONTRAIN) == 0)
         {
-            // 去训练按钮 - 直接进入运动卡片(跳过星历检查)
-            NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGCRAD);
-            
-            // 启动运动相关资源
+            CountdownPresenter::SetReturnSlice(VIEW_TRAININGCRAD);
+            NativeAbility::GetInstance().EnterSlice(VIEW_SPORT_COUNTDOWN);
             ExerciseClass type = TraingModel::GetInstance()->GetSportId();
             TraingCardPresenter::GetInstance()->OpenSensor(type);
             TraingModel::GetInstance()->SetSportOpenWay(false);
index d185088..0b6e3cb 100644 (file)
@@ -3,6 +3,7 @@
 #include "components/ui_label_ext.h"
 #include"ui_resource_string.h"
 #include "NativeAbility.h"
+#include "sport_countdown/CountdownPresenter.h"
 
 #include <iostream>
 #include <chrono>
@@ -90,9 +91,9 @@ namespace OHOS
         }
         if (strcmp(view.GetViewId(), GPSBUTTONGO) == 0)
         {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "TraingGPSnotePresenter::OnClick BUTTONGO");
-            NativeAbility::GetInstance().ChangeSlice(VIEW_TRAININGCRAD);
-            // 启动运动相关资源
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "TraingGPSnotePresenter::OnClick BUTTONGO GPS未定位跳过,也走运动倒计时");
+            CountdownPresenter::SetReturnSlice(VIEW_TRAININGCRAD);
+            NativeAbility::GetInstance().EnterSlice(VIEW_SPORT_COUNTDOWN);
             ExerciseClass type = TraingModel::GetInstance()->GetSportId();
             TraingCardPresenter::GetInstance()->OpenSensor(type);
             TraingModel::GetInstance()->SetSportOpenWay(false);