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