/*
 * Copyright (c) Huawei Device Co., Ltd. 2024-2025. All rights reserved.
 * 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.
 */

import Curves from '@ohos.curves';
import lazy { lottie, AnimationItem } from '../../utils/LazyImportUtil';
import lazy { HiLog } from '../../utils/HiLog';
import lazy { OhCombinedState, Dispatch, Unsubscribe, getStates } from '../../redux';
import lazy { Action, ActionData, UiStateMode } from '../../redux/actions/Action';
import lazy { RecordAction } from '../recordcontrol/RecordAction';
import lazy { RecordingState } from '../recordcontrol/RecordAction';
import lazy { ComponentIdKeys } from '../../utils/ComponentIdKeys';
import lazy { FunctionAction } from '../core/FunctionAction';
import lazy { RecordMode } from '../recordcontrol/RecordMode';
import lazy { FunctionId } from '../core/functionproperty/FunctionId';
import lazy { FeatureManager } from '../core/FeatureManager';
import lazy { SettingFuncDialogItemIndex } from '../../component/settingview/SettingFuncDialogItemIndex';
import lazy { ModeType } from '../../mode/ModeType';
import lazy { AnimSpecifications } from '../../animation/AnimSpecifications';
import lazy { EventBus } from '../../worker/eventbus/EventBus';
import lazy { EventBusManager } from '../../worker/eventbus/EventBusManager';
import lazy { CameraAction, CameraRunningState } from '../../camera/uithread/CameraAction';
import lazy { CaptureAction } from './CaptureAction';
import lazy { AudioControlShutterButton } from './AudioControlShutterButton';
import lazy { UIOperationType } from '../../component/uicomponent/UIOperationType';
import lazy { VideoTimer } from '../../component/videoTimer/VideoTimer';
import camera from '@ohos.multimedia.camera';
import lazy { BaseComponent } from '../../worker/BaseComponent';
import lazy { PowerKeyService } from '../../service/powerKey/PowerKeyService';
import lazy { WindowEventData, WindowStatusChangeActionData } from '../../utils/types';
import window from '@ohos.window';
import lazy { CaptureService } from './CaptureService';
import lazy { FlashMode } from '../enumbase/FlashMode';
import lazy { TipService } from '../../component/tip/TipService';
import lazy { ShutterButtonType, ShutterController } from './ShutterController';
import lazy { VibratorService } from '../../component/vibration/VibratorService';
import lazy { CameraProxy } from '../../camera/uithread/CameraProxy';
import lazy { DeviceInfo } from '../../component/deviceinfo/DeviceInfo';
import lazy { OutputType } from '../outputswitcher/OutputType';
import lazy { OutputSwitcher } from '../outputswitcher/OutputSwitcher';
import display from '@ohos.display';
import lazy { CameraAppCapability } from '../../camera/CameraAppCapability';
import lazy { ContextManager } from '../../service/context/ContextManager';
import lazy { systemDateTime } from '../../utils/LazyImportUtil';
import ResGetter from '../../utils/ResGetter';
import lazy { CommonConstants } from '../../statistics/CommonConstants';
import lazy { ThumbnailService } from '../../component/thumbnail/ThumbnailService';
import lazy { WindowService } from '../../service/window/WindowService';
import lazy { PickerUtils } from '../../utils/PickerUtils';
import lazy { PickerWindowType } from '../../component/picker/PickerWindowType';
import lazy { CaptureScene } from './CaptureFunction';
import lazy { DisplayService } from '../../service/UIAdaptive/DisplayService';
import lazy { ContinuumVideoButton } from './ContinuumVideoButton';
import lazy { AccessibilityUtils } from '../../utils/AccessibilityUtils';
import lazy { simpleStringify } from '../../utils/SimpleStringify';
import lazy { RecordController, RecordType } from '../recordcontrol/RecordController';
import lazy { MemoryService } from '../../service/Memory/MemoryService';
import lazy { StoreManager } from '../../worker/StoreManager';
import lazy { PickerAction } from '../../service/picker/PickerAction';
import lazy { execAction } from '../../redux/ActionRegistry';
import lazy { BlurAnimateUtil } from '../../utils/BlurAnimateUtil';
import lazy { AuxiliaryMode } from '../enumbase/AuxiliaryMode';
import lazy { reduxSubscribe } from '../../redux/Store';
import lazy { TimeLapseActionType } from '../../redux/actions/TimeLapseActionType';
import lazy { FloatingShutterActionType } from '../../redux/actions/FloatingShutterActionType';
import lazy { CameraActionType } from '../../redux/actions/CameraActionType';
import lazy { ActionType } from '../../redux/actions/ActionType';
import lazy { FunctionActionType } from '../../redux/actions/FunctionActionType';
import lazy { RecordActionType } from '../../redux/actions/RecordActionType';
import lazy { ContextActionType } from '../../redux/actions/ContextActionType';
import lazy { CollaborateControlActionType } from '../../redux/actions/CollaborateControlActionType';
import lazy { CaptureActionType } from '../../redux/actions/CaptureActionType';
import lazy { LeftRightSwipeActionType } from '../../redux/actions/LeftRightSwipeActionType';
import type { TimeLapseRecordMessage } from '../../camera/DataType';
import lazy { WindowDirection } from '../../utils/WindowDirection';
import lazy { WindowActionType } from '../../redux/actions/WindowActionType';
import lazy { LocationMessage } from '../../service/location/LocationMessage';
import lazy { LocationManager } from '../../service/location/LocationManager';
import {
  LeftRightSwipeWorkerCaptureService
} from '../../component/leftrightswipecontrol/LeftRightSwipeWorkerCaptureService';

export const QUEUE_SIZE: number = 4;

export const MIN_LOADING_MODE_DURATION: number = 800;

const CAPTURE_DELAY: number = 10;
const RECORD_UP_DELAY: number = 10;
const IMMERSIVE_DELAY: number = 250;
const INVALID_CAPTURE_DURATION: number = 0;
const MAX_CLICK_MODE_DURATION: number = 350;
const MIN_COUNTER_DOWN_MODE_DURATION: number = 1500;
const PRO_SHUTTER_THRESHOLD: number = 1000000;
const SHUTTER_ANIMATE_DELAY: number = 100;
const CAN_AUDIO_SHUTTER_DELAY: number = 1000;
const TIP_DURING: number = 3000;
const STITCHING_STATUS_HIDE_DELAY = 1000;

/* instrument ignore file */
const TAG: string = 'ShutterButton';
const NIGHT_START_LOOP: string = 'nightStartLoop';
const NIGHT_STOP_LOOP: string = 'nightStopLoop';
const NIGHT_CAPTURE_FIRST_LOOP: string = 'nightCaptureFirstLoop';
const NIGHT_CAPTURE_SECOND_LOOP: string = 'nightCaptureSecondLoop';

const STITCHING_FIRST_LOOP: string = 'stitchingFirstLoop';
const STITCHING_SECOND_LOOP: string = 'stitchingSecondLoop';

const NIGHT_EXPOSURE_PATH: string = 'common/lottie/night_exposure.json';
const NIGHT_CAPTURE_FIRST_PATH: string = 'common/lottie/night_capture_first.json';
const NIGHT_CAPTURE_SECOND_PATH: string = 'common/lottie/night_capture_second.json';
const LIGHT_PAINTING_CAPTURE_FIRST_LOOP: string = 'lightPaintingCaptureFirstLoop';
const LIGHT_PAINTING_CAPTURE_PATH: string = 'common/lottie/light_painting_capture.json';
const SHUTTER_OUT_SHADE_COLOR: string = '#334d4d4d';
const REFRESH_MINIMUM_TIME: number = 50;
const SLEEP: Function = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
const CLICK_DOWN_CAPTURE_SUPPORT_MODE: ModeType[] = [ModeType.PHOTO];

class FrameStartData {
  public isPreviewFrameStart: boolean = false;
}

class VideoErrorData {
  public code: number = 0;
  public msg: string = '';
}

class VolumeKeyPhotoData {
  public isDown: boolean = false;
}

class PickerData {
  public isPicker: boolean = false;
  public dbValue?: number = 0;
  public dbThreshold?: number = 0;
  public dbStateList?: number[];
}

interface ProShutterValue {
  functionId: FunctionId,
  value: number
}

interface FunctionConflictParamData {
  id: FunctionId,
  conflictParam: Object
}

class EnterImmersiveData {
  public isImmersive: boolean = false;
}

class ShutterButtonDispatcher {
  private mDispatch: Dispatch = (data) => data;
  private lastClickRefreshTime: number = 0;

  public setDispatch(dispatch: Dispatch) {
    this.mDispatch = dispatch;
  }

  //TODO 到这里一切都是正常的
  public capture(): void {
    this.mDispatch(Action.updateIsShowParamBar(true));
    this.mDispatch(Action.updateIsShowExtendBar(false));
    this.mDispatch(Action.proSonChangeState(-1));
    this.mDispatch(Action.changeShowExtendComponent(FunctionId.NONE));
    this.mDispatch(CaptureAction.capture());
  }

  public startRecording(isSoundEffect: boolean = true): void {
    this.mDispatch(Action.proSonChangeState(-1));
    this.mDispatch(Action.uiStateWithMode(false, UiStateMode.EXCLUDE_PREVIEW));
    this.mDispatch(RecordAction.start(isSoundEffect));
  }

  public updateShowPickerView(showPicker: boolean): void {
    this.mDispatch(Action.updateShowPickerView(showPicker, true));
  }

  public stopRecording(): void {
    this.mDispatch(Action.uiStateWithMode(false, UiStateMode.EXCLUDE_PREVIEW));
    this.mDispatch(RecordAction.stop());
  }

  public changeTimeLapse(isShowtimeLapse: boolean): void {
    this.mDispatch(Action.changeTimeLapse(isShowtimeLapse));
  }

  public changeTimedShot(isShowTimedShot: boolean): void {
    this.mDispatch(Action.changeTimedShot(isShowTimedShot));
  }

  public changeFunctionValue(id: FunctionId, value: number | string | boolean): void {
    this.mDispatch(FunctionAction.changeFunctionValue(id, value));
  }

  public isEnterImmersive(isEnterImmersive: boolean): void {
    if (isEnterImmersive) {
      this.mDispatch(Action.isEnterImmersive(isEnterImmersive, UIOperationType.FOOT_BAR));
    } else {
      this.mDispatch(Action.isEnterImmersive(isEnterImmersive, UIOperationType.NULL));
    }
  }

  public confirmCapture(): void {
    this.mDispatch(CaptureAction.confirmCapture());
  }

  public confirmCaptureEffect(): void {
    this.mDispatch(Action.updateIsShowParamBar(true));
    this.mDispatch(Action.updateIsShowExtendBar(false));
    this.mDispatch(Action.proSonChangeState(-1));
    this.mDispatch(Action.changeShowExtendComponent(FunctionId.NONE));
    this.mDispatch(Action.confirmCaptureEffect());
  }

  public isClearExposureTime(): void {
    this.mDispatch(Action.isResetExposureTime());
  }

  public enableUiWithMode(uiStateMode: UiStateMode, excludeComponent: string): void {
    this.mDispatch(Action.uiStateWithMode(true, uiStateMode, excludeComponent));
  }

  public disableUiWithMode(uiStateMode: UiStateMode, excludeComponent: string): void {
    this.mDispatch(Action.uiStateWithMode(false, uiStateMode, excludeComponent));
  }

  public disAbleModeBarChanged(isNeedDisShowingMode: boolean): void {
    this.mDispatch(Action.disAbleModeBarChanged(isNeedDisShowingMode));
  }

  public hideThumbnailAndSwitchButton(): void {
    this.mDispatch(Action.hideThumbnailAndSwitchButton());
  }

  public longExposureShutter(): void {
    AppStorage.setOrCreate('longExposureShutter', true);
    this.mDispatch(Action.longExposureShutter());
  }

  public longExposureShutterEnd(): void {
    AppStorage.setOrCreate('longExposureShutter', false);
    this.mDispatch(Action.longExposureShutterEnd());
  }

  public countDownShutter(): void {
    this.mDispatch(Action.countDownShutter());
  }

  public countDownShutterEnd(): void {
    this.mDispatch(Action.countDownShutterEnd());
  }

  public captureEnd(): void {
    this.mDispatch(Action.captureEnd());
  }

  public proSonChangeState(iconId: number): void {
    this.mDispatch(Action.proSonChangeState(iconId));
  }

  public uiDisabled(): void {
    this.mDispatch(Action.uiState(false));
  }

  public uiEnabled(): void {
    this.mDispatch(Action.uiState(true));
  }

  public async longClickStatusChange(isLongClicked: boolean): Promise<void> {
    let currentTime: number = Date.now();
    let refreshInterval: number = (currentTime - this.lastClickRefreshTime) < 0
      ? currentTime : (currentTime - this.lastClickRefreshTime);
    HiLog.i(TAG, `clickStatus refreshInterval:${refreshInterval} for longclick ${isLongClicked}`);
    let pauseTime: number = 0;
    if (refreshInterval < REFRESH_MINIMUM_TIME) {
      pauseTime = REFRESH_MINIMUM_TIME - refreshInterval;
      await SLEEP(pauseTime);
      HiLog.i(TAG, `clickStatus pause finish for :${refreshInterval}`);
    }
    this.lastClickRefreshTime = currentTime + pauseTime;
    HiLog.i(TAG, `longClickChange ${isLongClicked}`);
  }

  public isShowExtendBarAndParamBar(): void {
    this.mDispatch(Action.updateIsShowParamBar(true));
    this.mDispatch(Action.updateIsShowExtendBar(false));
  }

