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 display from '@ohos.display'; 17import { Action } from '@ohos/common/src/main/ets/default/redux/actions/Action'; 18import { CameraWorker } from '@ohos/common/src/main/ets/default/worker/CameraWorker'; 19import { ComponentPosition } from '@ohos/common/src/main/ets/default/utils/ComponentPosition'; 20import { Constants } from '@ohos/common/src/main/ets/default/utils/Constants'; 21import { EventBus } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBus'; 22import { EventBusManager } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBusManager'; 23import { Dispatch, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store'; 24import { getStore } from '@ohos/common/src/main/ets/default/redux/store'; 25import { Log } from '@ohos/common/src/main/ets/default/utils/Log'; 26import { MoreList } from '@ohos/common/src/main/ets/default/featurecommon/moreList/moreList'; 27import { 28 PersistType, 29 PreferencesService 30} from '@ohos/common/src/main/ets/default/featurecommon/preferences/PreferencesService'; 31import { RdbStoreManager } from '@ohos/common/src/main/ets/default/setting/storage/RdbStoreManager'; 32import { ScreenLockManager } from '@ohos/common/src/main/ets/default/featurecommon/screenlock/ScreenLockManager'; 33import { TabBarLand } from '@ohos/common/src/main/ets/default/featurecommon/tabbar/TabBarLand'; 34import { ZoomViewLand } from '@ohos/common/src/main/ets/default/featurecommon/zoomview/ZoomViewLand'; 35import { FootBarLand } from './FootBarLand'; 36import { PreviewAreaLand } from './PreviewAreaLand'; 37import { SettingView } from './SettingView'; 38import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 39import { ModeMap } from '../common/ModeMap'; 40import { GlobalContext } from '@ohos/common/src/main/ets/default/utils/GlobalContext'; 41import { CameraId } from '@ohos/common/src/main/ets/default/setting/settingitem/CameraId'; 42import { BusinessError } from '@ohos.base'; 43import ability from '@ohos.ability.ability'; 44 45const DEFAULT_FUNCTION = () => { 46} 47 48CameraWorker.getInstance(new ModeMap()); 49let mScreenLockManager = new ScreenLockManager(); 50 51PersistentStorage.PersistProp('storageCameraId', ''); 52 53class StateStruct { 54 permissionFlag: boolean = false; 55 mode: string = ''; 56 curMode: string = ''; 57 isBigVideoTimerVisible: boolean = false; 58 isSmallVideoTimerVisible: boolean = false; 59 videoState: string = ''; 60 isShowtimeLapse: boolean = false; 61 isShowMoreList: boolean = false; 62 isThirdPartyCall: boolean = false; 63 showZoomLabelValue: boolean = false; 64 cameraPosition: CameraId = CameraId.FRONT; 65 isShowPinch: boolean = false; 66 xComponentWidth: number = 0; 67 xComponentHeight: number = 0; 68 isShowPageView: boolean = false; 69 isInitiated: boolean = false; 70 initShowFlag: boolean = false; 71} 72 73class IndexDispatcher { 74 private mDispatch: Dispatch = (data) => data; 75 76 public setDispatch(dispatch: Dispatch) { 77 this.mDispatch = dispatch; 78 } 79 80 public setPermissionFlag(permissionFlag: boolean): void { 81 Log.info(`CameraApp setPermissionFlag: ${permissionFlag}`); 82 this.mDispatch(Action.setPermissionFlag(permissionFlag)); 83 } 84 85 public initAction(action: string): void { 86 this.mDispatch(Action.initAction(action)); 87 } 88 89 public initCameraPosition(cameraPosition: string): void { 90 this.mDispatch(Action.setCameraPosition(cameraPosition)); 91 } 92 93 public initMode(mode: string): void { 94 this.mDispatch(Action.initMode(mode)); 95 } 96 97 public changeTimeLapse(isShowtimeLapse: boolean): void { 98 this.mDispatch(Action.changeTimeLapse(isShowtimeLapse)); 99 } 100 101 public stopRecording(): void { 102 this.mDispatch(Action.stopRecording()); 103 this.mDispatch(Action.updateVideoState('beforeTakeVideo')); 104 this.mDispatch(Action.updateBigVideoTimerVisible(false)); 105 this.mDispatch(Action.updateSmallVideoTimerVisible(false)); 106 } 107 108 public resetRecordingTime(): void { 109 this.mDispatch(Action.updateRecordingTime(0)); 110 this.mDispatch(Action.updateRecordingTimeDisplay('00:00')); 111 } 112 113 public hideSettingView(): void { 114 this.mDispatch(Action.showSettingView(false)); 115 } 116 117 public updateModeIndex(index: number): void { 118 this.mDispatch(Action.updateModeIndex(index)); 119 } 120 121 public faCall(isFaCall: boolean): void { 122 this.mDispatch(Action.faCall(isFaCall)); 123 } 124 125 public updateInitShowFlag(initShowFlag: boolean): void { 126 this.mDispatch(Action.updateInitShowFlag(initShowFlag)) 127 } 128 129 public thirdPartyCall(isThirdPartyCall: boolean, action: string): void { 130 this.mDispatch(Action.thirdPartyCall(isThirdPartyCall, action)); 131 } 132 133 public resetZoomRatio(): void { 134 this.mDispatch(Action.changeZoomRatio(1)); 135 } 136} 137 138interface ScreenSizeType { 139 width: number 140 height: number 141} 142 143@Entry 144@Component 145struct Index { 146 appEventBus: EventBus = EventBusManager.getInstance().getEventBus(); 147 @State state: StateStruct = new StateStruct(); 148 @State screenSize: ScreenSizeType = { width: 0, height: 0 }; 149 protected mPreferencesService: PreferencesService = PreferencesService.getInstance(); 150 private TAG: string = '[IndexLand]:'; 151 private modeArray: Array<string> = ['PHOTO', 'VIDEO']; 152 private mAction: IndexDispatcher = new IndexDispatcher(); 153 154 aboutToAppear(): void { 155 Log.info(`${this.TAG} aboutToAppear E`); 156 let dbStore = RdbStoreManager.getInstance(); 157 dbStore.initRdbConfig(); 158 getStore().subscribe((state: OhCombinedState) => { 159 this.state = { 160 permissionFlag: state.contextReducer.permissionFlag, 161 mode: state.modeReducer.mode, 162 curMode: state.modeReducer.curMode, 163 isBigVideoTimerVisible: state.recordReducer.isBigVideoTimerVisible, 164 isSmallVideoTimerVisible: state.recordReducer.isSmallVideoTimerVisible, 165 videoState: state.recordReducer.videoState, 166 isShowtimeLapse: state.settingReducer.isShowtimeLapse, 167 isShowMoreList: state.modeReducer.isShowMoreList, 168 isThirdPartyCall: state.contextReducer.isThirdPartyCall, 169 showZoomLabelValue: state.zoomReducer.showZoomLabelValue, 170 cameraPosition: state.cameraReducer.cameraPosition, 171 isShowPinch: state.zoomReducer.isShowPinch, 172 xComponentWidth: state.previewReducer.xComponentWidth, 173 xComponentHeight: state.previewReducer.xComponentHeight, 174 isShowPageView: state.settingReducer.isShowSettingView, 175 isInitiated: state.modeReducer.isInitiated, 176 initShowFlag: state.contextReducer.initShowFlag 177 }; 178 }, (dispatch: Dispatch) => { 179 this.mAction.setDispatch(dispatch); 180 }) 181 182 mScreenLockManager.init(); 183 184 if (!this.state.permissionFlag) { 185 let permissionList: Array<Permissions> = [ 186 "ohos.permission.MEDIA_LOCATION", 187 "ohos.permission.READ_IMAGEVIDEO", 188 "ohos.permission.WRITE_IMAGEVIDEO", 189 "ohos.permission.CAMERA", 190 "ohos.permission.MICROPHONE", 191 "ohos.permission.DISTRIBUTED_DATASYNC", 192 "ohos.permission.LOCATION", 193 "ohos.permission.LOCATION_IN_BACKGROUND", 194 "ohos.permission.APPROXIMATELY_LOCATION" 195 ]; 196 Log.info(`${this.TAG} permissions need to require from user: ${JSON.stringify(permissionList)}`); 197 let atManager = abilityAccessCtrl.createAtManager(); 198 try { 199 atManager.requestPermissionsFromUser(GlobalContext.get().getCameraAbilityContext(), permissionList) 200 .then((data) => { 201 Log.info(`${this.TAG} data permissions: ${JSON.stringify(data.permissions)}`); 202 Log.info(`${this.TAG} data authResult: ${JSON.stringify(data.authResults)}`); 203 let sum = 0; 204 for (let i = 0; i < data.authResults.length; i++) { 205 sum += data.authResults[i]; 206 } 207 if (sum >= 0) { 208 GlobalContext.get().setObject('permissionFlag', true); 209 this.mAction.setPermissionFlag(true); 210 } else { 211 GlobalContext.get().setObject('permissionFlag', false); 212 this.mAction.setPermissionFlag(false); 213 } 214 Log.info(`${this.TAG} request permissions result: ${GlobalContext.get().getT<boolean>('permissionFlag')}`); 215 }, (err: BusinessError) => { 216 Log.error(`${this.TAG} Failed to start ability err code: ${err.code}`); 217 }); 218 } catch (error) { 219 Log.info(`${this.TAG} catch error: ${JSON.stringify(error)}`); 220 } 221 } 222 223 if (GlobalContext.get().getCameraFormParam() != undefined) { 224 this.mAction.initAction(GlobalContext.get().getCameraFormParam().action); 225 this.mAction.initMode(GlobalContext.get().getCameraFormParam().mode); 226 GlobalContext.get().setCameraFormParam(undefined); 227 } 228 229 GlobalContext.get().setObject('stopCameraRecording', () => { 230 this.stopCameraRecording(); 231 }) 232 233 GlobalContext.get().setObject('resetZoomRatio', () => { 234 this.mAction.resetZoomRatio(); 235 }) 236 237 if (AppStorage.Has(Constants.APP_KEY_WINDOW_SIZE)) { 238 const screenSizeData: ScreenSizeType | undefined = AppStorage.Get(Constants.APP_KEY_WINDOW_SIZE); 239 if (screenSizeData) { 240 this.screenSize = screenSizeData; 241 } 242 } else { 243 display.getDefaultDisplay().then((dis) => { 244 this.screenSize.width = px2vp(dis.width); 245 this.screenSize.height = px2vp(dis.height); 246 }) 247 } 248 249 if (!this.state.isInitiated) { 250 let initIndex = this.mPreferencesService.getModeValue(PersistType.FOR_AWHILE, 1); 251 Log.info(`${this.TAG} initModeIndex: ${initIndex}`); 252 this.mAction.initMode(this.modeArray[initIndex]); 253 this.mAction.updateModeIndex(initIndex); 254 } 255 256 Log.info(`${this.TAG} aboutToAppear X`); 257 } 258 259 onPageShow(): void { 260 Log.info(`${this.TAG} onPageShow E this.permissionFlag: ${this.state.permissionFlag} 261 globalThis.permissionFlag: ${GlobalContext.get().getT<boolean>('permissionFlag')}`); 262 this.mAction.setPermissionFlag(GlobalContext.get().getT<boolean>('permissionFlag')); 263 let cameraId = AppStorage.Get<string>('storageCameraId'); 264 if (cameraId) this.mAction.initCameraPosition(cameraId); 265 Log.info(`${this.TAG} initCameraPosition ${cameraId}`); 266 this.mAction.resetRecordingTime(); 267 Log.info(`${this.TAG} onPageShow X`); 268 } 269 270 onBackPress(): boolean { 271 Log.info(`${this.TAG} onBackPress E`); 272 if (this.state.isShowPageView) { 273 this.mAction.hideSettingView(); 274 return true; 275 } else if (this.state.isShowtimeLapse) { 276 this.mAction.changeTimeLapse(false); 277 return true; 278 } else if (this.state.isThirdPartyCall) { 279 this.terminateSelfWithResult(); 280 return true; 281 } else { 282 if (this.state.videoState === 'startTakeVideo' || this.state.videoState === 'pauseTakeVideo') { 283 this.mAction.stopRecording(); 284 return true; 285 } 286 Log.info(`${this.TAG} onBackPress X`); 287 return false; 288 } 289 } 290 291 onPageHide(): void { 292 Log.info(`${this.TAG} onPageHide E`); 293 this.stopCameraRecording(); 294 Log.info(`${this.TAG} onPageHide X`); 295 } 296 297 public stopCameraRecording(): void { 298 Log.info(`${this.TAG} stopCameraRecording E`); 299 if (this.state.isShowtimeLapse) { 300 this.mAction.changeTimeLapse(false); 301 } 302 if (this.state.videoState === 'startTakeVideo' || this.state.videoState === 'pauseTakeVideo') { 303 this.mAction.stopRecording(); 304 } 305 Log.info(`${this.TAG} stopCameraRecording X`); 306 } 307 308 terminateSelfWithResult(): void { 309 Log.info(`${this.TAG} terminateSelfWithResult start`); 310 let abilityResult: ability.AbilityResult = { 311 resultCode: 200, 312 want: { 313 parameters: { 314 resourceUri: "", 315 width: "", 316 height: "" 317 }, 318 bundleName: "com.ohos.camera", 319 abilityName: "com.ohos.camera.MainAbility" 320 } 321 }; 322 323 GlobalContext.get().getCameraAbilityContext().terminateSelfWithResult(abilityResult, (error: BusinessError, data: Object) => { 324 if (error) { 325 Log.error(`${this.TAG} Operation failed. Cause: ${error}`); 326 return; 327 } 328 Log.info(`${this.TAG} Operation succeeded: ${data}`); 329 }); 330 } 331 332 private onBackClicked(): void { 333 Log.info(`${this.TAG} onBackClicked E`); 334 this.terminateSelfWithResult(); 335 } 336 337 private componentVisibility(condition: boolean): Visibility { 338 return (!this.state.isShowtimeLapse && this.state.initShowFlag && condition) ? Visibility.Visible : Visibility.Hidden 339 } 340 341 build() { 342 Stack({ alignContent: Alignment.TopStart }) { 343 Column() { 344 PreviewAreaLand({ screenSize: $screenSize }) 345 } 346 .position(this.state.isThirdPartyCall ? ComponentPosition.previewTabletPosition(this.screenSize.width, this.screenSize.height, 347 this.state.xComponentWidth, this.state.xComponentHeight) : ComponentPosition.previewPosition(this.screenSize.width, this.screenSize.height, 348 this.state.xComponentWidth, this.state.xComponentHeight)) 349 350 Column() { 351 if ((this.state.mode === "PHOTO" || this.state.mode === "VIDEO") && this.state.cameraPosition !== 'FRONT') { 352 ZoomViewLand() 353 } else { 354 Column() { 355 }.width(82).margin({ right: '20vp' }) 356 } 357 }.zIndex(2).height('100%') 358 .position(this.state.isThirdPartyCall ? { 359 x: 984, 360 y: 0 361 } : ComponentPosition.zoomViewPosition(this.screenSize.width, this.screenSize.height, 362 this.state.xComponentWidth, this.state.xComponentHeight, this.state.videoState)) 363 .visibility(this.componentVisibility(!this.state.isShowPinch)) 364 365 Column() { 366 FootBarLand({ screenSize: $screenSize }) 367 }.zIndex(2).height('100%') 368 .position(this.state.isThirdPartyCall ? { 369 x: 1124, 370 y: 0 371 } : ComponentPosition.footBarPosition(this.screenSize.width, this.screenSize.height, 372 this.state.xComponentWidth, this.state.xComponentHeight)) 373 .visibility(this.componentVisibility(this.state.showZoomLabelValue)) 374 375 Column() { 376 TabBarLand({ onBackClicked: () => this.onBackClicked(), screenSize: $screenSize }) 377 }.zIndex(3) 378 .visibility(this.componentVisibility(this.state.videoState === "beforeTakeVideo" && this.state.showZoomLabelValue)) 379 .position(this.state.isThirdPartyCall ? { 380 x: 0, 381 y: 44 382 } : ComponentPosition.tabBarPosition(this.screenSize.width, this.screenSize.height, 383 this.state.xComponentWidth, this.state.xComponentHeight)) 384 .height(712) 385 386 if (this.state.isShowMoreList) { 387 Column() { 388 MoreList() 389 }.zIndex(1).height('100%').width('100%') 390 .visibility(this.componentVisibility(this.state.showZoomLabelValue)) 391 } 392 if (this.state.isShowPageView) { 393 SettingView().width('100%').height('100%').zIndex(4) 394 } 395 }.width('100%').height('100%').backgroundColor('#000') 396 } 397}