• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import router from '@system.router';
17import display from '@ohos.display';
18import deviceInfo from '@ohos.deviceInfo';
19import { BigVideoTimer } from './BigVideoTimer';
20import { Action, UiStateMode } from '@ohos/common/src/main/ets/default/redux/actions/Action';
21import { AssistiveGridView } from '@ohos/common/src/main/ets/default/featurecommon/assistivegridview/AssistiveGridView';
22import { BigText } from '@ohos/common/src/main/ets/default/featurecommon/bigtext/BigText';
23import { CameraNeedStatus, CameraStatus } from '@ohos/common/src/main/ets/default/utils/Constants';
24import { CameraId } from '@ohos/common/src/main/ets/default/setting/settingitem/CameraId';
25import { EventBus } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBus';
26import { EventBusManager } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBusManager';
27import { Dispatch, getStore, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store';
28import { Log } from '@ohos/common/src/main/ets/default/utils/Log';
29import { GeoLocation } from '@ohos/common/src/main/ets/default/featurecommon/geolocation/GeoLocation';
30import { ScreenLockManager } from '@ohos/common/src/main/ets/default/featurecommon/screenlock/ScreenLockManager';
31import { SettingManager } from '@ohos/common/src/main/ets/default/setting/SettingManager';
32import { ShowFlashBlack } from '@ohos/common/src/main/ets/default/featurecommon/animate/ShowFlashBlack';
33import { TimeLapseView } from '@ohos/common/src/main/ets/default/featurecommon/timelapseview/TimeLapseView';
34import { ZoomText } from '@ohos/common/src/main/ets/default/featurecommon/zoomview/ZoomText';
35import { SmallVideoTimer } from './SmallVideoTimer';
36import promptAction from '@ohos.promptAction';
37import wantConstant from '@ohos.ability.wantConstant';
38import { GlobalContext } from '@ohos/common/src/main/ets/default/utils/GlobalContext';
39import { CameraPlatformCapability } from '@ohos/common/src/main/ets/default/camera/CameraPlatformCapability';
40import { BusinessError } from '@ohos.base';
41
42const DEFAULT_FUNCTION: Function = () => {
43};
44
45class SizeStruct {
46  width: number = 0;
47  height: number = 0;
48}
49
50class StateStruct {
51  mode: string = '';
52  curMode: string = '';
53  isShowPreview: boolean = true;
54  surfaceId: number = 0;
55  xComponentWidth: number = 0;
56  xComponentHeight: number = 0;
57  cameraPosition: CameraId = CameraId.BACK;
58  curCameraPosition: CameraId = CameraId.BACK;
59  minZoomRatio: number = 0;
60  maxZoomRatio: number = 0;
61  zoomRatio: number = 0;
62  platformCapability: CameraPlatformCapability | undefined = undefined;
63  videoState: string = '';
64  footBarHeight: number = 0;
65  isShowZoomText: boolean = false;
66  showZoomLabelValue: boolean = false;
67  modeIndex: number = 0;
68  isThirdPartyCall: boolean = false;
69  isShowBigText: boolean = false;
70  isShowtimeLapse: boolean = false;
71  isBigVideoTimerVisible: boolean = false;
72  isSmallVideoTimerVisible: boolean = false;
73  isAssGridViewShow: string = '';
74  isShowFlashBlack: boolean = false;
75  modeChangeDone: boolean = false;
76  isShowPageView: boolean = false;
77  showBlur: boolean = false;
78  isFaCall: boolean = false;
79  baseZoom: number = 0;
80}
81
82class PreviewAreaDispatcher {
83  private mDispatch: Dispatch = (data) => data;
84
85  public setDispatch(dispatch: Dispatch) {
86    this.mDispatch = dispatch;
87  }
88
89  public initCamera(cameraId: CameraId, mode: string): void {
90    this.mDispatch(Action.initCamera(cameraId, mode));
91  }
92
93  public initZoomRatio(min: number, max: number): void {
94    this.mDispatch(Action.initZoomRatio(min, max));
95  }
96
97  public changeZoomRatio(zoomRatio: number): void {
98    this.mDispatch(Action.changeZoomRatio(zoomRatio));
99  }
100
101  public updateZoomPercentage(zoomPercentage: number): void {
102    this.mDispatch(Action.updateZoomPercentage(zoomPercentage));
103  }
104
105  public prepareSurface(surfaceId: number): void {
106    this.mDispatch(Action.prepareSurface(surfaceId));
107  }
108
109  public startPreview(zoomRatio: number): void {
110    this.mDispatch(Action.startPreview(zoomRatio));
111  }
112
113  public switchCamera(cameraId: CameraId, mode: string): void {
114    this.mDispatch(Action.switchCamera(cameraId, mode));
115  }
116
117  public updateCameraPosition(cameraPosition: string): void {
118    this.mDispatch(Action.updateCameraPosition(cameraPosition));
119  }
120
121  public startVideoFlag(isStartVideo: boolean): void {
122    this.mDispatch(Action.startVideoFlag(isStartVideo));
123  }
124
125  public changeXComponentSize(xComponentWidth: number, xComponentHeight: number): void {
126    this.mDispatch(Action.changeXComponentSize(xComponentWidth, xComponentHeight));
127  }
128
129  public updateShowPreviewFlag(isShowPreview: boolean): void {
130    this.mDispatch(Action.updateShowPreviewFlag(isShowPreview));
131  }
132
133  public updateIsShowZoomText(isShowZoomText: boolean): void {
134    this.mDispatch(Action.updateShowZoomTextFlag(isShowZoomText));
135  }
136
137  public updateIsPhotoZoomDetails(isPhotoZoomDetails: boolean): void {
138    this.mDispatch(Action.updatePhotoZoomDetailsFlag(isPhotoZoomDetails));
139  }
140
141  public updateBaseZoom(zoomRatio: number): void {
142    this.mDispatch(Action.updateBaseZoom(zoomRatio));
143  }
144
145  public changeImageSize(videoSize: ScreenSizeType): void {
146    this.mDispatch(Action.changeVideoSize(videoSize));
147  }
148
149  public changeVideoSize(videoSize: SizeStruct): void {
150    this.mDispatch(Action.changeVideoSize(videoSize));
151  }
152
153  public close(): void {
154    this.mDispatch(Action.close());
155  }
156
157  public stopRecording(): void {
158    this.mDispatch(Action.stopRecording());
159    this.mDispatch(Action.updateVideoState('beforeTakeVideo'));
160    this.mDispatch(Action.updateBigVideoTimerVisible(false));
161    this.mDispatch(Action.updateSmallVideoTimerVisible(false));
162    this.mDispatch(Action.updateScreenStatus(false));
163  }
164
165  public changeTimeLapse(isShowtimeLapse: boolean): void {
166    this.mDispatch(Action.changeTimeLapse(isShowtimeLapse));
167  }
168
169  public capture(): void {
170    this.mDispatch(Action.updateShowFlashBlackFlag(true));
171    this.mDispatch(Action.capture());
172  }
173
174  public startRecording(): void {
175    this.mDispatch(Action.startRecording());
176    this.mDispatch(Action.updateVideoState('startTakeVideo'));
177    this.mDispatch(Action.updateBigVideoTimerVisible(true));
178    this.mDispatch(Action.updateScreenStatus(true));
179  }
180
181  public assistiveGridView(isViewShow: number): void {
182    this.mDispatch(Action.assistiveGridView(isViewShow));
183  }
184
185  public swipeChangeMode(swipeModeIndex: number): void {
186    this.mDispatch(Action.swipeChangeMode(swipeModeIndex));
187  }
188
189  public thirdPartyCall(isThirdPartyCall: boolean, action: string): void {
190    this.mDispatch(Action.thirdPartyCall(isThirdPartyCall, action));
191  }
192
193  public faCall(isFaCall: boolean): void {
194    this.mDispatch(Action.faCall(isFaCall));
195  }
196
197  public initMode(mode: string): void {
198    this.mDispatch(Action.initMode(mode));
199  }
200
201  public updateModeIndex(index: number): void {
202    this.mDispatch(Action.updateModeIndex(index));
203  }
204
205  public updateMode(mode: string): void {
206    this.mDispatch(Action.updateMode(mode));
207  }
208
209  public changeToMode(mode: string): void {
210    this.mDispatch(Action.changeMode(mode));
211  }
212
213  public updateShowZoomLabelValue(flag: boolean): void {
214    this.mDispatch(Action.updateShowZoomLabelValue(flag));
215  }
216
217  public reloadThumbnail(): void {
218    this.mDispatch(Action.reloadThumbnail());
219  }
220
221  public changeCameraPosition(cameraPosition: string): void {
222    this.mDispatch(Action.setCameraPosition(cameraPosition));
223  }
224
225  public updateShowPinch(flag: boolean): void {
226    this.mDispatch(Action.updateShowPinch(flag));
227  }
228
229  public swipeModeChangeDone(actionOff: boolean): void {
230    this.mDispatch(Action.swipeModeChangeDone(actionOff));
231  }
232
233  public updateInitShowFlag(initShowFlag: boolean): void {
234    this.mDispatch(Action.updateInitShowFlag(initShowFlag));
235  }
236
237  public hideSettingView(): void {
238    this.mDispatch(Action.showSettingView(false));
239  }
240}
241
242GlobalContext.get().setXComponentController(new XComponentController())
243
244interface ScreenSizeType {
245  width: number
246  height: number
247}
248
249interface PlatformCapability {
250  platformCapability: CameraPlatformCapability
251}
252
253interface ModeData {
254  mode: string
255}
256
257interface KeepScreenData {
258  isKeepScreenOn: boolean
259}
260
261@Component
262export struct PreviewAreaLand {
263  private TAG: string = '[PreviewAreaLand]:';
264  appEventBus: EventBus = EventBusManager.getInstance().getEventBus();
265  @State state: StateStruct = new StateStruct();
266  @State btnSwitch: boolean = false;
267  @State btnSwitchSec: boolean = false;
268  @State pinchGestureTimerId: number = 0;
269  @State onTouchDownTimerId: number = 0;
270  @State scaleX: number = 1;
271  @State scaleXSec: number = 0.8;
272  @State rotateAngle: number = 0;
273  @State rotateAngleSec: number = 80;
274  @State btnOpacityFirst: number = 1;
275  @State btnOpacitySec: number = 0;
276  @State switchBackgroundOpacity: number = 1;
277  @State isSwitchBackground: boolean = false;
278  @State pageType: string = '';
279  @Link screenSize: ScreenSizeType;
280  @State isShowBlurSize: ScreenSizeType = { width: 0, height: 0 };
281  private mConnect: Function = () => {
282  };
283  private isShowPreview: boolean = false;
284  private settingManager = SettingManager.getInstance();
285  private pinchGestureTimer: number = 0;
286  private baseZoom: number = 0;
287  private modeArray: Array<string> = ['PHOTO', 'VIDEO'];
288  private mAction: PreviewAreaDispatcher = new PreviewAreaDispatcher();
289
290  private async onCameraInit(): Promise<void> {
291    Log.info(`${this.TAG} EventBus onCameraInit isShowPreview = ${this.isShowPreview}
292      platformCapability = ${this.state.platformCapability} E`);
293    if (this.state.platformCapability) {
294      this.settingManager.loadAllSetting().then(() => {
295        this.settingManager.setCameraId(this.state.cameraPosition);
296
297        let imageSize = this.settingManager.getImageSize();
298        this.mAction.changeImageSize(imageSize);
299
300        let videoSize = this.settingManager.getVideoSize();
301        this.mAction.changeVideoSize(videoSize);
302
303        let isAssGridViewShow: number = Number(this.settingManager.getAssistiveGrid());
304        this.mAction.assistiveGridView(isAssGridViewShow);
305
306        GeoLocation.getInstance().on();
307
308        this.resetScreenSize(this.screenSize);
309        this.mAction.updateShowPreviewFlag(true);
310      })
311    }
312    Log.info(`${this.TAG} onCameraInit isShowPreview = ${this.state.isShowPreview}  X`);
313  }
314
315  private async doCameraAction() {
316    Log.info(`${this.TAG} doCameraAction E`);
317    this.settingManager.setCameraId(this.state.cameraPosition);
318    Log.info(`${this.TAG} curMode:${this.state.curMode} mode:${this.state.mode}`);
319    if (this.state.curCameraPosition != this.state.cameraPosition) {
320      this.mAction.switchCamera(this.state.cameraPosition, this.state.mode);
321      this.mAction.updateCameraPosition(this.state.cameraPosition);
322    } else if (this.state.curMode != this.state.mode) {
323      this.mAction.changeToMode(this.state.mode);
324      this.mAction.updateMode(this.state.mode);
325    } else {
326      if (GlobalContext.get().getT<boolean>('keepCameraZoomRatio') && GlobalContext.get()
327        .getT<boolean>('keepCameraZoomRatio')) {
328        GlobalContext.get().setObject('keepCameraZoomRatio', false)
329        Log.info(`${this.TAG} keep zoomRatio: ` + this.state.zoomRatio);
330      } else {
331        this.mAction.changeZoomRatio(1);
332        Log.info(`${this.TAG} change zoomRatio: 1`);
333      }
334      this.mAction.startPreview(this.state.zoomRatio);
335    }
336    Log.info(`${this.TAG} doCameraAction X`);
337    this.mAction.updateInitShowFlag(true);
338  }
339
340  private async onModeChanged(data: ModeData) {
341    Log.info(`${this.TAG} onModeChanged E data.mode: ${data.mode}`);
342    this.mAction.changeZoomRatio(1);
343    this.mAction.updateShowPreviewFlag(true);
344    Log.info(`${this.TAG} onModeChanged X`);
345  }
346
347  private async onRecordError() {
348    Log.info(`${this.TAG} onRecordError invoke E`);
349    promptAction.showToast({
350      message: "录像异常",
351      duration: 2000,
352    })
353    if (this.state.videoState === 'startTakeVideo') {
354      this.mAction.stopRecording();
355    }
356    this.mAction.close();
357    Log.info(`${this.TAG} onRecordError invoke X`);
358  }
359
360  aboutToAppear(): void {
361    Log.info(`${this.TAG} aboutToAppear E ${JSON.stringify(router.getParams())}`);
362    let routerParams = router.getParams();
363    if (routerParams && routerParams.pageType) {
364      this.pageType = routerParams.pageType.toString();
365    }
366    getStore().subscribe((state: OhCombinedState) => {
367      let isShowBlur: boolean = !state.contextReducer.uiEnable && state.contextReducer.uiStateMode == UiStateMode.NONE;
368      this.state = {
369        mode: state.modeReducer.mode,
370        curMode: state.modeReducer.curMode,
371        isShowPreview: state.previewReducer.isShowPreview,
372        surfaceId: state.previewReducer.surfaceId,
373        xComponentWidth: state.previewReducer.xComponentWidth,
374        xComponentHeight: state.previewReducer.xComponentHeight,
375        cameraPosition: state.cameraReducer.cameraPosition,
376        curCameraPosition: state.cameraReducer.curCameraPosition,
377        minZoomRatio: state.zoomReducer.minZoomRatio,
378        maxZoomRatio: state.zoomReducer.maxZoomRatio,
379        zoomRatio: state.zoomReducer.zoomRatio,
380        platformCapability: state.cameraInitReducer.platformCapability,
381        videoState: state.recordReducer.videoState,
382        footBarHeight: state.contextReducer.footBarHeight,
383        isShowZoomText: state.zoomReducer.isShowZoomText,
384        showZoomLabelValue: state.zoomReducer.showZoomLabelValue,
385        modeIndex: state.modeReducer.modeIndex,
386        isThirdPartyCall: state.contextReducer.isThirdPartyCall,
387        isShowBigText: state.modeReducer.isShowBigText,
388        isShowtimeLapse: state.settingReducer.isShowtimeLapse,
389        isBigVideoTimerVisible: state.recordReducer.isBigVideoTimerVisible,
390        isSmallVideoTimerVisible: state.recordReducer.isSmallVideoTimerVisible,
391        isAssGridViewShow: state.settingReducer.isAssGridViewShow,
392        isShowFlashBlack: state.previewReducer.isShowFlashBlack,
393        modeChangeDone: state.modeReducer.modeChangeDone,
394        isShowPageView: state.settingReducer.isShowSettingView,
395        showBlur: isShowBlur,
396        isFaCall: state.contextReducer.isFaCall,
397        baseZoom: 0
398
399      };
400    }, (dispatch: Dispatch) => {
401      this.mAction.setDispatch(dispatch);
402    });
403    this.mConnect(this.state)
404    this.appEventBus.on(Action.ACTION_INIT_DONE, () => this.onCameraInit);
405    this.appEventBus.on(Action.ACTION_ON_MODE_CHANGED, () => this.onModeChanged);
406    this.appEventBus.on(Action.ACTION_KEEP_SCREEN_ON, () => this.onKeepScreen);
407    this.appEventBus.on('windowSize', () => this.windowSizeChange);
408    this.appEventBus.on(Action.ACTION_RECORD_ERROR, () => this.onRecordError);
409    this.appEventBus.on(ScreenLockManager.SCREEN_CHANGE_EVENT, () => this.onScreenChange);
410    this.appEventBus.on(Action.ACTION_UPDATE_CAMERA_STATUS, () => this.updateCameraStatus);
411    GlobalContext.get().setObject('updateCameraStatus', () => {
412      Log.info(`${this.TAG} globalThis.updateCameraStatus called`);
413      this.updateCameraStatus();
414    });
415    display.getDefaultDisplay().then((dis) => {
416      this.isShowBlurSize = { width: px2vp(dis.width), height: px2vp(dis.height) };
417    })
418    this.calledByOther();
419    this.mAction.initCamera(this.state.cameraPosition, this.state.mode);
420    this.mAction.initZoomRatio(1, 6); //TODO 需要动态取得实际变焦能力范围
421    Log.info(`${this.TAG} aboutToAppear X`);
422    Log.start(Log.X_COMPONENT_LIFE);
423  }
424
425  private releaseCamera(): void {
426    Log.info(`${this.TAG} globalThis.releaseCamera called`);
427    GlobalContext.get().setObject('cameraNeedStatus', CameraNeedStatus.CAMERA_NO_NEED_TO_DO);
428    if (this.state.videoState === 'startTakeVideo') {
429      this.mAction.stopRecording();
430    }
431    this.mAction.close();
432  }
433
434  private async onForegroundInit() {
435    Log.info(`${this.TAG} onForegroundInit E `);
436    this.pageType = '';
437    GlobalContext.get().setObject('cameraNeedStatus', CameraNeedStatus.CAMERA_NO_NEED_TO_DO);
438    this.calledByOther();
439    this.mAction.initCamera(this.state.cameraPosition, this.state.mode);
440    await new Promise<Function | string>((resolve: Function | string) => setTimeout(resolve, 40));
441    this.doCameraAction();
442    this.mAction.updateInitShowFlag(true);
443    if (!this.state.isThirdPartyCall) {
444      this.mAction.reloadThumbnail();
445    }
446    Log.info(`${this.TAG} onForegroundInit X`);
447  }
448
449  private calledByOther(): void {
450    Log.info(`${this.TAG} calledByOther invoke E`);
451    let from: string = "";
452    let action: string = "";
453
454    if (GlobalContext.get().getCameraAbilityWant()) {
455      Log.info(`${this.TAG} cameraAbilityWant: ${JSON.stringify(GlobalContext.get().getCameraAbilityWant())}`);
456      if (GlobalContext.get().getCameraAbilityWant()?.parameters?.from) {
457        from = GlobalContext.get().getCameraAbilityWant()?.parameters?.from as string;
458      }
459      let cameraAbilityWant = GlobalContext.get().getCameraAbilityWant();
460      if (cameraAbilityWant?.action) {
461        action = cameraAbilityWant?.action;
462      }
463    } else {
464      this.mAction.thirdPartyCall(false, "");
465      return;
466    }
467    Log.info(`${this.TAG} from: ${from}  uri: ${action}`);
468
469    if (from === "FA") {
470      Log.info(`from === "FA"`);
471      if (GlobalContext.get().getCameraAbilityWant()?.parameters?.action) {
472        action = GlobalContext.get().getCameraAbilityWant()?.parameters?.action as string;
473      }
474      this.mAction.faCall(true);
475      this.mAction.thirdPartyCall(false, "");
476      this.initStateMode(action);
477    } else if (action != "") {
478      this.mAction.faCall(false);
479      this.mAction.thirdPartyCall(true, GlobalContext.get().getCameraAbilityWant().action as string);
480      this.initStateMode(action);
481    } else {
482      this.mAction.faCall(false);
483      this.mAction.thirdPartyCall(false, "");
484    }
485    Log.info(`${this.TAG} calledByOther invoke X: ${this.state.mode}`);
486  }
487
488  private initStateMode(action: string): void {
489    switch (action) {
490      case wantConstant.Action.ACTION_IMAGE_CAPTURE:
491        this.mAction.initMode('PHOTO');
492        this.mAction.updateModeIndex(0);
493        break;
494      case wantConstant.Action.ACTION_VIDEO_CAPTURE:
495        this.mAction.initMode('VIDEO');
496        this.mAction.updateModeIndex(1);
497        break;
498      default:
499        Log.info(`${this.TAG} FA default`);
500        break;
501    }
502  }
503
504  private updateCameraStatus(): void {
505    Log.info(`${this.TAG} updateCameraStatus  cameraStatus: ${GlobalContext.get().getT<string>('cameraStatus')}
506      cameraNeedStatus: ${GlobalContext.get().getT<string>('cameraNeedStatus')}`);
507    if (this.canInit() && GlobalContext.get().getT<string>('cameraNeedStatus') == CameraNeedStatus.CAMERA_NEED_INIT) {
508      this.onForegroundInit();
509    }
510    if (this.canRelease() && GlobalContext.get()
511      .getT<string>('cameraNeedStatus') == CameraNeedStatus.CAMERA_NEED_RELEASE) {
512      this.releaseCamera();
513    }
514    Log.info(`${this.TAG} updateCameraStatus X`);
515  }
516
517  private canInit(): boolean {
518    //相机状态是首次加载或者session释放完成状态,才能进行初始化操作
519    return GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_BEFORE_VALUE ||
520      GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_RELEASE_FINISHED;
521  }
522
523  private canRelease(): boolean {
524    //相机状态是预览完成状态或录像完成状态才能进行释放操作
525    return GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_PREVIEW_FINISHED ||
526      GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_TAKE_VIDEO_FINISHED;
527  }
528
529  aboutToDisappear(): void {
530    Log.info(`${this.TAG} aboutToDisappear E`);
531    this.appEventBus.off(Action.ACTION_INIT_DONE, () => this.onCameraInit);
532    this.appEventBus.off(Action.ACTION_ON_MODE_CHANGED, () => this.onModeChanged);
533    this.appEventBus.off('windowSize', () => this.windowSizeChange);
534    this.appEventBus.off(Action.ACTION_UPDATE_CAMERA_STATUS, () => this.updateCameraStatus);
535    // this.mConnect?.destroy();
536    GeoLocation.getInstance().off();
537    GlobalContext.get().setObject('cameraNeedStatus', CameraNeedStatus.CAMERA_NEED_RELEASE)
538    this.updateCameraStatus();
539    Log.info(`${this.TAG} aboutToDisappear X`);
540  }
541
542  onPageHide(): void {
543    this.mAction.startVideoFlag(false);
544    Log.info(`${this.TAG} onPageHide`);
545  }
546
547  private switchAnimationSec(): void {
548    Log.info(`${this.TAG} switchAnimationSec called`);
549    animateTo({
550      duration: 200,
551      delay: 0,
552      curve: Curve.Sharp,
553    }, () => {
554      this.btnOpacitySec = 1;
555    })
556    animateTo({
557      duration: 350,
558      curve: Curve.FastOutSlowIn,
559      delay: 0,
560    }, () => {
561      Log.info(`${this.TAG} btnSwitchSec callback btnSwitchSec= ${this.btnSwitchSec}`);
562      this.scaleXSec = 1;
563    })
564    animateTo({
565      duration: 350,
566      curve: 'cubic-bezier(0.21, 0.27, 0.20, 1.00)',
567      delay: 0,
568      onFinish: () => {
569        Log.info(`${this.TAG} btnSwitchSec onFinish btnSwitchSec= ${this.btnSwitchSec}`);
570        this.btnSwitchSec = false;
571        this.btnOpacitySec = 0;
572        this.scaleXSec = 0.8;
573        this.rotateAngleSec = 80;
574        this.switchBackgroundAnimation();
575      }
576    }, () => {
577      Log.info(`${this.TAG} btnSwitchSec callback btnSwitchSec= ${this.btnSwitchSec}`);
578      this.rotateAngleSec = 0;
579    })
580  }
581
582  private switchBackgroundAnimation(): void {
583    animateTo({
584      duration: 350,
585      delay: 0,
586      curve: Curve.Sharp,
587      onFinish: () => {
588        this.isSwitchBackground = false;
589        this.switchBackgroundOpacity = 1;
590      }
591    }, () => {
592      this.switchBackgroundOpacity = 0;
593    })
594  }
595
596  private pinchGestureStart(event: GestureEvent): void {
597    Log.info(`${this.TAG} pinchGestureStart invoke E`);
598    if (this.state.mode != 'MULTI' && this.state.cameraPosition !== 'FRONT') {
599      clearTimeout(this.pinchGestureTimer);
600      this.mAction.updateIsShowZoomText(true);
601      this.mAction.updateShowPinch(true);
602      this.mAction.updateShowZoomLabelValue(false);
603      this.baseZoom = this.state.zoomRatio;
604    }
605    if (this.state.mode !== "MULTI" && this.state.cameraPosition !== 'FRONT') {
606      this.mAction.updateIsShowZoomText(true);
607      this.mAction.updateShowPinch(true);
608      this.mAction.updateIsPhotoZoomDetails(true);
609      this.mAction.updateBaseZoom(this.state.zoomRatio);
610      clearTimeout(this.pinchGestureTimerId);
611      clearTimeout(this.onTouchDownTimerId);
612    }
613    Log.info(`${this.TAG} pinchGestureStart invoke X`);
614  }
615
616  private pinchGestureUpdate(event: GestureEvent): void {
617    Log.info(`${this.TAG} pinchGestureUpdate invoke E`);
618    if (this.state.mode != 'MULTI' && this.state.cameraPosition !== 'FRONT') {
619      let zoomRatio = event.scale + this.baseZoom - 1;
620      if (zoomRatio > 6) {
621        zoomRatio = 6;
622      }
623      if (zoomRatio < 1) {
624        zoomRatio = 1;
625      }
626      this.mAction.changeZoomRatio(zoomRatio);
627    }
628    Log.info(`${this.TAG} pinchGestureUpdate invoke X`);
629  }
630
631  private pinchGestureEnd(event: GestureEvent): void {
632    Log.info(`${this.TAG} pinchGestureEnd invoke E`);
633    this.mAction.updateShowZoomLabelValue(true);
634    this.mAction.updateShowPinch(false);
635    if (this.state.mode != 'MULTI' && this.state.cameraPosition !== 'FRONT') {
636      this.pinchGestureTimer = setTimeout(() => {
637        this.mAction.updateIsShowZoomText(false);
638      }, 2000)
639    }
640    Log.info(`${this.TAG} pinchGestureEnd invoke X`);
641  }
642
643  private onPreviewClicked(): void {
644    Log.info(`${this.TAG} onPreviewClicked isShowtimeLapse= ${this.state.isShowtimeLapse}, state.mode= ${this.state.mode}`);
645    if (this.state.mode === 'PHOTO' && this.state.isShowtimeLapse) {
646      this.mAction.changeTimeLapse(false);
647      this.mAction.capture();
648    } else if (this.state.mode === 'VIDEO' && this.state.isShowtimeLapse) {
649      this.mAction.changeTimeLapse(false);
650      this.mAction.startRecording();
651    }
652    Log.info(`${this.TAG} onPreviewClicked invoke X`);
653  }
654
655  private swipeChangeMode(swipe: number): void {
656    Log.info(`${this.TAG} swipeChangeMode E`);
657    if (!this.state.modeChangeDone && this.state.modeIndex + swipe >= 0 &&
658      this.state.modeIndex + swipe <= this.modeArray.length - 1 && !this.state.isShowtimeLapse) {
659      this.mAction.swipeChangeMode(this.state.modeIndex + swipe);
660      this.mAction.swipeModeChangeDone(true);
661    }
662    Log.info(`${this.TAG} swipeChangeMode X`);
663  }
664
665  private onKeepScreen(data: KeepScreenData): void {
666    Log.info(`${this.TAG} onKeepScreen E`);
667    if (data) {
668      GlobalContext.get()
669        .getCameraWinClass()
670        .setKeepScreenOn(data.isKeepScreenOn)
671        .then((v) => {
672          Log.info('Succeeded in setting the screen to be always on. Data: ' + JSON.stringify(v));
673        })
674        .catch((err: BusinessError) => {
675          Log.error('Failed to set the screen to be always on. Cause: ' + JSON.stringify(err));
676        });
677    }
678    Log.info(`${this.TAG} onKeepScreen X`);
679  }
680
681  private windowSizeChange(data: ScreenSizeType): void {
682    if (this.screenSize != data) {
683      this.screenSize = data;
684      this.resetScreenSize(data);
685    }
686  }
687
688  private resetScreenSize(size: ScreenSizeType): void {
689    this.settingManager.setScreenHeight(size.height);
690    this.settingManager.setScreenWidth(size.width);
691    let xComponentSize = this.settingManager.getPreviewDisplaySize(this.state.mode);
692    Log.info(this.TAG + " PreviewArea xComponentSize = " + JSON.stringify(xComponentSize));
693    this.mAction.changeXComponentSize(xComponentSize.width, xComponentSize.height);
694  }
695
696  private async onScreenChange(isScreenOn: boolean) {
697    Log.info(`${this.TAG} onScreenChanged E isScreenOn: ${isScreenOn}`);
698    if (!isScreenOn) {
699      GlobalContext.get().setObject('keepCameraZoomRatio', true);
700      if (this.state.isShowPageView) {
701        this.mAction.hideSettingView();
702      }
703    }
704    Log.info(`${this.TAG} onScreenChanged X`);
705  }
706
707  build() {
708    Column() {
709      if (this.state.isShowPreview) {
710        Stack() {
711          XComponent({
712            id: '',
713            type: 'surface',
714            libraryname: '',
715            controller: GlobalContext.get().getXComponentController()
716          })
717            .onLoad(() => {
718              Log.end(Log.X_COMPONENT_LIFE);
719              Log.info(`${this.TAG} XComponent_onLoad`);
720              let surfaceId: number = GlobalContext.get().getXComponentController().getXComponentSurfaceId();
721              this.mAction.prepareSurface(surfaceId);
722              this.doCameraAction();
723            })
724            .width(this.state.xComponentWidth)
725            .height(this.state.xComponentHeight)
726            .animation({
727              duration: 100,
728              curve: Curve.Sharp,
729              delay: 0,
730              iterations: 1,
731              playMode: PlayMode.Normal
732            })
733
734          if (this.isSwitchBackground) {
735            Column() {
736            }
737            .width(this.state.xComponentWidth)
738            .height(this.state.xComponentHeight)
739            .backgroundColor('#000')
740            .opacity(this.switchBackgroundOpacity)
741          }
742
743          if (this.btnSwitch) {
744            Image($r('app.media.whitePicture'))
745              .width(this.state.xComponentWidth)
746              .height(this.state.xComponentHeight)
747              .syncLoad(false)
748              .scale({ x: this.scaleX, y: 1.0 })
749              .rotate({
750                x: 0,
751                y: 10,
752                z: 0,
753                angle: this.rotateAngle
754              })// .opacity(this.state.btnOpacity_first)
755              .onComplete(() => {
756              })
757          }
758
759          if (this.btnSwitchSec) {
760            Image($r('app.media.whitePicture'))
761              .width(this.state.xComponentWidth)
762              .height(this.state.xComponentHeight)
763              .syncLoad(false)
764              .scale({ x: this.scaleX, y: 1.0 })
765              .rotate({
766                x: 0,
767                y: 10,
768                z: 0,
769                angle: this.rotateAngleSec
770              })// .opacity(this.state.btnOpacity_sec)
771              .onComplete(() => {
772              })
773          }
774
775          if (this.state.isShowFlashBlack) {
776            ShowFlashBlack();
777          }
778
779          if (this.state.isShowZoomText && deviceInfo.deviceType !== 'default' && !this.state.isShowtimeLapse) {
780            Stack({ alignContent: Alignment.Top }) {
781              Column() {
782                Column() {
783                  ZoomText({ state: $state })
784                }
785                .width('100%')
786                .height('100%')
787              }
788              .width('100%')
789              .height('100%')
790              .alignItems(HorizontalAlign.Start)
791            }
792            .width('100%')
793            .height('96%')
794          }
795
796          if (this.state.isAssGridViewShow === '1' && this.state.mode !== 'MORE') {
797            AssistiveGridView();
798          }
799
800          if (this.state.isSmallVideoTimerVisible) {
801            Column() {
802              SmallVideoTimer();
803            }
804            .width('100%')
805            .height('100%')
806            .alignItems(HorizontalAlign.Start)
807          }
808          if (this.state.isBigVideoTimerVisible) {
809            Column() {
810              BigVideoTimer();
811            }
812            .width('100%')
813            .height('100%')
814            .alignItems(HorizontalAlign.Start)
815          }
816          if (this.state.isShowtimeLapse) {
817            Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
818              Column() {
819                TimeLapseView();
820              }.width('100%').height(150)
821            }.width('100%').height('100%')
822          }
823          if (this.state.showBlur) {
824            Column()
825              .width(this.isShowBlurSize.width)
826              .height(this.isShowBlurSize.height)
827              .backgroundColor(Color.Black)
828              .border({ width: { top: 0.5, bottom: 0.5 }, color: Color.Black })
829          }
830
831          Stack() {
832            if (this.state.isShowBigText) {
833              Stack({ alignContent: Alignment.BottomStart }) {
834                Column() {
835                  Column() {
836                    BigText()
837                  }
838                  .width('100%')
839                  .height('100%')
840                }
841                .width('100%')
842                .height('96vp')
843                .alignItems(HorizontalAlign.Start)
844              }
845              .width('100%')
846              .height('100%')
847            }
848          }
849          .width(this.screenSize.width > this.screenSize.height ? this.screenSize.height : this.screenSize.width)
850          .height(this.screenSize.height > (this.screenSize.width * 9 / 16) ? (this.screenSize.width * 9 / 16) :
851          this.screenSize.height)
852        }
853        .width('100%')
854        .height('100%')
855      }
856    }
857    .width(this.state.xComponentWidth)
858    .height(this.state.xComponentHeight)
859    .margin({ top: 0 })
860    .backgroundColor('#000')
861    .gesture(
862      GestureGroup(
863        GestureMode.Exclusive,
864        TapGesture({ fingers: 1, count: 1 })
865          .onAction(() => this.onPreviewClicked),
866        PinchGesture({ fingers: 2, distance: 1 })
867          .onActionStart(() => this.pinchGestureStart)
868          .onActionUpdate(() => this.pinchGestureUpdate)
869          .onActionEnd(() => this.pinchGestureEnd),
870        PanGesture({ fingers: 1, direction: PanDirection.Up, distance: 10 })
871          .onActionEnd(() => {
872            if (!this.state.isThirdPartyCall && !this.state.isFaCall) {
873              this.swipeChangeMode(1);
874            }
875          }),
876        PanGesture({ fingers: 1, direction: PanDirection.Down, distance: 10 })
877          .onActionEnd(() => {
878            if (!this.state.isThirdPartyCall && !this.state.isFaCall) {
879              this.swipeChangeMode(-1);
880            }
881          })
882      )
883    )
884  }
885}