  public async startLightPainting(): Promise<void> {
    const startTimeSeconds: number = await systemDateTime.getRealTime(false);
    this.mDispatch(execAction('LightPaintingAction', 'start'));
    this.mDispatch(execAction('LightPaintingAction', 'setStartSeconds', startTimeSeconds + CAPTURE_DELAY));
    this.mDispatch(execAction('LightPaintingAction', 'setLightPaintingTimerShow', true));
  }

  public showLightPaintingFlashTimer(): void {
    this.mDispatch(execAction('LightPaintingAction', 'setLightPaintingFlashTimerShow', true));
  }

  public stopLightPaintingFlashTimer(): void {
    this.mDispatch(execAction('LightPaintingAction', 'setLightPaintingFlashTimerShow', false));
  }

  public stopLightPaintingTimer(): void {
    this.mDispatch(execAction('LightPaintingAction', 'setLightPaintingTimerShow', false));
  }

  public startPanorama(): void {
    this.mDispatch(Action.startPanorama());
  }

  public stitchingCaptureStart(): void {
    this.mDispatch(Action.stitchingCaptureStart())
  }

  public stitchingCaptureEnd(): void {
    this.mDispatch(Action.stitchingCaptureEnd())
  }

  public hideStitchingStatusView(delayTime?: number): void {
    this.mDispatch(execAction('StitchingAction', 'hideStitchingStatus', delayTime ? delayTime : 0));
  }

  public endPanorama(): void {
    this.mDispatch(Action.endPanorama());
  }

  public nightCapture(): void {
    this.mDispatch(CaptureAction.nightCapture());
  }

  public hideExtendBar(): void {
    this.mDispatch(Action.updateIsShowParamBar(true));
    this.mDispatch(Action.updateIsShowExtendBar(false));
  }
}

@Component
export struct ShutterButton {
  private isShutterButtonLongClick: boolean = false;
  @Link touchEvent: TouchEvent | null;
  private currentTouchEvent: TouchEvent | null = null;
  private timeoutID: number = 0;
  @State @Watch('changeOuterBackground') isLrShutterShown: boolean = false;
  @Link isInLrImmersive: boolean;
  private mBase: BaseComponent = new BaseComponent();
  private cameraManager: camera.CameraManager | undefined;
  type: ButtonType = ButtonType.Normal;
  stateEffect: boolean = false;
  @State uiEnable: boolean = false;
  @State excludeComponent: string = UIOperationType.NULL;
  @State mode: ModeType = ModeType.NONE;
  @State isShowtimeLapse: boolean = false;
  @State cameraPosition: camera.CameraPosition = camera.CameraPosition.CAMERA_POSITION_UNSPECIFIED;
  @State isLockRotation: boolean = true;
  private exposureTime: number = 0;
  @State estimatedCaptureDuration: number = 0;
  @State @Watch('videoStateOnChange') videoState: RecordingState = RecordingState.READY;
  @State isShowCapture: boolean = false;
  @State isShowVideo: boolean = false;
  @State isShowNight: boolean = false;
  @State isShowLongExposure: boolean = false;
  @State isShowLoading: boolean = false;
  @State isShowCountDown: boolean = false;
  @State captureBtnScale: ScaleOptions = { x: 1, y: 1 };
  @State captureBtnOpacity: number = 1;
  @State captureBtn2Opacity: number = 1;
  @State videoBtn1Scale: ScaleOptions = { x: 1, y: 1 };
  @State videoBtn1Opacity: number = 1;
  @State videoBtn2Scale: ScaleOptions = { x: 0.5, y: 0.5 };
  @State videoBtn2Opacity: number = 0;
  @State videoWidth: number = AnimSpecifications.ANIM_VIDEO_BUTTON_WIDTH_END;
  @State videoRadius: number = AnimSpecifications.ANIM_VIDEO_BUTTON_RADIUS_END;
  @State videoColor: Color | string = AnimSpecifications.ANIM_VIDEO_BUTTON_COLOR_END;
  @State nightBtn1Scale: ScaleOptions = { x: 1, y: 1 };
  @State nightBtn1Opacity: number = 1;
  @State nightBtn2Scale: ScaleOptions = { x: 1, y: 1 };
  @State nightBtn2Opacity: number = 1;
  @State audioCaptureBtnScale: ScaleOptions = { x: 1, y: 1 };
  @State audioCaptureBtnVisibility: Visibility = Visibility.Visible;
  @State nightWidth: number = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
  @State nightRadius: number = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
  @State nightColor: Color = AnimSpecifications.ANIM_NIGHT_BUTTON_COLOR_END;
  @State confirmCaptureState: boolean = false;
  @State nightShutterStatus: boolean = false;
  @State audioControlShutterStatus: boolean = true;
  @State nightStartCaptureState: boolean = false;
  @State nightCaptureFirstFinish: boolean = false;
  @State loadingCaptureFirstFinish: boolean = false;
  @State shouldExitLongExposure: boolean = false;
  @State captureBtnWidth: number = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
  @State captureBtnRadius: number = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
  private mAction: ShutterButtonDispatcher = new ShutterButtonDispatcher();
  private mCaptureService: CaptureService = CaptureService.getInstance();
  private mEventBus: EventBus = EventBusManager.getInstance().getEventBus();
  @State audioControlType: SettingFuncDialogItemIndex = SettingFuncDialogItemIndex.INDEX_NONE;
  @State rotateAngle: number = 0;
  @State @Watch('rotateAngleChanged') rotateAngleWatch: number = 0;
  @Prop innerHorizontalOffset: number = 0;
  private mSubscriber: Unsubscribe = {
    destroy: () => {
    }
  };
  @StorageLink('nightCaptureStarted') nightCaptureStarted: boolean = false;
  @StorageLink('isOpenOrCloseTreasureBox') isOpenOrCloseTreasureBox: boolean = false; //百宝箱是否在做开关动效中
  // picker
  private singleStagePhotoCaptured: boolean = false;
  private isPicker: boolean = false;
  @State pickerWindowType: PickerWindowType = PickerWindowType.COLLAPSED_VERTICAL_FULL;
  // 夜景后置拍照按钮三种动画:小圆点消失、圆环动态更新、小圆点静止
  private antiAliasingSetting: RenderingContextSettings = new RenderingContextSettings(true);
  private mLoopStartController: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.antiAliasingSetting);
  private mLoopsStopController: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.antiAliasingSetting);
  private mLoopCaptureFirstController: CanvasRenderingContext2D =
    new CanvasRenderingContext2D(this.antiAliasingSetting);
  private mLoopCaptureSecondController: CanvasRenderingContext2D =
    new CanvasRenderingContext2D(this.antiAliasingSetting);
  private exposureStartAnimationItem: AnimationItem | undefined = undefined;
  private exposureStopAnimationItem: AnimationItem | undefined = undefined;
  private captureStartFirstAnimationItem: AnimationItem | undefined = undefined;
  private captureStartSecondAnimationItem: AnimationItem | undefined = undefined;
  private interval: number = 0;
  private timelapseDurationTimerId: number = Number.MIN_VALUE;
  private nightTimerId: number = Number.MIN_VALUE;
  private nightImmersiveTimerId: number = Number.MIN_VALUE;
  @State private isDuringSavePowerMode: boolean = false;
  @State currentButtonType: ShutterButtonType = ShutterButtonType.NULL;
  private mHasClickDownCapture: boolean = false;
  private mCountDownBtnDuration: number = 0;
  private mWaitingThumbnailAnimation: boolean = false;
  private mIsLongCaptureWaitingClickUp: boolean = false;
  private horizontallyArranged: boolean = true;
  @StorageLink('isTimeLapseVideoRecording') isTimeLapseVideoRecording: boolean = false;
  private isDelaySendCaptureEnd: boolean = false;
  private isFrameStarted: boolean = false;
  private isIgnoreTouch = false;
  @StorageLink('slowRecordingCompVisible') slowRecordingCompVisible: boolean = true;
  @State collapsStatus: display.FoldStatus = display.FoldStatus.FOLD_STATUS_UNKNOWN;
  @State @Watch('updateDensity') density: number = 1 //DisplayService.getInstance().getDisplay().densityPixels;
  @State isShowSubScreenRadius: boolean = false;
  @State isTakePhoto: boolean = false;
  @State proShutterValue: number = 0;
  @StorageLink('isProShutterCaptureState') isProShutterCapture: boolean = false;
  @State isHalfCollapsLEM: boolean = false;
  @State isVdeCollapsed: boolean = false;
  private outerLottiePath = NIGHT_EXPOSURE_PATH;
  private outerFirstLoopLottieName = NIGHT_CAPTURE_FIRST_LOOP;
  private isLottieLoop: boolean = false;
  private screenWidth: number = 0;
  private screenHeight: number = 0;
  private immersiveDelay = IMMERSIVE_DELAY;
  private shutterDownTime: number = -1;
  @State shutterOutsideBackground: ResourceColor = SHUTTER_OUT_SHADE_COLOR;
  @State shutterAllVisibility: Visibility = Visibility.Visible;
  private invisibleTimeout: number = Number.MIN_VALUE;
  private shouldApplyShade: boolean = false;
  // 多任务停流方案,快门状态需要重置
  private isMultiTaskStopStream: boolean = CameraAppCapability.getInstance().getIsSupportStopStreamToMultiTask();
  private isBackground: boolean = false;
  @StorageLink('onActionMenuShow') isShowActionMenu: boolean = false;

  aboutToAppear() {
    HiLog.i(TAG, 'aboutToAppear E.');
    this.rotateAngle = getStates().get<number>('contextReducer', 'rotateAngle');
    this.mSubscriber = reduxSubscribe((state: OhCombinedState) => {
      this.rotateAngleWatch = state.get<number>('contextReducer', 'rotateAngle');
      this.videoState = state.get<RecordingState>('recordReducer', 'recordingState');
      this.density = state.get<number>('collapsReducer', 'density');
      this.isHalfCollapsLEM = state.get<boolean>('collapsReducer', 'isHalfCollapsLEM');
      this.isVdeCollapsed = state.get<boolean>('collapsReducer', 'isVdeCollapsed');
      this.screenWidth = state.get<number>('windowReducer', 'windowWidth');
      this.screenHeight = state.get<number>('windowReducer', 'windowHeight');
      this.uiEnable = state.get<boolean>('contextReducer', 'uiEnable');
      this.mode = state.get<ModeType>('modeReducer', 'mode');
      this.isShowtimeLapse = state.get<boolean>('settingReducer', 'isShowtimeLapse');
      this.cameraPosition = state.get<camera.CameraPosition>('cameraReducer', 'cameraPosition');
      this.isLockRotation = state.get<boolean>('windowReducer', 'isLockRotation');
      this.exposureTime = state.get<number>('contextReducer', 'exposureTime');
      this.estimatedCaptureDuration = state.get<number>('contextReducer', 'estimatedCaptureDuration');
      this.excludeComponent = state.get<string>('contextReducer', 'excludeComponent');
      this.isDuringSavePowerMode = state.get<boolean>('contextReducer', 'isDuringSavePowerMode');
      this.isShutterButtonLongClick = state.get<boolean>('leftRightSwipeReducer', 'longClicked');
      this.isLrShutterShown = state.get<boolean>('leftRightSwipeReducer', 'lrShutterShown');
      this.collapsStatus = state.get<display.FoldStatus>('collapsReducer', 'collapsStatus');
      this.pickerWindowType = state.get<PickerWindowType>('windowReducer', 'pickerWindowType');
    }, (dispatch: Dispatch): void => {
      this.mAction.setDispatch(dispatch);
    });
    this.initMode();
    this.mEventBus.on(TimeLapseActionType.START_VIDEO_ANIM, this.startVideoAnim.bind(this), this.mBase.hashCode());
    this.mEventBus.on([CameraActionType.CHANGE_MODE,
      CameraActionType.CHANGE_OUTPUT_TYPE,
      CameraActionType.SWITCH_CAMERA_CHANGE_MODE,
      CameraActionType.SWITCH_CAMERA, CameraActionType.STARTED], () => this.modeOnChange(), this.mBase.hashCode());
    this.mEventBus.on(RecordActionType.ERROR, this.onVideoError.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ContextActionType.CHANGE_WINDOW_EVENT_TYPE, this.onChangeWindowEventType.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ContextActionType.CHANGE_EXTENSION_WINDOW_EVENT_TYPE,
      this.onChangeExtensionWindowEventType.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(FloatingShutterActionType.FLOATING_SHUTTER_BUTTON_CLICK,
      this.clickFloatingShutterButton.bind(this), this.mBase.hashCode());
    this.mEventBus.on(CollaborateControlActionType.CAPTURE, this.onCollaborateControlCapture.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(CollaborateControlActionType.VIDEO, this.onCollaborateControlVideo.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ActionType.AUDIO_CONTROL_SHUTTER_BUTTON, this.audioControlShutterButton.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ContextActionType.DEV_ON_SHUTDOWN, this.onDevShutdown.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_NIGHT_CAPTURE_END, this.captureEnd.bind(this), this.mBase.hashCode());
    this.mEventBus.on(CameraActionType.PREEMPTION_WITH_ERROR, this.onBackground.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_DELAY_SEND_CAPTURE_END, this.delaySendCaptureEnd.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_CHANGE_TIME_LAPSE, this.timeLapseEnd.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ContextActionType.ABILITY_ON_BACKGROUND, this.onBackground.bind(this), this.mBase.hashCode());
    this.mEventBus.on(CaptureActionType.VOLUME_KEY_EVENT, this.volumeKeyEventShutter.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_POWER_KEY_DURATION_ONE_SECOND, this.powerKeyDownDuration.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(CaptureActionType.RICH_CAPTURE_NEXT, this.onRichCaptureNext.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_FRAME_SHUTTER_END, this.onFrameShutterEnd.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_SHOW_PICKER,
      this.onPickerReCapture.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ContextActionType.ABILITY_ON_FOREGROUND, this.onForeground.bind(this), this.mBase.hashCode());
    this.mEventBus.on(LeftRightSwipeActionType.FORCE_EXIT_LR_BURST, this.forceClickUp.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(LeftRightSwipeActionType.FORCE_EXIT_LR_RECORD,
      this.forceClickUpRecord.bind(this), this.mBase.hashCode());
    this.mEventBus.on(LeftRightSwipeActionType.RESET, this.doShutterExpandAnimation.bind(this), this.mBase.hashCode());
    this.mEventBus.on(CaptureActionType.IS_REMOTECAPTURE_EVENT, this.remoteCaptureEvent.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_COUNT_DOWN_SHUTTER_AFTER_TIMELAPSE,
      this.playLongExposureAfterTimeLapse.bind(this), this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_IS_ENTER_IMMERSIVE, this.isEnterImmersive.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(FunctionActionType.ACTION_SET_FUNCTION_CONFLICT_PARAM, this.onConflictParamChange.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(FunctionActionType.ACTION_CHANGE_FUNCTION_VAL, this.onFunctionChange.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_CHANGE_TIMED_SHOT, this.timeLapseEnd.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(CaptureActionType.IS_READY_FOR_NEXT_AUTO_CAPTURE, this.readyForNextAutoCapture.bind(this),
      this.mBase.hashCode());
    this.mEventBus.on(ActionType.ACTION_ON_PREVIEW_FRAME_START, this.onFrameStartStatusChanged.bind(this),
      this.mBase.hashCode());
    HiLog.i(TAG, 'aboutToAppear X.');
  }

  onConflictParamChange(data: FunctionConflictParamData) {
  }

  private readyForNextAutoCapture(): void {
    this.photoProcess(false, false);
  }

  aboutToDisappear(): void {
    HiLog.i(TAG, 'aboutToDisappear E.');
    this.mEventBus.clear(this.mBase.hashCode());
    this.mSubscriber.destroy();
    this.clearTimer();
    this.mAction.isClearExposureTime();
    this.lottieAnimationDestroy();
    HiLog.i(TAG, 'aboutToDisappear X.');
  }

  private rotateAngleChanged(): void {
    if (this.rotateAngle === this.rotateAngleWatch) {
      return;
    }
    animateToImmediately({
      duration: AnimSpecifications.ANIM_DURATION_300,
      curve: Curve.Friction,
      iterations: 1,
      playMode: PlayMode.Normal,
    }, () => {
      this.rotateAngle = this.rotateAngleWatch
    });
  }

  private lottieAnimationDestroy(): void {
    // 只销毁当前组件内的lottie动画
    this.exposureStartAnimationItem?.destroy();
    this.exposureStopAnimationItem?.destroy();
    this.captureStartFirstAnimationItem?.destroy();
    this.captureStartSecondAnimationItem?.destroy();
  }

  private onFrameStartStatusChanged(data: FrameStartData) {
    this.isFrameStarted = data.isPreviewFrameStart;
  }

  private onRichCaptureNext(): void {
    this.photoProcess(false, true);
  }

  private clearTimelapseDurationTimer(): void {
    HiLog.i(TAG, 'clearTimelapseDurationTimer');
    if (Number.MIN_VALUE !== this.timelapseDurationTimerId) {
      clearTimeout(this.timelapseDurationTimerId);
    }
  }

  private onDevShutdown(): void {
    this.onStatePaused('devOnShutDown');
  }

  private onChangeWindowEventType(data: WindowEventData): void {
    if (data.windowStageEventType === window.WindowStageEventType.PAUSED) {
      this.onStatePaused('onStagePaused');
      this.forceClickUp();
      if (this.isMultiTaskStopStream) {
        HiLog.i(TAG, 'isMultiTaskStopStream, onBackground reset shutterButton status');
        this.onBackground();
      }
    } else if (data.windowStageEventType === window.WindowStageEventType.RESUMED) {
      if (this.isMultiTaskStopStream) {
        HiLog.i(TAG, 'isMultiTaskStopStream, onForeground reset shutterButton status');
        this.onForeground();
      }
    }
    if (!this.cameraManager) {
      this.cameraManager = camera.getCameraManager(ContextManager.getInstance().getAbilityStageContext());
    }
    if (data.windowStageEventType === window.WindowStageEventType.INACTIVE &&
      (this.cameraManager.isCameraMuted())) {
      if (this.videoState !== RecordingState.READY &&
        this.videoState !== RecordingState.STOPPING &&
        this.videoState !== RecordingState.ERROR) {
        this.mAction.stopRecording();
        this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_STOP);
        this.endVideoAnim();
      }
      clearTimeout(this.nightImmersiveTimerId);
    }
  }

  private onChangeExtensionWindowEventType(data: Record<'windowEventType', window.WindowEventType>): void {
    if (data.windowEventType === window.WindowEventType.WINDOW_INACTIVE && this.videoState !== RecordingState.READY &&
      this.videoState !== RecordingState.STOPPING) {
      this.endVideoAnim();
      this.mAction.stopRecording();
      this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_STOP);
    }
  }

  private powerKeyDownDuration() {
    if (this.videoState !== RecordingState.READY && this.videoState !== RecordingState.STOPPING &&
      this.videoState !== RecordingState.ERROR) {
      HiLog.i(TAG, 'power key duration one second triggered recording to stop.');
      this.mAction.stopRecording();
      this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_STOP);
      this.endVideoAnim();
    }
  }

  /*
   * 相机适配非智能表遥控拍照
   */

  private remoteCaptureEvent(): void {
    if (this.isShowtimeLapse) {
      return;
    }
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    let isDown: boolean = false;
    if (AppStorage.get('isLemCollaps') ||
    this.isDuringSavePowerMode ||
    this.isProShutterCapture ||
      getStates().get<CameraRunningState>('cameraReducer', 'cameraRunningState') !== CameraRunningState.STARTED ||
      (!this.uiEnable && isDown)) {
      return;
    }
    if (this.currentButtonType === ShutterButtonType.NORMAL_CAPTURE || this.isShowCapture) {
      this.mAction.disableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.CAPTURE_BUTTON);
      this.photoShutterDownAnimate();
      this.shutterDownTime = Date.now();
      this.photoShutterDownCapture();
      this.photoProcess(isDown, false);
      if (!isDown) {
        this.handleClickDownCaptureWhenUp();
      }
    }
  }

  private onFunctionChange(data: ActionData): void {
  }

  private volumeKeyEventShutter(data: VolumeKeyPhotoData) {
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    if (this.isPicker && AppStorage.get('inPrivacyLearnMore')) {
      return;
    }
    let isDown: boolean = data.isDown;
    if (AppStorage.get('isLemCollaps') ||
    this.isDuringSavePowerMode ||
    this.isProShutterCapture ||
      getStates().get<CameraRunningState>('cameraReducer', 'cameraRunningState') !== CameraRunningState.STARTED ||
      (!this.uiEnable && isDown)) {
      return;
    }
    if (this.currentButtonType === ShutterButtonType.NORMAL_CAPTURE || this.isShowCapture) {
      this.photoProcess(isDown, false);
      if (!isDown) {
        this.handleClickDownCaptureWhenUp();
      }
    }
    if (this.isShowVideo) {
      this.videoProcess(isDown);
    }
  }

  private onPickerReCapture(data: ActionData): void {
    // picker一次只允许拍一张
    if (!data['showPicker']) {
      this.singleStagePhotoCaptured = false;
    }
  }

  private onStatePaused(event: string): void {
    HiLog.i(TAG, `${event} event triggered. Video state is ${this.videoState}`);
    if (this.videoState !== RecordingState.READY &&
      this.videoState !== RecordingState.STOPPING &&
      this.videoState !== RecordingState.ERROR) {
      HiLog.i(TAG, `${event} triggered video stopped. `);
      this.mAction.stopRecording();
      this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_STOP);
      this.endVideoAnim();
      return;
    }
    if (this.isShowtimeLapse) {
      this.endVideoAnim();
    }
  }

  private onVideoError(data: VideoErrorData) {
    HiLog.i(TAG, `onVideoError  errorCode : ${data.code} errorMsg : ${data.msg}`);
    this.mAction.stopRecording();
    this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_STOP);
  }

  private resetLongExposureState() {
    HiLog.i(TAG, 'resetLongExposureState');
    this.isShowLongExposure = false;
    this.isShowLoading = false;
    this.isShowCountDown = false;
    this.shouldExitLongExposure = false;
    this.loadingCaptureFirstFinish = false;
    this.mCountDownBtnDuration = 0;
    this.captureBtnWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
    this.captureBtnRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
    this.resetPhotoInnerBtn();
  }

  private initMode() {
    const buttonType: ShutterButtonType = this.getNewButtonType();
    HiLog.i(TAG, `buttonType: ${buttonType}.`);
    this.isFrameStarted = getStates().get<boolean>('cameraReducer', 'isFrameStarted');
    this.isTimeLapseVideoRecording = false;
    this.getAppearAnim(buttonType)(true);
    this.currentButtonType = buttonType;
  }

  private modeOnChange() {
    const buttonType: ShutterButtonType = this.getNewButtonType();
    HiLog.i(TAG, `new buttonType: ${buttonType},${this.currentButtonType}.`);
    if (this.currentButtonType === buttonType) { // started 起流结束在次刷新shutter样式,避免快切场景ui和模式不匹配
      return;
    }
    this.isFrameStarted = false;
    this.isTimeLapseVideoRecording = false;
    if (getStates().get<boolean>('uiReducer', 'isImmersive')) {
      this.mAction.isEnterImmersive(false);
    }
    this.changeAnim(this.currentButtonType, buttonType);
  }

  private changeAnim(currentButtonType: ShutterButtonType, buttonType: ShutterButtonType) {
    switch (currentButtonType) {
      case ShutterButtonType.NULL:
        this.getAppearAnim(buttonType)(true);
        this.currentButtonType = buttonType;
        break;
      case ShutterButtonType.NORMAL_CAPTURE:
        this.photoBtnDisAppearAnim(this.getAppearAnim(buttonType), buttonType);
        break;
      case ShutterButtonType.NORMAL_VIDEO:
        this.videoBtnDisAppearAnim(this.getAppearAnim(buttonType), buttonType);
        break;
    }
  }

  private videoStateOnChange() {
    HiLog.i(TAG, `videoStateOnChange videoState:${this.videoState}.`);
    if (this.videoState === RecordingState.STOPPING) {
      this.isTimeLapseVideoRecording = true;
      this.endVideoAnim();
      if (this.isPicker) {
        const windowState: window.WindowStageEventType =
          AppStorage.get('windowStageEventType') ?? window.WindowStageEventType.SHOWN;
        HiLog.i(TAG, `windowState is ${windowState}`);
        if (windowState === window.WindowStageEventType.HIDDEN) {
          return;
        }
        StoreManager.getInstance().postMessage(PickerAction.showPickerView());
      }
    } else {
      this.isTimeLapseVideoRecording = false;
    }
  }

  private getAppearAnim(buttonType: ShutterButtonType): Function {
    HiLog.i(TAG, `getAppearAnim mode: ${this.mode}, buttonType: ${buttonType}.`);
    if (buttonType === ShutterButtonType.NORMAL_VIDEO) {
      return (): void => this.videoBtnAppearAnim();
    }
    return (): void => this.photoBtnAppearAnim();
  }

  private photoBtnAppearAnim() {
    this.isShowCapture = true;
  }

  private photoBtnDisAppearAnim(appearAnim: Function, buttonType: ShutterButtonType) {
    this.currentButtonType = buttonType;
    setTimeout(() => {
      appearAnim();
      this.isShowCapture = false;
    }, SHUTTER_ANIMATE_DELAY);
  }

  private videoBtnAppearAnim(disableAnim?: boolean) {
    this.isShowVideo = true;
    if (disableAnim) {
      return;
    }
    this.videoBtn2Scale = { x: 0.5, y: 0.5 };
    this.videoBtn2Opacity = 0;
    animateToImmediately({
      duration: 100,
      curve: Curve.Sharp
    }, () => {
      this.videoBtn2Scale = { x: 1, y: 1 };
      this.videoBtn2Opacity = 1;
    });
  }

  private videoBtnDisAppearAnim(appearAnim: Function, buttonType: ShutterButtonType) {
    this.videoBtn2Scale = { x: 1, y: 1 };
    this.videoBtn2Opacity = 1;
    let prevButtonType = this.currentButtonType;
    this.currentButtonType = buttonType;
    animateToImmediately({
      duration: 100,
      curve: Curve.Sharp,
      onFinish: () => {
        this.isShowVideo = false;
        appearAnim();
      }
    }, () => {
      this.videoBtn2Scale = { x: 0.5, y: 0.5 };
      this.videoBtn2Opacity = 0;
    });
  }

  private timeLapseBtnAppearAnim(disableAnim?: boolean) {
    this.isShowVideo = true;
    this.isShowNight = true;
    if (disableAnim) {
      return;
    }
    this.videoBtn2Scale = { x: 0.5, y: 0.5 };
    this.videoBtn2Opacity = 0;
    animateToImmediately(
      {
        duration: 100,
        curve: Curve.Sharp
      },
      () => {
        this.videoBtn2Scale = { x: 1, y: 1 };
        this.videoBtn2Opacity = 1;
      });
  }

  private timeLapseBtnDisAppearAnim(appearAnim: Function, buttonType: ShutterButtonType) {
    this.videoBtn2Scale = { x: 1, y: 1 };
    this.videoBtn2Opacity = 1;
    this.currentButtonType = buttonType;
    animateToImmediately({
      duration: 100,
      curve: Curve.Sharp,
      onFinish: () => {
        this.isShowVideo = false;
        this.isShowNight = false;
        appearAnim();
      }
    }, () => {
      this.videoBtn2Scale = { x: 0.5, y: 0.5 };
      this.videoBtn2Opacity = 0;
    });
  }

  private confirmCapture() {
    let cancelConfirmCapture: boolean = this.confirmCaptureState || !this.nightStartCaptureState;
    HiLog.i(TAG, 'confirmCapture. cancelConfirmCapture:' + cancelConfirmCapture);
    if (cancelConfirmCapture) {
      return;
    }
    this.clearTimer();
    this.endNightSmallAnim();
    this.mAction.isClearExposureTime();
    this.confirmCaptureState = true;
    if (this.isDelaySendCaptureEnd) {
      this.mAction.captureEnd();
      this.isDelaySendCaptureEnd = false;
    }
  }

  private captureEnd() {
    HiLog.i(TAG, 'captureEnd E. ');
    if (!this.confirmCaptureState) {
      return;
    }
    this.isDelaySendCaptureEnd = false;
    this.nightCaptureFirstFinish = false;
    this.nightShutterStatus = false;
    this.nightStartCaptureState = false;
    this.confirmCaptureState = false;
    const timerLapse: number = FeatureManager.getInstance().getFunction(FunctionId.TIME_LAPSE)?.getValue() as number;
    this.mAction.isEnterImmersive(false);
    if (timerLapse && timerLapse === SettingFuncDialogItemIndex.INDEX_FIF && !this.isBackground) {
    }
    HiLog.i(TAG, 'captureEnd X. ');
  }

  private delaySendCaptureEnd() {
    HiLog.i(TAG, 'delaySendCaptureEnd. ');
    this.isDelaySendCaptureEnd = true;
  }

  private onBackground() {
    this.isBackground = true;
    this.audioControlShutterStatus = true;
    if (this.isShutterButtonLongClick) {
      this.forceClickUp();
    }
    if (this.isShowLongExposure) {
      this.exitLongExposure();
    }
    this.mHasClickDownCapture = false;
    this.mWaitingThumbnailAnimation = false;
    this.buttonStatusReset();
    this.isTakePhoto = false;
    this.isTimeLapseVideoRecording = false;
  }

  private onForeground() {
    if (getStates().get<boolean>('uiReducer', 'isImmersive')) {
      this.mAction.isEnterImmersive(false);
    }
  }

  private onVdeCollapsed(data: ActionData) {
    if (!data['isVdeCollapsed']) {
      return;
    }
    HiLog.i(TAG, 'is onCollapsStatusChanged E.');
    this.onBackground();
    HiLog.i(TAG, 'is onCollapsStatusChanged X.');
  }

  private buttonStatusReset(): void {
    this.captureBtnWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
    this.captureBtnRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
    this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    this.videoWidth = this.isVdeCollapsed ? AnimSpecifications.VDE_ANIM_VIDEO_BUTTON_WIDTH_END :
      AnimSpecifications.ANIM_VIDEO_BUTTON_WIDTH_END;
    this.videoRadius = AnimSpecifications.ANIM_VIDEO_BUTTON_RADIUS_END;
    this.videoColor = AnimSpecifications.ANIM_VIDEO_BUTTON_COLOR_END;
    this.videoBtn2Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    this.nightWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
    this.nightRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
  }

  private isSupportMultiCaptureEffect(captureDuration: number): boolean {
    HiLog.d(TAG, `support IsSupportedEffectWhenNotEnableCapture ${CameraAppCapability.getInstance()
      .getIsSupportedEffectWhenNotEnableCapture()}`);
    return captureDuration !== INVALID_CAPTURE_DURATION && ((this.mode === ModeType.PHOTO) &&
      this.cameraPosition === camera.CameraPosition.CAMERA_POSITION_BACK) && this.isPicker === false;
  }

  private startLoadingBtnAnimation() {
    HiLog.i(TAG, 'startLoadingBtnAnimation');
    this.isShowLoading = true;
    this.loadingCaptureFirstFinish = false;
    this.startLoadingInnerBtnAnimation();
  }

  private stopLoadingBtnAnimation() {
    HiLog.i(TAG, 'stopLoadingBtnAnimation');
    if (this.mCountDownBtnDuration < MIN_COUNTER_DOWN_MODE_DURATION) {
      VibratorService.getInstance().triggerVibrator(VibratorService.LONG_EXPOSURE_CAPTURE);
      this.mEventBus.emit(ActionType.ACTION_CAPTURE_EFFECT, []);
    }

    this.exitLongExposure();
  }

  private exitLongExposure() {
    HiLog.i(TAG, 'stopLoadingBtnAnimation');
    this.resetLongExposureState();
    this.mAction.isEnterImmersive(false);
    this.mAction.longExposureShutterEnd();
  }

  private onFrameShutterEnd() {
    HiLog.i(TAG, `on Frame Shutter End.${this.mHasClickDownCapture}`);
    this.isTakePhoto = false;
    if (this.mHasClickDownCapture) {
      HiLog.i(TAG, 'button down Interrupt ThumbnailAnimation');
      this.mWaitingThumbnailAnimation = true;
    } else {
      CameraProxy.getInstance().attemptPlayThumbnailAnimation();
    }

    if (!this.isShowLongExposure) {
      return;
    }

    if (this.isShowCountDown) {
      HiLog.i(TAG, 'shouldExitLongExposure');
      this.shouldExitLongExposure = true;
      return;
    }

    if (this.isShowLoading) {
      this.stopLoadingBtnAnimation();
    }
  }

  private startCountDownInnerBtnAnimation() {
    HiLog.i(TAG, 'startCountDownInnerBtnAnimation');
    animateToImmediately(
      {
        duration: 175,
        curve: Curves.cubicBezierCurve(0.4, 0, 0.2, 1.0),
      },
      () => {
        this.captureBtnWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_START;
        this.captureBtnRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_START;
        this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
      })
  }

  private endCountDownInnerBtnAnimation() {
    HiLog.i(TAG, 'endCountDownInnerBtnAnimation');
    animateToImmediately(
      {
        duration: 150,
        curve: Curves.cubicBezierCurve(0.4, 0, 0.2, 1.0)
      },
      () => {
        this.captureBtnWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
        this.captureBtnRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
        this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
        this.audioCaptureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
      })
  }

  private resetPhotoInnerBtn() {
    this.captureBtnWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
    this.captureBtnRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
    this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    this.audioCaptureBtnVisibility = Visibility.Visible;
  }

  private startLoadingInnerBtnAnimation() {
    HiLog.i(TAG, 'startLoadingInnerBtnAnimation');
    animateToImmediately(
      {
        duration: 175,
        curve: Curves.cubicBezierCurve(0.4, 0, 0.2, 1.0),
      },
      () => {
        this.captureBtnWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
        this.captureBtnRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
        this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
      })
  }

  private middleNightSmallAnim() {
    HiLog.i(TAG, 'play middleNightSmallAnim. ');
    this.nightWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
    this.nightBtn2Scale = AnimSpecifications.ANIM_NIGHT_BUTTON_SCALE_UP;
    this.audioCaptureBtnScale = AnimSpecifications.ANIM_NIGHT_BUTTON_SCALE_UP;
    animateToImmediately(
      {
        duration: 125,
        curve: Curves.cubicBezierCurve(0.4, 0, 0.2, 1.0),
      },
      () => {
        this.nightWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_MIDDLE;
        this.nightBtn2Scale = AnimSpecifications.ANIM_NIGHT_BUTTON_SCALE_DOWN;
        this.audioCaptureBtnScale = AnimSpecifications.ANIM_AUDIO_CONTROL_CAPTURE_BUTTON_SCALE_DOWN;
      })
  }

  private endNightSmallAnim() {
    HiLog.i(TAG, 'play endNightAnim. ');
    this.nightWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_START;
    this.nightRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_START;
    this.nightBtn2Scale = AnimSpecifications.ANIM_NIGHT_BUTTON_TWO_SCALE_DOWN;
    this.nightColor = AnimSpecifications.ANIM_NIGHT_BUTTON_COLOR_END;
    animateToImmediately(
      {
        duration: 150,
        curve: Curves.cubicBezierCurve(0.4, 0, 0.2, 1.0)
      },
      () => {
        // shape C-B
        this.nightWidth = AnimSpecifications.ANIM_NIGHT_BUTTON_WIDTH_END;
        this.nightRadius = AnimSpecifications.ANIM_NIGHT_BUTTON_RADIUS_END;
        this.nightColor = AnimSpecifications.ANIM_NIGHT_BUTTON_COLOR_MIDDLE;
        // A scale 0-1
        this.nightBtn2Scale = AnimSpecifications.ANIM_NIGHT_BUTTON_SCALE_UP;
        this.audioCaptureBtnScale = AnimSpecifications.ANIM_NIGHT_BUTTON_SCALE_UP;
        // 流光快门/高像素/夜景模式快门动效结束之后,声控开启状态下将按钮重置为声控拍照样式
        if (!this.nightShutterStatus &&
          (this.audioControlType === SettingFuncDialogItemIndex.INDEX_SEC ||
            this.audioControlType === SettingFuncDialogItemIndex.INDEX_THR)) {
          this.audioControlShutterStatus = true;
        }
      })
  }

  private timeLapseEnd(data: ActionData) {
    HiLog.i(TAG, `timeLapseEnd mode:${this.mode}.`);
    // 录像模式
    if (this.mode === ModeType.VIDEO) {
      // 录像模式倒计时被打断按钮恢复
      this.resetVideoBtnScale(data);
    } else {
      CaptureService.getInstance().onCaptureReady();
    }
  }

  private resetVideoBtnScale(data: ActionData) {
    if (!this.isShowtimeLapse && data['timeLapseInterrupt']) {
      this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    }
  }

  private photoAudioControlShutterDownAnimate(): void {
    this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    this.audioCaptureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    animateToImmediately({
      curve: Curve.Sharp,
      duration: 125,
      onFinish: () => {
        this.photoAudioControlShutterUpAnimate();
      }
    }, () => {
      this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_DOWN;
      this.audioCaptureBtnScale = AnimSpecifications.ANIM_AUDIO_CONTROL_CAPTURE_BUTTON_SCALE_DOWN;
    });
  }

  private photoAudioControlShutterUpAnimate(): void {
    this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_DOWN;
    this.audioCaptureBtnScale = AnimSpecifications.ANIM_AUDIO_CONTROL_CAPTURE_BUTTON_SCALE_DOWN;
    animateToImmediately({
      curve: Curve.Sharp,
      duration: 125,
      onFinish: () => {
        if (!this.isProShutterCapture) {
          this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
        }
      }
    }, () => {
      this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
      this.audioCaptureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    });
  }

  private photoShutterDownAnimate(): void {
    HiLog.i(TAG, 'photoShutterDownAnimate animation begin');
    animateToImmediately({
      curve: AnimSpecifications.ANIM_CAPTURE_CURVE,
      onFinish: () => {
        HiLog.i(TAG, 'photoShutterDownAnimate animation Finish');
      }
    }, () => {
      this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_DOWN;
      this.audioCaptureBtnScale = AnimSpecifications.ANIM_AUDIO_CONTROL_CAPTURE_BUTTON_SCALE_DOWN;
    })
  }

  private photoShutterUpAnimate(): void {
    HiLog.i(TAG, 'photoShutterUpAnimate animation begin');
    animateToImmediately({
      curve: AnimSpecifications.ANIM_CAPTURE_CURVE,
      onFinish: () => {
        HiLog.i(TAG, 'photoShutterUpAnimate animation Finish');
      }
    }, () => {
      this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
      this.audioCaptureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    })
  }

  private onVideoButtonDown(): void {
    HiLog.i(TAG, 'onVideoButtonDown animation begin');
    this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    animateToImmediately({
      curve: AnimSpecifications.ANIM_VIDEO_CURVE
    }, () => {
      this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_1_SCALE_DOWN;
    })
  }

  private onVideoButtonUpCancel(): void {
    HiLog.i(TAG, 'onVideoButtonUpCancel animation begin');
    this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_1_SCALE_DOWN;
    animateToImmediately({
      curve: AnimSpecifications.ANIM_VIDEO_CURVE
    }, () => {
      this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    })
  }

  private startVideoAnim() {
    HiLog.i(TAG, 'startVideoAnim');
    this.videoWidth = this.isVdeCollapsed ? AnimSpecifications.VDE_ANIM_VIDEO_BUTTON_WIDTH_END :
      AnimSpecifications.ANIM_VIDEO_BUTTON_WIDTH_END;
    this.videoRadius = AnimSpecifications.ANIM_VIDEO_BUTTON_RADIUS_END;
    this.videoColor = AnimSpecifications.ANIM_VIDEO_BUTTON_COLOR_END;
    this.videoBtn2Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_1_SCALE_DOWN;
    animateToImmediately({
      curve: AnimSpecifications.ANIM_VIDEO_CURVE
    }, () => {
      // shape B-C
      this.videoWidth = this.isVdeCollapsed ? AnimSpecifications.VDE_ANIM_VIDEO_BUTTON_WIDTH_START :
        AnimSpecifications.ANIM_VIDEO_BUTTON_WIDTH_START;
      this.videoRadius = AnimSpecifications.ANIM_VIDEO_BUTTON_RADIUS_START;
      this.videoColor = AnimSpecifications.ANIM_VIDEO_BUTTON_COLOR_START;
      // A scale 1-0
      this.videoBtn2Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_2_SCALE_DOWN;
      // total scale 0.9-1
      this.videoBtn1Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    })
  }

  private endVideoAnim() {
    HiLog.i(TAG, 'endVideoAnim');
    this.videoWidth = this.isVdeCollapsed ? AnimSpecifications.VDE_ANIM_VIDEO_BUTTON_WIDTH_START :
      AnimSpecifications.ANIM_VIDEO_BUTTON_WIDTH_START;
    this.videoRadius = AnimSpecifications.ANIM_VIDEO_BUTTON_RADIUS_START;
    this.videoColor = AnimSpecifications.ANIM_VIDEO_BUTTON_COLOR_START;
    this.videoBtn2Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_2_SCALE_DOWN;
    animateToImmediately({
      curve: AnimSpecifications.ANIM_VIDEO_CURVE
    }, () => {
      // shape C-B
      this.videoWidth = this.isVdeCollapsed ? AnimSpecifications.VDE_ANIM_VIDEO_BUTTON_WIDTH_END :
        AnimSpecifications.ANIM_VIDEO_BUTTON_WIDTH_END;
      this.videoRadius = AnimSpecifications.ANIM_VIDEO_BUTTON_RADIUS_END;
      this.videoColor = AnimSpecifications.ANIM_VIDEO_BUTTON_COLOR_END;
      // A scale 0-1
      this.videoBtn2Scale = AnimSpecifications.ANIM_VIDEO_BUTTON_SCALE_UP;
    })
  }

  private isEnterImmersive(data: EnterImmersiveData): void {
    HiLog.i(TAG, `isEnterImmersive isImmersive: ${data.isImmersive}.`);
    let timer: number = Number.NaN;
    if (!data.isImmersive) {
      timer = setTimeout(() => {
        HiLog.i(TAG, 'canAudioShutter is true');
      }, CAN_AUDIO_SHUTTER_DELAY);
    } else {
      clearTimeout(timer);
    }
  }

  private audioControlShutterButton(data: PickerData) {
    if (!this.uiEnable || data.isPicker !== this.isPicker || this.isProShutterCapture) {
      HiLog.i(TAG, 'audio Control Shutter return.');
      return;
    }
    if (!this.isCaptureEnabled()) {
      return;
    }
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    if ((this.isShowCapture ||
      this.currentButtonType === ShutterButtonType.NORMAL_CAPTURE)) {
      this.mAction.disableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      this.photoAudioControlShutterDownAnimate();
      if (this.shouldPlayCaptureEffectWhenClick(this.estimatedCaptureDuration)) {
        HiLog.i(TAG, 'play capture effect when up');
        this.mEventBus.emit(ActionType.ACTION_CAPTURE_EFFECT, []);
      }
      this.photoShutterUpCapture();
      return;
    }
    if (this.currentButtonType === ShutterButtonType.SECOND_CAPTURE) {
      this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      if (!this.nightShutterStatus && !this.confirmCaptureState) {
      } else if (this.nightShutterStatus && !this.confirmCaptureState) {
        this.clearTimer();
        HiLog.i(TAG, 'audioControlShutterButton confirmCapture');
        this.confirmCapture();
        this.mAction.confirmCapture();
      }
    }
  }

  private clickFloatingShutterButton(data: PickerData) {
    if ((!this.uiEnable && !this.nightShutterStatus) || data.isPicker !== this.isPicker) {
      HiLog.i(TAG, 'Floating Shutter return.');
      return;
    }
    HiLog.i(TAG, `onFloatingShutterButtonClick takeCapture isPicker: ${data.isPicker}.`);
    if (!this.isCaptureEnabled() &&
      !(this.nightShutterStatus && !this.confirmCaptureState)) {
      HiLog.i(TAG, `captureReadyis not end`);
      return;
    }
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    const isPlayDownAnimate = this.isShowCapture ||
      (this.currentButtonType === ShutterButtonType.NORMAL_CAPTURE && !this.isShowLongExposure);
    if (isPlayDownAnimate) {
      this.photoShutterDownAnimate();
      if (this.shouldPlayCaptureEffectWhenClick(this.estimatedCaptureDuration)) {
        HiLog.i(TAG, 'play capture effect when up');
        this.mEventBus.emit(ActionType.ACTION_CAPTURE_EFFECT, []);
      }
      if (this.mHasClickDownCapture) {
        this.mHasClickDownCapture = false;
      }
      this.photoShutterUpCapture();
      setTimeout((): void => {
        this.photoShutterUpAnimate();
      }, CAPTURE_DELAY * 5);
      return;
    }
    if (this.isShowVideo) {
      if (this.videoState === RecordingState.READY) {
        this.onVideoButtonDown();
      }
      this.videoInnerBtnTouchUp();
    }
    if (this.currentButtonType === ShutterButtonType.SECOND_CAPTURE) {
      this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      if (!this.nightShutterStatus && !this.confirmCaptureState) {
      } else if (this.nightShutterStatus && !this.confirmCaptureState) {
        this.clearTimer();
        HiLog.i(TAG, 'clickFloatingShutterButton confirmCapture');
        this.confirmCapture();
        this.mAction.confirmCapture();
      }
    }
    HiLog.i(TAG, 'onFloatingShutterButtonClick end');
  }

  private onCollaborateControlCapture(): void {
    if (getStates().get<CameraRunningState>('cameraReducer', 'cameraRunningState') !== CameraRunningState.STARTING ||
      !this.uiEnable) {
      return;
    }
    HiLog.begin(TAG, 'onCollaborateControlCapture')
    if (this.currentButtonType === ShutterButtonType.NORMAL_CAPTURE || this.isShowCapture) {
      // 遥控拍照,模拟触摸事件,按下50ms后抬起,仅普通拍照模式
      this.photoProcess(true, false);
      setTimeout((): void => {
        this.photoProcess(false, false);
        this.handleClickDownCaptureWhenUp();
      }, CAPTURE_DELAY * 5)
    }
    HiLog.end(TAG, 'onCollaborateControlCapture')
  }

  private onCollaborateControlVideo(): void {
    if (AppStorage.get('isLemCollaps') ||
    this.isDuringSavePowerMode ||
    this.isProShutterCapture ||
      getStates().get<CameraRunningState>('cameraReducer', 'cameraRunningState') !== CameraRunningState.STARTED ||
      !this.uiEnable) {
      return;
    }
    HiLog.begin(TAG, 'onCollaborateControlVideo');
    // 遥控拍照,模拟触摸事件,按下50ms后抬起,仅普通录像模式
    if (this.isShowVideo) {
      // 遥控拍照,模拟触摸事件,按下50ms后抬起,仅普通录像模式
      if (this.currentButtonType === ShutterButtonType.NORMAL_VIDEO) {
        this.videoProcess(true);
        setTimeout((): void => {
          this.videoProcess(false);
        }, CAPTURE_DELAY * 5);
      }
    }
    HiLog.end(TAG, 'onCollaborateControlVideo');
  }

  private photoShutterUpCapture(): void {
    HiLog.i(TAG, 'up button capture.');
    if (!this.isFrameStarted) {
      return;
    }
    const currentCaptureDuration = this.estimatedCaptureDuration;
    const timeLapse: number = FeatureManager.getInstance().getFunction(FunctionId.TIME_LAPSE)?.getValue();
    const timedShot: number = FeatureManager.getInstance().getFunction(FunctionId.TIMED_SHOT)?.getValue();
    const timeLapseType: boolean = !timeLapse || timeLapse <= SettingFuncDialogItemIndex.INDEX_FIR;
    const timeShotType: boolean = !timedShot || timedShot <= SettingFuncDialogItemIndex.INDEX_FIR;
    HiLog.i(TAG,
      `timeLapse: ${timeLapse}, timedShot: ${timedShot}, timeLapseType: ${timeLapseType}, timeShotType: ${timeShotType}`);
    if ((timeLapseType && timeShotType) ||
      (timeLapse && this.videoState !== RecordingState.READY)) {
      HiLog.i(TAG, 'up capture called.');
      this.playCaptureEffectWhenCapture(currentCaptureDuration);
      this.mAction.capture();
      this.singleStagePhotoCaptured = this.isPicker ? true : this.singleStagePhotoCaptured;
      CaptureService.getInstance().clearRichCaptureNext();
      this.mAction.changeFunctionValue(FunctionId.CAPTURE, true);
    }

    const timerLapseType: boolean = !!timeLapse && timeLapse > SettingFuncDialogItemIndex.INDEX_FIR;
    if (timerLapseType) {
      HiLog.i(TAG, 'up capture changeTimeLapse called.');
      CaptureService.getInstance().clearRichCaptureNext();
      this.mAction.changeTimeLapse(true);
      return;
    }

    HiLog.i(TAG, 'up capture end.');
  }

  private shouldPlayCaptureEffectWhenClick(captureDuration: number) {
    const timerLapse: number = FeatureManager.getInstance().getFunction(FunctionId.TIME_LAPSE)?.getValue();
    const timedShot: number = FeatureManager.getInstance().getFunction(FunctionId.TIMED_SHOT)?.getValue();
    if (timerLapse && timerLapse > SettingFuncDialogItemIndex.INDEX_FIR) {
      return false;
    }

    const result: boolean =
      (this.isSupportMultiCaptureEffect(captureDuration)) &&
        captureDuration <= MAX_CLICK_MODE_DURATION;
    HiLog.i(TAG, `play capture effect without waiting: ${result}`);
    return result;
  }

  private playCaptureEffectWhenCapture(currentCaptureDuration: number) {
    if (this.isFlashOn()) {
      return;
    }

    if (this.videoState !== RecordingState.READY) {
      this.mEventBus.emit(ActionType.ACTION_CAPTURE_EFFECT, []);
      return;
    }

    if (!this.isSupportMultiCaptureEffect(currentCaptureDuration)) {
      HiLog.i(TAG, 'play capture effect when capture');
      this.mEventBus.emit(ActionType.ACTION_CAPTURE_EFFECT, []);
      return;
    }

    if (currentCaptureDuration > MAX_CLICK_MODE_DURATION && !this.mHasClickDownCapture) {
      HiLog.i(TAG, 'play capture effect when capture');
    }
  }

  private playLongExposureAfterTimeLapse() {
    HiLog.i(TAG, 'play long exposure after timeLapse');
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    const currentCaptureDuration = this.estimatedCaptureDuration;
    this.playCaptureEffectWhenCapture(currentCaptureDuration);
    this.mAction.capture();
    this.mAction.changeFunctionValue(FunctionId.CAPTURE, true);
  }

  private isFlashSteady(): boolean {
    const flashStatus: number = FeatureManager.getInstance().getFunction(FunctionId.FLASH).getValue();
    let isFlashSteady = !(flashStatus === FlashMode.ON || flashStatus === FlashMode.AUTO);
    HiLog.i(TAG, `isFlashSteady: ${isFlashSteady}.`);
    return isFlashSteady
  }

  private isFlashOn(): boolean {
    const flashStatus: number = FeatureManager.getInstance().getFunction(FunctionId.FLASH).getValue();
    HiLog.i(TAG, `isFlashOn flashStatus: ${flashStatus}.`);
    return flashStatus === FlashMode.ON;
  }

  private photoShutterDownCapture(): void {
    if (!this.isClickDownCaptureEnabled() && this.mode !== ModeType.VIDEO) {
      HiLog.w(TAG, `capture loop interrupt ${this.mode.toString()}E.`);
      return;
    }
    this.mHasClickDownCapture = true;
    const currentCaptureDuration = this.estimatedCaptureDuration;
    if (currentCaptureDuration >= MIN_LOADING_MODE_DURATION) {
      this.mIsLongCaptureWaitingClickUp = true;
    }
    HiLog.i(TAG, 'down button capture.' + this.estimatedCaptureDuration);
    CaptureService.getInstance().clearRichCaptureNext();
    this.mAction.changeFunctionValue(FunctionId.CAPTURE, CaptureScene.SHUTTER_DOWN_CAPTURE);
    this.mAction.capture();
  }

  private longClickUpdate(isDown: boolean): void {
    HiLog.i(TAG, `longClickUpdate ${isDown}`);
    if (isDown) {
      if (this.timeoutID) {
        clearTimeout(this.timeoutID);
      }
      this.timeoutID = setTimeout(() => {
        this.mAction.longClickStatusChange(true);
        this.doShutterLongClickShrinkAnimation();
        VibratorService.getInstance().triggerVibrator(VibratorService.CAMERA_LONG_PRESS_ID);
        this.touchEvent = this.currentTouchEvent;
        this.timeoutID = 0;
      }, AnimSpecifications.ANIM_DURATION_LR_LONG_CLICK);
    } else {
      this.touchEvent = null;
      if (this.timeoutID) {
        clearTimeout(this.timeoutID);
      }
      this.mAction.longClickStatusChange(false);
    }
  }

  private doShutterLongClickShrinkAnimation(): void {
    this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_LR_SWIPE;
    this.invisibleTimeout = setTimeout(() => {
      this.shutterAllVisibility = Visibility.None;
    }, AnimSpecifications.ANIM_DELAY_150);
  }

  private doShutterExpandAnimation(): void {
    clearTimeout(this.invisibleTimeout);
    this.shutterAllVisibility = Visibility.Visible;
    animateToImmediately({
      curve: AnimSpecifications.ANIM_FOLLOW_HAND_CIRCLE_SCALE_UP_CURVE
    }, () => {
      this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    })
  }

  private forceClickUp(): void {
    HiLog.i(TAG, 'exit longClick by force');
    this.mAction.longClickStatusChange(false);
    this.handleClickDownCaptureWhenUp();
    // 上滑动效消失兜底方案
    this.captureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
    this.audioCaptureBtnScale = AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP;
  }

  private forceClickUpRecord(): void {
    HiLog.i(TAG, 'exit longClick by force');
    this.doShutterExpandAnimation();
    setTimeout(() => {
      this.handleClickDownCaptureWhenUp();
      this.mAction.longClickStatusChange(false);
    }, RECORD_UP_DELAY)
  }

  private isClickDownCaptureEnabled(): boolean {
    if (!CLICK_DOWN_CAPTURE_SUPPORT_MODE.includes(this.mode)) {
      return false;
    }

    if (this.isPicker) {
      return false;
    }

    if (!DeviceInfo.isPhone()) {
      return false;
    }

    if (!this.isCaptureEnabled()) {
      return false;
    }

    if (!this.isFlashSteady()) {
      return false;
    }

    if (this.estimatedCaptureDuration >= MIN_LOADING_MODE_DURATION) {
      return false;
    }

    const timerLapse: number = FeatureManager.getInstance().getFunction(FunctionId.TIME_LAPSE)?.getValue();

    const timedShot: number = FeatureManager.getInstance().getFunction(FunctionId.TIMED_SHOT)?.getValue();
    if (timerLapse && timerLapse > SettingFuncDialogItemIndex.INDEX_FIR) {
      return false;
    }

    // 时间间隔
    if (timedShot && timedShot > SettingFuncDialogItemIndex.INDEX_FIR) {
      return false;
    }
    return true;
  }

  private checkRecordingConditions(): boolean {
    if (AppStorage.get('isRecordUnavailable')) {
      if (AppStorage.get('isBatterySOCStopping')) {
        AppStorage.setOrCreate<boolean>('isBatterySOCStopping', false);
        return true;
      } else {
        TipService.getInstance().showTip($r('app.string.battery_desc_unable'), TIP_DURING, true, null, undefined, true);
        HiLog.i(TAG, 'batterySOC is less than 2%');
        this.onVideoButtonUpCancel(); // 快门抬起
        return false;
      }
    }
    if (this.videoState === RecordingState.READY && !RecordController.getInstance().validateAudioAvailable()) {
      TipService.getInstance().showTip($r('app.string.no_record_remind'), TIP_DURING, true, null, undefined, true);
      this.onVideoButtonUpCancel(); // 快门抬起
      return false;
    }
    return true;
  }

  private videoInnerBtnTouchUp(): void {
    if (!this.checkRecordingConditions()) {
      HiLog.i(TAG, `videoInnerBtnTouchUp checkRecordingConditions fail.`);
      return;
    }
    if (this.videoState === RecordingState.READY) {
      PowerKeyService.getInstance().powerKeySubscribe();
      let timerLapse: number = FeatureManager.getInstance().getFunction(FunctionId.TIME_LAPSE)?.getValue();
      HiLog.i(TAG, `ShutterButton startRecording getValue: ${JSON.stringify(timerLapse)}.`);
      if (timerLapse && timerLapse > SettingFuncDialogItemIndex.INDEX_FIR) {
        HiLog.i(TAG, 'ShutterButton startRecording changeTimeLapse called.');
        this.mAction.changeTimeLapse(true);
      } else {
        HiLog.i(TAG, 'ShutterButton startRecording changeTimeLapse not called.');
        this.startVideoAnim();
        this.mAction.startRecording();
        this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_START);
        this.mAction.isShowExtendBarAndParamBar();
      }
    } else {
      HiLog.i(TAG, 'startRecording not ready.');
      PowerKeyService.getInstance().powerKeyUnsubscribe();
      this.mAction.stopRecording();
      this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_STOP);
      this.mAction.isShowExtendBarAndParamBar();
    }
  }

  private getAnimationDuration(): number {
    return AnimSpecifications.ANIM_DURATION_300;
  }

  private photoInnerBtnOnTouch(event: TouchEvent): void {
    this.currentTouchEvent = event;
    if (event.type === TouchType.Down) {
      this.mAction.isShowExtendBarAndParamBar();
      if (this.isFrameStarted) {
        this.longClickUpdate(true);
      }
      if (getStates().get<boolean>('leftRightSwipeReducer', 'isCancelClickDown')) {
      }
      VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_DOWN);
      this.photoProcess(true, false);
    }
    if (event.type === TouchType.Up) {
      let longClickStatusCache = this.isShutterButtonLongClick;
      if (!this.isShutterButtonLongClick) {
        // 进入沉浸式后,退出无闪黑等动效
        VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_UP);
        this.photoProcess(false, false);
      }
      this.handleClickDownCaptureWhenUp();
      this.longClickUpdate(false);
      if (longClickStatusCache) {
        this.photoShutterUpAnimate();
        this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      }
    }
    if (this.isShutterButtonLongClick && event.type === TouchType.Move) {
      this.touchEvent = event;
    }
  }

  private handleClickDownCaptureWhenUp(): void {
    if (this.mHasClickDownCapture && this.mWaitingThumbnailAnimation) {
      CameraProxy.getInstance().attemptPlayThumbnailAnimation();
      this.mWaitingThumbnailAnimation = false;
    }
    this.mHasClickDownCapture = false;
  }

  private needPlayClickUpCaptureEffect(isCached: boolean): boolean {
    if (this.isFlashOn()) {
      return false;
    }

    const currentCaptureDuration = this.estimatedCaptureDuration;
    HiLog.i(TAG, 'CaptureDuration when play click up capture effect: ' + currentCaptureDuration);
    if (currentCaptureDuration >= MIN_LOADING_MODE_DURATION) {
      return false;
    }

    if (this.mHasClickDownCapture) {
      HiLog.i(TAG, 'hasClickDownCapture: ' + this.mHasClickDownCapture);
      return true;
    }

    return !isCached && this.shouldPlayCaptureEffectWhenClick(currentCaptureDuration);
  }

  private isCaptureEnabled(report: boolean = true): boolean {
    const isStarted: boolean =
      getStates().get<CameraRunningState>('cameraReducer', 'cameraRunningState') === CameraRunningState.STARTED;
    if (!isStarted) {
      HiLog.i(TAG, 'camera status is not started.');
      return false;
    }

    if (!this.mCaptureService.isEnableCapture(report) || ThumbnailService.getInstance().isPictureAcquireOrStoreTimeOut()) {
      HiLog.i(TAG, 'camera is not ready or wait save photo.');
      return false;
    }

    if (this.isShowLoading || this.isShowCountDown) {
      HiLog.i(TAG, 'is BtnAnimation');
      return false;
    }
    return true;
  }

  private photoProcess(isDown: boolean, isCacheTriggered: boolean): void {
    this.isShowActionMenu = false;
    if (!this.isFrameStarted) {
      if (this.captureBtnScale !== AnimSpecifications.ANIM_CAPTURE_BUTTON_SCALE_UP) {
        this.doShutterExpandAnimation();
      }
      if (!this.uiEnable && this.excludeComponent === UIOperationType.CAPTURE_BUTTON) {
        this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      }
      HiLog.e(TAG, 'photoProcess,frame not start');
      return;
    }
    HiLog.i(TAG, `isDown: ${isDown}, isCacheTriggered: ${isCacheTriggered}.`);
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    if (isDown) {
      this.mAction.disableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.CAPTURE_BUTTON);
      this.photoShutterDownAnimate();
      this.shutterDownTime = Date.now();
      this.photoShutterDownCapture();
    } else {
      CameraProxy.getInstance().sendShutterButtonUp(Date.now() - this.shutterDownTime);
      this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      if (this.mIsLongCaptureWaitingClickUp) {
        HiLog.i(TAG, 'ignore click up because long exposure');
        this.mIsLongCaptureWaitingClickUp = false;
        return;
      }

      if (this.needPlayClickUpCaptureEffect(isCacheTriggered)) {
        HiLog.i(TAG, 'play capture effect when click');
        this.mEventBus.emit(ActionType.ACTION_CAPTURE_EFFECT, []);
      }

      if (!isCacheTriggered) {
        this.photoShutterUpAnimate();
      }

      if (this.mHasClickDownCapture || !this.isCaptureEnabled(false)) {
        HiLog.i(TAG, 'ignore photo shutter up capture.');
        this.cacheRichCapture();
        return;
      }

      if (this.mCaptureService.isEnableCapture() && !this.mHasClickDownCapture &&
        !ThumbnailService.getInstance().isPictureAcquireOrStoreTimeOut()) {
        this.photoShutterUpCapture();
      }
    }
  }

  private cacheRichCapture() {
    if (this.mHasClickDownCapture) {
      return;
    }

    if (!this.isFlashSteady()) {
      return;
    }

    CaptureService.getInstance().cacheRichCaptureNext();
  }

  private nightProcess(isDown: boolean): void {
    if (MemoryService.getInstance().isFullStorage()) {
      return;
    }
    const isEnable = this.mCaptureService.isEnableCapture();
    if (!this.nightShutterStatus && !this.confirmCaptureState && isDown && !this.nightStartCaptureState && isEnable) {
      this.mAction.disableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NIGHT_SCENE_CAPTURE_BUTTON);
      this.middleNightSmallAnim();
    } else if (!this.nightShutterStatus && !this.confirmCaptureState && !isDown && isEnable) {
      this.mAction.hideThumbnailAndSwitchButton();
      this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
    } else if (this.nightShutterStatus && !this.confirmCaptureState && !isDown) {
      this.clearTimer();
      this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      HiLog.i(TAG, 'nightProcess confirmCapture');
      this.confirmCapture();
      this.mAction.confirmCapture();
    }
  }

  private videoProcess(isDown: boolean): void {
    if (!this.uiEnable && this.excludeComponent !== UIOperationType.RECORD_BUTTON) {
      return;
    }
    if (isDown) {
      this.mAction.disableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.RECORD_BUTTON);
      if (this.videoState === RecordingState.READY) {
        VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_DOWN);
        this.onVideoButtonDown();
      }
      return;
    }
    this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
    VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_UP);
    this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
    HiLog.i(TAG, `videoProcess videoInnerBtnTouchUp`)
    this.videoInnerBtnTouchUp();
  }

  private timeLapseVideoProcess(isDown: boolean): void {
    if (!this.uiEnable && this.excludeComponent !== UIOperationType.RECORD_BUTTON) {
      return;
    }
    if (isDown) {
      this.mAction.disableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.RECORD_BUTTON);
      if (this.videoState === RecordingState.READY) {
        VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_DOWN);
        this.onVideoButtonDown();
      }
      return;
    }
    this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
    VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_UP);
    this.videoInnerBtnTouchUp();
    let timerLapse: number = FeatureManager.getInstance().getFunction(FunctionId.TIME_LAPSE)?.getValue();
    let isNeedDelayChangeTimelapse = timerLapse && timerLapse > SettingFuncDialogItemIndex.INDEX_FIR &&
      this.videoState === RecordingState.READY;
  }

  private onSlowMoButtonChange(): void { // 慢动作:超慢&标慢切换帧率不需动效直接变更状态
    const buttonType: ShutterButtonType = this.getNewButtonType();
    HiLog.i(TAG, `currentButtonType: ${this.currentButtonType}, buttonType: ${buttonType}.`);
    this.currentButtonType = buttonType;
  }

  private getNewButtonType(): ShutterButtonType {
    const outputType: OutputType = OutputSwitcher.getInstance().getOutput();
    return ShutterController.getInstance().getButtonType(this.mode, outputType, this.cameraPosition);
  }

  private isInTouchTarget(event?: TouchEvent): boolean {
    if (!event || !event.touches || !event.target || !event.target.area) {
      return false;
    }
    for (let touchObject of event.touches) {
      if (touchObject.x >= 0 && touchObject.x <= event.target.area.width &&
        touchObject.y >= 0 && touchObject.y <= event.target.area.height) {
        return true;
      } else {
        HiLog.i(TAG, `out touchx: ${touchObject.x}, touchy: ${touchObject.y}`)
      }
    }
    HiLog.i(TAG, `confirm out target width: ${event.target.area.width}, height: ${event.target.area.height}}`)
    return false;
  }

  private getButtonColor(): string | Color {
    return Color.White;
  }

  @Builder
  normalOuterBtn() {
    // photo & video use the same
    Column()
      .width(this.isVdeCollapsed ? 52 : 64)
      .aspectRatio(1)
      .border({
        width: 2,
        color: this.getButtonColor(),
        radius: this.isShowSubScreenRadius ? 0 : 32,
        style: BorderStyle.Solid
      })
      .backgroundColor(this.shutterOutsideBackground)
      .key(ComponentIdKeys.SHUTTER_BUTTON_NORMAL_OUT_BTN)
  }

  @Builder
  countDownBtnStart() {
    Canvas(this.mLoopStartController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'countDownBtnStart onReady.');
        this.mLoopStartController.imageSmoothingEnabled = true;
        this.mLoopStartController.imageSmoothingQuality = 'medium';
        this.exposureStartAnimationItem?.destroy();
        this.exposureStartAnimationItem = lottie.loadAnimation({
          container: this.mLoopStartController,
          renderer: 'canvas',
          loop: false,
          autoplay: true,
          name: NIGHT_START_LOOP,
          path: NIGHT_EXPOSURE_PATH,
        })
        this.exposureStartAnimationItem.addEventListener('DOMLoaded', (args: Object): void => {
          HiLog.i(TAG, 'countDownBtnStart DownLoaded');
          let ssd: number | undefined = this.exposureStartAnimationItem?.getDuration();
          if (ssd === undefined) {
            return;
          }
          let speed: number = (1000 * ssd / this.mCountDownBtnDuration);
          this.exposureStartAnimationItem?.setSpeed(speed);
        })
      })
      .onDisAppear((): void => {
        // Canvas销毁时销毁lottie动画
        HiLog.i(TAG, 'countDownBtnStart onDisAppear.');
        if (this.exposureStartAnimationItem !== undefined) {
          lottie?.destroy(NIGHT_START_LOOP);
          this.exposureStartAnimationItem = undefined;
        }
      })
      .visibility(this.isShowCountDown ? Visibility.Visible : Visibility.Hidden)
  }

  @Builder
  loadingBtnFirst() {
    Canvas(this.mLoopCaptureFirstController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'loadingBtnFirst onReady.');
        this.mLoopCaptureFirstController.imageSmoothingEnabled = true;
        this.mLoopCaptureFirstController.imageSmoothingQuality = 'medium';
        this.captureStartFirstAnimationItem?.destroy();
        this.captureStartFirstAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureFirstController,
          renderer: 'canvas',
          loop: false,
          autoplay: true,
          name: NIGHT_CAPTURE_FIRST_LOOP,
          path: NIGHT_CAPTURE_FIRST_PATH,
        })
        this.captureStartFirstAnimationItem.addEventListener('complete', (args: Object): void => {
          if (!this.isShowLongExposure || !this.isShowLoading) {
            return;
          }
          HiLog.i(TAG, 'lottieLoadingFirst complete.');
          if (this.shouldExitLongExposure) {
            this.stopLoadingBtnAnimation();
          } else {
            this.loadingCaptureFirstFinish = true;
          }
        }); //动画播放结束且不再播放动画触发
      })
      .onDisAppear((): void => {
        HiLog.i(TAG, 'loadingBtnFirst disappear');
        if (this.captureStartFirstAnimationItem !== undefined) {
          HiLog.i(TAG, 'loadingBtnFirst onDisAppear.');
          lottie?.destroy(NIGHT_CAPTURE_FIRST_LOOP);
          this.captureStartFirstAnimationItem = undefined;
        }
      })
      .visibility((this.isShowLoading && !this.loadingCaptureFirstFinish) ? Visibility.Visible : Visibility.Hidden)
  }

  @Builder
  loadingBtnSecond() {
    Canvas(this.mLoopCaptureSecondController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'loadingBtnSecond onReady.');
        this.mLoopCaptureSecondController.imageSmoothingEnabled = true;
        this.mLoopCaptureSecondController.imageSmoothingQuality = 'medium';
        this.captureStartSecondAnimationItem?.destroy();
        this.captureStartSecondAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureSecondController,
          renderer: 'canvas',
          loop: true,
          autoplay: true,
          name: NIGHT_CAPTURE_SECOND_LOOP,
          path: NIGHT_CAPTURE_SECOND_PATH,
        })
      })
      .onDisAppear((): void => {
        if (this.captureStartSecondAnimationItem !== undefined) {
          HiLog.i(TAG, 'loadingBtnSecond onDisAppear.');
          lottie?.destroy(NIGHT_CAPTURE_SECOND_LOOP);
          this.captureStartSecondAnimationItem = undefined;
        }
      })
      .visibility(this.isLoadingBtnSecond() ? Visibility.Visible : Visibility.Hidden)
  }

  @Builder
  lottieCanvasLightPaintingStart() {
    Canvas(this.mLoopStartController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'lottieCanvasLightPaintingStart onReady.');
        this.mLoopStartController.imageSmoothingEnabled = true;
        this.mLoopStartController.imageSmoothingQuality = 'medium';
        this.exposureStartAnimationItem?.destroy();
        this.exposureStartAnimationItem = lottie.loadAnimation({
          container: this.mLoopStartController,
          renderer: 'canvas',
          loop: false,
          autoplay: true,
          name: LIGHT_PAINTING_CAPTURE_FIRST_LOOP,
          path: LIGHT_PAINTING_CAPTURE_PATH,
        })
        this.exposureStartAnimationItem.addEventListener('DOMLoaded', (args: Object): void => {
          HiLog.i(TAG, 'lottieCanvasLightPaintingStart DownLoaded');
          let ssd: number | undefined = this.exposureStartAnimationItem?.getDuration();
          if (ssd === undefined) {
            return;
          }
          let speed: number = (1000 * ssd / this.mCountDownBtnDuration);
          this.exposureStartAnimationItem?.setSpeed(speed);
        })
      })
      .onDisAppear((): void => {
        // Canvas销毁时销毁lottie动画
        HiLog.i(TAG, 'lottieCanvasLightPaintingStart onDisAppear.');
        if (this.exposureStartAnimationItem !== undefined) {
          lottie?.destroy(LIGHT_PAINTING_CAPTURE_FIRST_LOOP);
          this.exposureStartAnimationItem = undefined;
        }
      })
      .visibility(Visibility.Visible)
  }

  @Builder
  lottieCanvasLightPaintingCaptureStartFirst() {
    Canvas(this.mLoopCaptureFirstController)
      .width(64)
      .height(64)
      .onReady(() => {
        HiLog.i(TAG, 'lottieCanvasLightPaintingCaptureStartFirst onReady.');
        this.mLoopCaptureFirstController.imageSmoothingEnabled = true;
        this.mLoopCaptureFirstController.imageSmoothingQuality = 'medium';
        this.captureStartFirstAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureFirstController,
          renderer: 'canvas',
          loop: false,
          autoplay: true,
          name: LIGHT_PAINTING_CAPTURE_FIRST_LOOP,
          path: LIGHT_PAINTING_CAPTURE_PATH,
        })
        this.captureStartFirstAnimationItem.addEventListener('complete', (args: Object): void => {
          HiLog.i(TAG, 'lottieCanvasLightPaintingCaptureStartFirst complete.');
          this.nightCaptureFirstFinish = true;
        }); //动画播放结束且不再播放动画触发
      })
      .onDisAppear(() => {
        if (this.captureStartFirstAnimationItem !== undefined) {
          HiLog.i(TAG, 'lottieCanvasLightPaintingCaptureStartFirst onDisAppear.');
          lottie?.destroy(LIGHT_PAINTING_CAPTURE_FIRST_LOOP);
          this.captureStartFirstAnimationItem = undefined;
        }
      })
      .visibility(Visibility.Visible)
  }

  @Builder
  nightOuterBtn() {
    Row() {
      if (this.nightShutterStatus && !this.confirmCaptureState) {
      } else if (this.nightShutterStatus && this.confirmCaptureState && !this.nightCaptureFirstFinish) {
        this.lottieCanvasCaptureStartFirst();
      } else if (this.nightShutterStatus && this.confirmCaptureState && this.nightCaptureFirstFinish) {
        this.lottieCanvasCaptureStartSecond();
      }
    }
  }

  @Builder
  timeLapseOuterBtn() {
    Row() {
      if (this.videoState === RecordingState.RECORDING || this.videoState === RecordingState.STARTING) {
        this.lottieTimeLapseCanvasStart();
      } else if (this.videoState === RecordingState.STOPPING) {
        this.loadingBtnSecond();
      }
    }
  }

  @Builder
  longExposureOuterBtn() {
    Row() {
      if (this.isShowCountDown) {
        this.countDownBtnStart();
      } else {
        if (this.loadingCaptureFirstFinish) {
          this.loadingBtnSecond();
        } else {
          this.loadingBtnFirst();
        }
      }
    }
  }

  @Builder
  lottieTimeLapseCanvasStart() {
    Canvas(this.mLoopStartController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'lottieTimeLapseCanvasStart onReady.');
        this.mLoopStartController.imageSmoothingEnabled = true;
        this.mLoopStartController.imageSmoothingQuality = 'medium';
        this.exposureStartAnimationItem?.destroy();
        this.exposureStartAnimationItem = lottie.loadAnimation({
          container: this.mLoopStartController,
          renderer: 'canvas',
          loop: true,
          autoplay: true,
          name: LIGHT_PAINTING_CAPTURE_FIRST_LOOP,
          path: LIGHT_PAINTING_CAPTURE_PATH,
        })
        this.exposureStartAnimationItem.addEventListener('DOMLoaded', (args: Object): void => {
          HiLog.i(TAG, 'lottieTimeLapseCanvasStart DownLoaded');
          let ssd: number | undefined = this.exposureStartAnimationItem?.getDuration();
          if (ssd === undefined) {
            return;
          }
          let speed: number = (ssd / 12);
          this.exposureStartAnimationItem?.setSpeed(speed);
        })
      })
      .onDisAppear((): void => {
        // Canvas销毁时销毁lottie动画
        HiLog.i(TAG, 'lottieTimeLapseCanvasStart onDisAppear.');
        if (this.exposureStartAnimationItem !== undefined) {
          lottie?.destroy(LIGHT_PAINTING_CAPTURE_FIRST_LOOP);
          this.exposureStartAnimationItem = undefined;
        }
      })
  }

  @Builder
  lottieCanvasCaptureStartFirst() {
    Canvas(this.mLoopCaptureFirstController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'lottieCanvasCaptureStartFirst onReady.');
        this.mLoopCaptureFirstController.imageSmoothingEnabled = true;
        this.mLoopCaptureFirstController.imageSmoothingQuality = 'medium';
        this.captureStartFirstAnimationItem?.destroy();
        lottie.pause(NIGHT_CAPTURE_FIRST_LOOP);
        this.captureStartFirstAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureFirstController,
          renderer: 'canvas',
          loop: false,
          autoplay: true,
          name: NIGHT_CAPTURE_FIRST_LOOP,
          path: NIGHT_CAPTURE_FIRST_PATH,
        })
        this.captureStartFirstAnimationItem.addEventListener('complete', (args: Object): void => {
          HiLog.i(TAG, 'lottieCanvasCaptureStart complete.');
          this.nightCaptureFirstFinish = true;
        }); //动画播放结束且不再播放动画触发
      })
      .onDisAppear((): void => {
        if (this.captureStartFirstAnimationItem !== undefined) {
          HiLog.i(TAG, 'lottieCanvasCaptureStart onDisAppear.');
          lottie?.destroy(NIGHT_CAPTURE_FIRST_LOOP);
          this.captureStartFirstAnimationItem = undefined;
        }
      })
      .visibility(this.nightShutterStatus && this.confirmCaptureState &&
        !this.nightCaptureFirstFinish ? Visibility.Visible : Visibility.Hidden)
  }

  @Builder
  stitchingLottieShootFirst() {
    Canvas(this.mLoopCaptureFirstController)
      .width(64)
      .height(64)
      .onReady((): void => {
        this.mLoopCaptureFirstController.imageSmoothingEnabled = true;
        this.mLoopCaptureFirstController.imageSmoothingQuality = 'medium';
        this.captureStartFirstAnimationItem?.destroy();
        this.captureStartFirstAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureFirstController,
          renderer: 'canvas',
          loop: false,
          autoplay: true,
          name: STITCHING_FIRST_LOOP,
          path: NIGHT_CAPTURE_FIRST_PATH,
        })
        this.captureStartFirstAnimationItem.addEventListener('complete', (args: Object): void => {
        }); //动画播放结束且不再播放动画触发
      })
      .onDisAppear((): void => {
        if (this.captureStartFirstAnimationItem !== undefined) {
          HiLog.i(TAG, 'lottieCanvasCaptureStart onDisAppear.');
          lottie?.destroy(STITCHING_FIRST_LOOP);
          this.captureStartFirstAnimationItem = undefined;
        }
      })
  }

  private isLoadingBtnSecond(): boolean {
    return this.isShowLoading && this.loadingCaptureFirstFinish;
  }

  @Builder
  lottieCanvasCaptureStartSecond() {
    Canvas(this.mLoopCaptureSecondController)
      .width(64)
      .height(64)
      .onReady((): void => {
        HiLog.i(TAG, 'lottieCanvasCaptureStartSecond onReady.');
        this.mLoopCaptureSecondController.imageSmoothingEnabled = true;
        this.mLoopCaptureSecondController.imageSmoothingQuality = 'medium';
        this.captureStartSecondAnimationItem?.destroy();
        lottie.pause(NIGHT_CAPTURE_SECOND_LOOP);
        this.captureStartSecondAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureSecondController,
          renderer: 'canvas',
          loop: true,
          autoplay: true,
          name: NIGHT_CAPTURE_SECOND_LOOP,
          path: NIGHT_CAPTURE_SECOND_PATH,
        })
      })
      .onDisAppear((): void => {
        if (this.captureStartSecondAnimationItem !== undefined) {
          HiLog.i(TAG, 'lottieCanvasCaptureStartSecond onDisAppear.');
          lottie?.destroy(NIGHT_CAPTURE_SECOND_LOOP);
          this.captureStartSecondAnimationItem = undefined;
        }
      })
      .visibility(this.nightShutterStatus && this.confirmCaptureState && this.nightCaptureFirstFinish
        ? Visibility.Visible : Visibility.Hidden)
  }

  @Builder
  stitchingLottieShootSecond() {
    Canvas(this.mLoopCaptureSecondController)
      .width(64)
      .height(64)
      .onReady((): void => {
        this.mLoopCaptureSecondController.imageSmoothingEnabled = true;
        this.mLoopCaptureSecondController.imageSmoothingQuality = 'medium';
        this.captureStartSecondAnimationItem?.destroy();
        this.captureStartSecondAnimationItem = lottie.loadAnimation({
          container: this.mLoopCaptureSecondController,
          renderer: 'canvas',
          loop: true,
          autoplay: true,
          name: STITCHING_SECOND_LOOP,
          path: NIGHT_CAPTURE_SECOND_PATH,
        })
      })
      .onDisAppear((): void => {
        if (this.captureStartSecondAnimationItem !== undefined) {
          lottie?.destroy(STITCHING_SECOND_LOOP);
          this.captureStartSecondAnimationItem = undefined;
        }
      })
  }

  /**
   * 及时清除定时器,避免timerId相对异步修改导致前一Id所属操作无法控制问题
   * */
  private clearTimer(): void {
    if (Number.MIN_VALUE !== this.nightTimerId) {
      clearTimeout(this.nightTimerId);
    }
  }

  private videoInnerTouchFn(event: TouchEvent): void {
    HiLog.i(TAG, 'videoInnerTouchFn videoState : ' + this.videoState);
    HiLog.i(TAG, 'videoInnerTouchFn event : ' + simpleStringify(event));
    if (this.videoState === RecordingState.STOPPING) {
      HiLog.e(TAG, 'videoInnerTouchFn videoState is stopping.');
      return;
    }
    if (MemoryService.getInstance().isFullStorage(true)) {
      if (event.type === TouchType.Down) {
        VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_DOWN);
      }
      if (event.type === TouchType.Up) {
        VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_UP);
      }
      HiLog.e(TAG, 'videoInnerTouchFn: The Storage is full and cannot record');
      return;
    }
    if (event.type === TouchType.Cancel) {
      HiLog.e(TAG, 'videoInnerTouchFn: The record cancel.');
      if (!this.uiEnable) {
        this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
      }
      this.onVideoButtonUpCancel();
    }
    if (event.type === TouchType.Down) {
      this.mAction.isShowExtendBarAndParamBar();
    }
    if (event.type === TouchType.Down) {
      RecordController.getInstance().click();
      HiLog.i(TAG, `TouchType.Down event: ${simpleStringify(event)}.`);
      this.videoProcess(true);
    }
    if (event.type === TouchType.Up) {
      HiLog.i(TAG, `TouchType.Up event: ${simpleStringify(event)}.`);
      if (RecordController.getInstance().getRecordType() !== RecordType.longClick) {
        this.videoProcess(false);
      }
    }
  }

  private getPhotoInnerBtnBgc(): string | Color {
    return this.isShowLongExposure ? Color.Gray : Color.White;
  }

  private getVideoInnerBtnBgc(): string | Color {
    return this.videoColor;
  }

  @Builder
  photoInnerBtn() {
    Stack({ alignContent: Alignment.Center }) {
      Column()
        .width(this.isVdeCollapsed ? 40 : this.captureBtnWidth)
        .aspectRatio(1)
        .borderRadius(this.isShowSubScreenRadius ? 0 : this.captureBtnRadius)
        .backgroundColor(this.getPhotoInnerBtnBgc())

      if (this.audioControlType === SettingFuncDialogItemIndex.INDEX_SEC ||
        this.audioControlType === SettingFuncDialogItemIndex.INDEX_THR) {
        AudioControlShutterButton()
          .scale(this.audioCaptureBtnScale)
          .aspectRatio(1)
          .borderRadius(this.isShowSubScreenRadius ? 0 : 9)
          .visibility(this.audioCaptureBtnVisibility)
          .rotate({ angle: this.rotateAngle })
      }
    }
    .width(this.isVdeCollapsed ? '56vp' : $r('app.float.big_button_length'))
    .aspectRatio(1)
    .id(ComponentIdKeys.SHUTTER_PHOTO_1)
    .scale(this.captureBtnScale)
    .opacity(this.captureBtnOpacity)
    .enabled((!this.isDuringSavePowerMode ||
      this.excludeComponent === UIOperationType.CAPTURE_BUTTON) && !this.isOpenOrCloseTreasureBox)
    .onTouch(this.photoInnerTouchFn())
    .visibility(this.isLrShutterShown ? Visibility.None : Visibility.Visible)
    .accessibilityGroup(true)
    .accessibilityRole(AccessibilityRoleType.BUTTON)
    .accessibilityDescription(`${ResGetter.getStringSafe($r('app.string.accessibility_clickable'))} ${''}`)
    .accessibilityLevel(CommonConstants.ACCESSIBILITY_LEVEL_YES)

    // .onPhotoInnerBtnClick();//无障碍模式点击
  }

  @Styles
  private onPhotoInnerBtnClick() {
    .onClick((event) => {
    })
  }

  private photoInnerTouchFn(): (event: TouchEvent) => void {
    return (event: TouchEvent) => {
      HiLog.i(TAG, `photoInnerBtn onTouch: ${event?.type}.`);
      if (!event) {
        return;
      }
      // 打断场景的恢复
      if (event.type === TouchType.Cancel) {
        HiLog.i(TAG, `touch canceled ${this.uiEnable},${this.excludeComponent}`);
        this.longClickUpdate(false);
        if (!this.uiEnable && this.excludeComponent === UIOperationType.CAPTURE_BUTTON) {
          this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
        }
        this.resetPhotoInnerBtn();
        return;
      }
      if (this.singleStagePhotoCaptured && this.isPicker) {
        return;
      }
      if (this.isShowLongExposure) {
        if (event.type === TouchType.Up) {
          // 避免阻塞长曝光场景拇指图更新
          this.mHasClickDownCapture = false;
          this.mIsLongCaptureWaitingClickUp = false;
          this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
        }
        HiLog.i(TAG, 'long exposure shutter interrupt.');
        return;
      }

      if (!this.isSupportLrSwipe()) {
        this.photoInnerBtnOnTouch(event);
        HiLog.i(TAG, 'lr swipe shutter interrupt.');
        return;
      }

      if (event.type != TouchType.Down && event.type != TouchType.Cancel && this.isIgnoreTouch) {
        HiLog.i(TAG, 'event shutter interrupt.');
        return;
      }
      this.isIgnoreTouch = false;
      if (!this.isInTouchTarget(event) && !this.isShutterButtonLongClick) {
        // 按压后划出快门场景,特殊抬起状态
        HiLog.i(TAG, 'out PhotoInnerBtn');
        if (this.isFrameStarted) {
          this.photoShutterUpAnimate();
        }
        this.mAction.enableUiWithMode(UiStateMode.EXCLUDE_COMPONENT, UIOperationType.NULL);
        this.isIgnoreTouch = true;
        if (this.mHasClickDownCapture) {
          this.mWaitingThumbnailAnimation = false;
          ThumbnailService.getInstance().thumbnailUpdate(1);
          LeftRightSwipeWorkerCaptureService.getInstance().needDeleteOnePhoto(false);
        }
        this.longClickUpdate(false);
        return;
      }
      this.photoInnerBtnOnTouch(event);
    }
  }

  private isSupportLrSwipe(): boolean {
    return false;
  }

  @Builder
  videoInnerBtn() {
    Stack({ alignContent: Alignment.Center }) {
      Column()
        .width(this.videoWidth)
        .aspectRatio(1)
        .borderRadius(this.isShowSubScreenRadius ? 0 : this.videoRadius)
        .backgroundColor(this.getVideoInnerBtnBgc())
        .opacity(1)

      Column()
        .width(this.isVdeCollapsed ? 20 : 24)
        .aspectRatio(1)
        .borderRadius(this.isShowSubScreenRadius ? 0 : 12)
        .scale(this.videoBtn2Scale)
        .opacity(this.videoBtn2Opacity)
        .backgroundColor(Color.Red)
    }
    .width(64)
    .aspectRatio(1)
    .scale(this.videoBtn1Scale)
    .opacity(1)
    .enabled((this.uiEnable || this.excludeComponent === UIOperationType.RECORD_BUTTON) &&
      !this.isOpenOrCloseTreasureBox)
    .key(this.videoState === RecordingState.READY
      ? ComponentIdKeys.SHUTTER_VIDEO_1
      : ComponentIdKeys.SHUTTER_VIDEO_END_1)
    .onTouch(async (event?: TouchEvent) => {
      HiLog.i(TAG, 'videoInnerBtn click.');
      if (event === undefined) {
        return;
      }
      this.videoInnerTouchFn(event);
    })
    .accessibilityGroup(true)
    .accessibilityText(this.getABText())
    .accessibilityLevel(CommonConstants.ACCESSIBILITY_LEVEL_YES)
    .onVideoInnerBtnClick()
    .accessibilityDescription(`${ResGetter.getStringSafe($r('app.string.accessibility_button'))} ${
    ResGetter.getStringSafe($r('app.string.accessibility_clickable'))}`)
    .gesture(
      LongPressGesture({ repeat: false, duration: 500 })
        .onAction((event: GestureEvent | undefined) => {
          if (!event) {
            HiLog.e(TAG, 'LongPressGesture event undefined.');
          }
          if (!this.uiEnable && this.excludeComponent !== UIOperationType.RECORD_BUTTON) {
            HiLog.e(TAG, `return, uiEnable: ${this.uiEnable}, excludeComponent: ${this.excludeComponent}.`);
            return;
          }
          HiLog.i(TAG, `checkPreRecordConditions ok, recordState: ${this.videoState}.`);
          if (this.videoState !== RecordingState.READY) {
            return;
          }
          if (MemoryService.getInstance().isFullStorage(true)) {
            return;
          }
          HiLog.i(TAG, 'PRE_RECORD_TRACK preRecord is opened, trigger preRecord.');
          VibratorService.getInstance().triggerVibrator(VibratorService.SHUTTER_CLICK_DOWN);
          RecordController.getInstance().longClick();
          PowerKeyService.getInstance().powerKeySubscribe();
          HiLog.i(TAG, 'ShutterButton startRecording changeTimeLapse not called.');
          this.startVideoAnim();
          this.mAction.startRecording(false);
          this.mAction.changeFunctionValue(FunctionId.RECORD_CONTROL, RecordMode.TO_START);
          this.mAction.isShowExtendBarAndParamBar();
        })
        .onActionEnd(() => {
          HiLog.i(TAG, `PRE_RECORD_TRACK LongPressGesture onActionEnd`)
        })
    )
  }

  @Styles
  private onVideoInnerBtnClick() {
    .onClick((event) => {
    })
  }

  @Builder
  shutterOuterBtn() {
    if (this.currentButtonType === ShutterButtonType.SECOND_CAPTURE) {
      this.nightOuterBtn();
    } else {
      if (this.isShowLongExposure) {
        this.longExposureOuterBtn();
      } else {
        this.normalOuterBtn();
      }
    }
  }

  private isButtonTypeVideo(): boolean {
    return this.currentButtonType === ShutterButtonType.NORMAL_VIDEO;
  }

  build() {
    Stack({ alignContent: Alignment.Center }) {
      this.normalOuterBtn()
      if (this.currentButtonType === ShutterButtonType.NORMAL_CAPTURE) {
        this.photoInnerBtn();
      } else if (this.isButtonTypeVideo()) {
        this.videoInnerBtn();
      }
    }
    .onTouch((event) => {
      AppStorage.setOrCreate<boolean>('disShutterEmitTreasureOpen', true);
      if (event.type === TouchType.Up || event.type === TouchType.Cancel) { // 双指拍摄&切模式同时操作,Ui错乱
        this.mAction.disAbleModeBarChanged(false);
      } else {
        this.mAction.disAbleModeBarChanged(true);
      }
    })
    .margin(this.getMargin())
    .id(ComponentIdKeys.SHUTTER_BUTTON_STACK)
    .accessibilityLevel(CommonConstants.ACCESSIBILITY_LEVEL_NO)
    .height(this.isVdeCollapsed ? '56vp' : $r('app.float.big_button_length'))
    .width($r('app.float.big_button_length'))
    .onDisAppear(() => {
      AppStorage.setOrCreate<boolean>('disShutterEmitTreasureOpen', false);
      this.mAction.disAbleModeBarChanged(false);
    })
    .onAppear(() => {
      // 无障碍场景 key值归一 方便自动聚焦拍摄组件
      if (!this.isButtonTypeVideo()) {
        AccessibilityUtils.sendFocusAccessibilityEvent('nightShutterStatusShutter');
      }
      AccessibilityUtils.sendFocusAccessibilityEvent(ComponentIdKeys.SHUTTER_VIDEO_1);
    })
  }

  private getMargin(): Padding | undefined {
    if (this.isVdeCollapsed) {
      if (PickerUtils.getIsPicker()) {
        return { left: '29vp', right: '29vp' };
      }
      return { left: '21vp', right: '21vp' };
    }
    if (this.horizontallyArranged) {
      return { left: 74, right: 74 };
    }
    if (DeviceInfo.isTablet()) {
      if (PickerUtils.getIsPicker() && this.pickerWindowType === PickerWindowType.TABLET_TOP_BOTTOM_HALF_SPLIT_SCREEN) {
        return { top: 0.05 * this.screenHeight, bottom: 0.05 * this.screenHeight };
      }
      if (!PickerUtils.getIsPicker() || this.pickerWindowType === PickerWindowType.TABLET_FULL_SCREEN &&
      DisplayService.getInstance().isOrientationVertical()) {
        return { top: 74, bottom: 74 };
      }
      return {
        top: this.pickerWindowType === PickerWindowType.TABLET_1_3_SPLIT_SCREEN ? 32 : 0.1 * this.screenHeight,
        bottom: this.pickerWindowType === PickerWindowType.TABLET_1_3_SPLIT_SCREEN ? 32 : 0.1 * this.screenHeight
      };
    }
    return { top: 62, bottom: 62 };
  }

  private updateDensity() {
    HiLog.i(TAG, 'updateDensity density=' + this.density);
    this.isShowSubScreenRadius = this.density === 1.5;
  }

  private getABText(): string {
    HiLog.i(TAG, 'getABText videoState=' + this.videoState);
    return ResGetter.getStringSafe('');
  }

  private changeOuterBackground(): void {
    if (this.isLrShutterShown) {
      this.shutterOutsideBackground = Color.Transparent;
      this.shouldApplyShade = false;
    } else {
      this.shouldApplyShade = true;
      setTimeout(() => {
        if (this.shouldApplyShade) {
          this.shutterOutsideBackground = SHUTTER_OUT_SHADE_COLOR;
        }
        this.shouldApplyShade = false;
      }, AnimSpecifications.ANIM_DURATION_150)
    }
  }
}