1/* 2 * Copyright (c) 2024 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 photoAccessHelper from '@ohos.file.photoAccessHelper'; 17import { fileIo as fs, fileUri } from '@kit.CoreFileKit'; 18import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit'; 19import { bundleManager } from '@kit.AbilityKit'; 20 21const FILTER_MEDIA_TYPE_ALL = 'FILTER_MEDIA_TYPE_ALL'; 22const FILTER_MEDIA_TYPE_IMAGE = 'FILTER_MEDIA_TYPE_IMAGE'; 23const FILTER_MEDIA_TYPE_VIDEO = 'FILTER_MEDIA_TYPE_VIDEO'; 24const FILTER_MEDIA_TYPE_IMAGE_MOVING_PHOTO = 'FILTER_MEDIA_TYPE_IMAGE_MOVING_PHOTO'; 25 26@Component 27export struct PhotoPickerComponent { 28 pickerOptions?: PickerOptions | undefined; 29 onSelect?: (uri: string) => void; 30 onDeselect?: (uri: string) => void; 31 onItemClicked?: (itemInfo: ItemInfo, clickType: ClickType) => boolean; 32 onEnterPhotoBrowser?: (photoBrowserInfo: PhotoBrowserInfo) => boolean; 33 onExitPhotoBrowser?: (photoBrowserInfo: PhotoBrowserInfo) => boolean; 34 onPickerControllerReady?: () => void; 35 onPhotoBrowserChanged?: (browserItemInfo: BaseItemInfo) => boolean; 36 onSelectedItemsDeleted?: ItemsDeletedCallback; 37 onExceedMaxSelected?: ExceedMaxSelectedCallback; 38 onCurrentAlbumDeleted?: CurrentAlbumDeletedCallback; 39 onVideoPlayStateChanged?: VideoPlayStateChangedCallback; 40 @ObjectLink @Watch('onChanged') pickerController: PickerController; 41 private proxy: UIExtensionProxy | undefined; 42 @State revokeIndex = 0; 43 44 private onChanged(): void { 45 if (!this.proxy) { 46 return; 47 } 48 let data = this.pickerController?.data; 49 if (data?.has('SET_SELECTED_URIS')) { 50 this.proxy.send({ 'selectUris': data?.get('SET_SELECTED_URIS') as Array<string> }); 51 console.info('PhotoPickerComponent onChanged: SET_SELECTED_URIS'); 52 } else if (data?.has('SET_ALBUM_URI')) { 53 this.proxy.send({ 'albumUri': data?.get('SET_ALBUM_URI') as string }); 54 console.info('PhotoPickerComponent onChanged: SET_ALBUM_URI'); 55 } else if (data?.has('SET_MAX_SELECT_COUNT')) { 56 this.onSetMaxSelectCount(data); 57 } else if (data?.has('SET_PHOTO_BROWSER_ITEM')) { 58 this.onSetPhotoBrowserItem(data); 59 } else { 60 this.otherOnChange(data); 61 } 62 } 63 64 private otherOnChange(data?: Map<string, Object>) { 65 if (data?.has('EXIT_PHOTO_BROWSER')) { 66 this.handleExitPhotoBrowser(); 67 } else if (data?.has('SET_PHOTO_BROWSER_UI_ELEMENT_VISIBILITY')) { 68 this.onSetPhotoBrowserUIElementVisibility(data); 69 } else if (data?.has('CREATE_URI')) { 70 this.onCreateUri(data); 71 console.info('PhotoPickerComponent onChanged: CREATE_URI'); 72 } else if (data?.has('REPLACE_URI')) { 73 this.onReplaceUri(data); 74 console.info('PhotoPickerComponent onChanged: REPLACE_URI'); 75 } else if (data?.has('SAVE_TRUSTED_PHOTO_ASSETS')) { 76 this.onSaveTrustedPhotoAssets(data); 77 console.info('PhotoPickerComponent onChanged: SAVE_REPLACE_PHOTO_ASSETS'); 78 } else { 79 console.info('PhotoPickerComponent onChanged: other case'); 80 } 81 } 82 83 private onSetMaxSelectCount(data?: Map<string, Object>): void { 84 let maxSelected: MaxSelected = data?.get('SET_MAX_SELECT_COUNT') as MaxSelected; 85 let map: Map<MaxCountType, number> | undefined = maxSelected?.data; 86 this.proxy.send({ 87 'totalCount': map?.get(MaxCountType.TOTAL_MAX_COUNT), 88 'photoCount': map?.get(MaxCountType.PHOTO_MAX_COUNT), 89 'videoCount': map?.get(MaxCountType.VIDEO_MAX_COUNT) 90 }); 91 console.info('PhotoPickerComponent onChanged: SET_MAX_SELECT_COUNT'); 92 } 93 94 private onSetPhotoBrowserItem(data?: Map<string, Object>): void { 95 let photoBrowserRangeInfo: PhotoBrowserRangeInfo = data?.get('SET_PHOTO_BROWSER_ITEM') as PhotoBrowserRangeInfo; 96 this.proxy?.send({ 97 'itemUri': photoBrowserRangeInfo?.uri, 98 'photoBrowserRange': photoBrowserRangeInfo?.photoBrowserRange 99 }); 100 console.info('PhotoPickerComponent onChanged: SET_PHOTO_BROWSER_ITEM'); 101 } 102 103 private handleExitPhotoBrowser(): void { 104 this.proxy.send({ 'exitPhotoBrowser': true }); 105 console.info('PhotoPickerComponent onChanged: EXIT_PHOTO_BROWSER'); 106 } 107 108 private onSetPhotoBrowserUIElementVisibility(data?: Map<string, Object>): void { 109 let photoBrowserUIElementVisibility: PhotoBrowserUIElementVisibility = 110 data?.get('SET_PHOTO_BROWSER_UI_ELEMENT_VISIBILITY') as PhotoBrowserUIElementVisibility; 111 this.proxy?.send({ 112 'elements': photoBrowserUIElementVisibility?.elements, 113 'isVisible': photoBrowserUIElementVisibility?.isVisible 114 }); 115 console.info('PhotoPickerComponent onChanged: SET_PHOTO_BROWSER_UI_ELEMENT_VISIBILITY'); 116 } 117 118 private onCreateUri(data?: Map<string, Object>): void { 119 let array = data?.get('CREATE_URI') as Array<Object>; 120 this.proxy?.send({ 121 selectedMediaUri: array[0], 122 createUri: array[1], 123 date: array[2] 124 }); 125 console.info('PhotoPickerComponent onChanged CREATE_URI'); 126 } 127 128 private onReplaceUri(data?: Map<string, Object>): void { 129 let array = data?.get('REPLACE_URI') as Array<Object>; 130 this.proxy?.send({ 131 oriUri: array[0], 132 replaceUri: array[1], 133 date: array[2] 134 }); 135 console.info('PhotoPickerComponent onChanged REPLACE_URI'); 136 } 137 138 private onSaveTrustedPhotoAssets(data?: Map<string, Object>): void { 139 let array: Array<object> = data?.get('SAVE_TRUSTED_PHOTO_ASSETS') as Array<object>; 140 this.proxy?.send({ 141 replaceUris: array[0], 142 config: array[1], 143 saveMode: array[2], 144 appName: array[3], 145 date: array[4] 146 }); 147 console.info('PhotoPickerComponent onChanged SAVE_REPLACE_PHOTO_ASSETS'); 148 } 149 150 build() { 151 Row() { 152 Column() { 153 SecurityUIExtensionComponent({ 154 parameters: { 155 errorRevokeIndex: this.revokeIndex, 156 "ability.want.params.uiExtensionTargetType": "photoPicker", 157 uri: "multipleselect", 158 targetPage: "photoPage", 159 filterMediaType: this.convertMIMETypeToFilterType(this.pickerOptions?.MIMEType), 160 maxSelectNumber: this.pickerOptions?.maxSelectNumber as number, 161 isPhotoTakingSupported: this.pickerOptions?.isPhotoTakingSupported as boolean, 162 isEditSupported: false, 163 recommendationOptions: this.pickerOptions?.recommendationOptions as photoAccessHelper.RecommendationOptions, 164 preselectedUri: this.pickerOptions?.preselectedUris as Array<string>, 165 isFromPickerView: true, 166 isNeedActionBar: false, 167 isNeedSelectBar: false, 168 isSearchSupported: this.pickerOptions?.isSearchSupported as boolean, 169 checkBoxColor: this.pickerOptions?.checkBoxColor as string, 170 backgroundColor: this.pickerOptions?.backgroundColor as string, 171 checkboxTextColor: this.pickerOptions?.checkboxTextColor as string, 172 photoBrowserBackgroundColorMode: this.pickerOptions?.photoBrowserBackgroundColorMode as PickerColorMode, 173 isRepeatSelectSupported: this.pickerOptions?.isRepeatSelectSupported as boolean, 174 maxSelectedReminderMode: this.pickerOptions?.maxSelectedReminderMode as ReminderMode, 175 orientation: this.pickerOptions?.orientation as PickerOrientation, 176 selectMode: this.pickerOptions?.selectMode as SelectMode, 177 maxPhotoSelectNumber: this.pickerOptions?.maxPhotoSelectNumber as number, 178 maxVideoSelectNumber: this.pickerOptions?.maxVideoSelectNumber as number, 179 isOnItemClickedSet: this.onItemClicked ? true : false, 180 isPreviewForSingleSelectionSupported: this.pickerOptions?.isPreviewForSingleSelectionSupported as boolean, 181 singleSelectionMode: this.pickerOptions?.singleSelectionMode as number, 182 isSlidingSelectionSupported: this.pickerOptions?.isSlidingSelectionSupported as boolean, 183 photoBrowserCheckboxPosition: this.pickerOptions?.photoBrowserCheckboxPosition as [number, number], 184 gridMargin: this.pickerOptions?.gridMargin as Margin, 185 photoBrowserMargin: this.pickerOptions?.photoBrowserMargin as Margin 186 } 187 }) 188 .height('100%') 189 .width('100%') 190 .onRemoteReady((proxy) => { 191 this.proxy = proxy; 192 console.info('PhotoPickerComponent onRemoteReady'); 193 }) 194 .onReceive((data) => { 195 let wantParam: Record<string, Object> = data as Record<string, Object>; 196 this.handleOnReceive(wantParam); 197 }) 198 .onError((error) => { 199 console.info('PhotoPickerComponent onError: ' + JSON.stringify(error)); 200 console.info('PhotoPickerComponent revokeIndex: ' + this.revokeIndex); 201 if (error.code === 100014 && this.revokeIndex < 3) { 202 this.revokeIndex++; 203 } 204 }); 205 } 206 .width('100%') 207 } 208 .height('100%') 209 } 210 211 private handleOnReceive(wantParam: Record<string, Object>): void { 212 let dataType = wantParam['dataType'] as string; 213 console.info('PhotoPickerComponent onReceive: dataType = ' + dataType); 214 if (dataType === 'selectOrDeselect') { 215 this.handleSelectOrDeselect(wantParam); 216 } else if (dataType === 'itemClick') { 217 this.handleItemClick(wantParam); 218 } else if (dataType === 'onPhotoBrowserStateChanged') { 219 this.handleEnterOrExitPhotoBrowser(wantParam); 220 } else if (dataType === 'remoteReady') { 221 if (this.onPickerControllerReady) { 222 this.onPickerControllerReady(); 223 console.info('PhotoPickerComponent onReceive: onPickerControllerReady'); 224 } 225 } else if (dataType === 'onPhotoBrowserChanged') { 226 this.handlePhotoBrowserChange(wantParam); 227 } else if (dataType === 'onVideoPlayStateChanged') { 228 this.handleVideoPlayStateChange(wantParam) 229 } else if (dataType === 'replaceCallback') { 230 this.handleReplaceCallback(wantParam); 231 } else if (dataType === 'createCallback') { 232 this.handleCreateCallback(wantParam); 233 } else if (dataType === 'saveCallback') { 234 this.handleSaveCallback(wantParam); 235 } else if (dataType === 'onBackground') { 236 console.info('PhotoPickerComponent onReceive: onBackground'); 237 this.revokeIndex = 0; 238 } else { 239 this.handleOtherOnReceive(wantParam); 240 console.info('PhotoPickerComponent onReceive: other case'); 241 } 242 console.info('PhotoPickerComponent onReceive' + this.pickerController.encrypt(JSON.stringify(wantParam))); 243 } 244 245 private handleOtherOnReceive(wantParam: Record<string, Object>): void { 246 let dataType = wantParam.dataType as string; 247 if (dataType === 'exceedMaxSelected') { 248 if (this.onExceedMaxSelected) { 249 this.onExceedMaxSelected(wantParam.maxCountType as MaxCountType); 250 } 251 } else if (dataType === 'selectedItemsDeleted') { 252 if (this.onSelectedItemsDeleted) { 253 this.onSelectedItemsDeleted(wantParam.selectedItemInfos as Array<BaseItemInfo>); 254 } 255 } else if (dataType === 'currentAlbumDeleted') { 256 if (this.onCurrentAlbumDeleted) { 257 this.onCurrentAlbumDeleted(); 258 } 259 } else { 260 console.info('PhotoPickerComponent onReceive: other case'); 261 } 262 } 263 264 private handleSelectOrDeselect(wantParam: Record<string, Object>): void { 265 let isSelect: boolean = wantParam['isSelect'] as boolean; 266 if (isSelect) { 267 if (this.onSelect) { 268 this.onSelect(wantParam['select-item-list'] as string); 269 console.info('PhotoPickerComponent onReceive: onSelect'); 270 } 271 } else { 272 if (this.onDeselect) { 273 this.onDeselect(wantParam['select-item-list'] as string); 274 console.info('PhotoPickerComponent onReceive: onDeselect'); 275 } 276 } 277 } 278 279 private handleItemClick(wantParam: Record<string, Object>): void { 280 if (this.onItemClicked) { 281 let clickType: ClickType = ClickType.SELECTED; 282 let type = wantParam['clickType'] as string; 283 if (type === 'select') { 284 clickType = ClickType.SELECTED; 285 } else if (type === 'deselect') { 286 clickType = ClickType.DESELECTED; 287 } else { 288 console.info('PhotoPickerComponent onReceive: other clickType'); 289 } 290 let itemInfo: ItemInfo = new ItemInfo(); 291 let itemType: string = wantParam['itemType'] as string; 292 if (itemType === 'thumbnail') { 293 itemInfo.itemType = ItemType.THUMBNAIL; 294 } else if (itemType === 'camera') { 295 itemInfo.itemType = ItemType.CAMERA; 296 } else { 297 console.info('PhotoPickerComponent onReceive: other itemType'); 298 } 299 itemInfo.uri = wantParam['uri'] as string; 300 itemInfo.mimeType = wantParam['mimeType'] as string; 301 itemInfo.width = wantParam['width'] as number; 302 itemInfo.height = wantParam['height'] as number; 303 itemInfo.size = wantParam['size'] as number; 304 itemInfo.duration = wantParam['duration'] as number; 305 let result: boolean = this.onItemClicked(itemInfo, clickType); 306 console.info('PhotoPickerComponent onReceive: onItemClicked = ' + clickType); 307 if (this.proxy) { 308 if (itemType === 'thumbnail' && clickType === ClickType.SELECTED) { 309 this.proxy.send({ 'clickConfirm': itemInfo.uri, 'isConfirm': result }); 310 console.info('PhotoPickerComponent onReceive: click confirm: uri = ' + 311 this.pickerController.encrypt(itemInfo.uri) + 'isConfirm = ' + result); 312 } 313 if (itemType === 'camera') { 314 this.proxy.send({ 'enterCamera': result }); 315 console.info('PhotoPickerComponent onReceive: enter camera ' + result); 316 } 317 } 318 } 319 } 320 321 private handleEnterOrExitPhotoBrowser(wantParam: Record<string, Object>): void { 322 let isEnter: boolean = wantParam['isEnter'] as boolean; 323 let photoBrowserInfo: PhotoBrowserInfo = new PhotoBrowserInfo(); 324 photoBrowserInfo.animatorParams = new AnimatorParams(); 325 photoBrowserInfo.animatorParams.duration = wantParam['duration'] as number; 326 photoBrowserInfo.animatorParams.curve = wantParam['curve'] as Curve | ICurve | string; 327 if (isEnter) { 328 if (this.onEnterPhotoBrowser) { 329 this.onEnterPhotoBrowser(photoBrowserInfo); 330 } 331 } else { 332 if (this.onExitPhotoBrowser) { 333 this.onExitPhotoBrowser(photoBrowserInfo); 334 } 335 } 336 console.info('PhotoPickerComponent onReceive: onPhotoBrowserStateChanged = ' + isEnter); 337 } 338 339 private handlePhotoBrowserChange(wantParam: Record<string, Object>): void { 340 let browserItemInfo: BaseItemInfo = new BaseItemInfo(); 341 browserItemInfo.uri = wantParam['uri'] as string; 342 if (this.onPhotoBrowserChanged) { 343 this.onPhotoBrowserChanged(browserItemInfo); 344 } 345 console.info('PhotoPickerComponent onReceive: onPhotoBrowserChanged = ' + 346 this.pickerController.encrypt(browserItemInfo.uri)); 347 } 348 349 private handleVideoPlayStateChange(wantParam: Record<string, Object>): void { 350 if (this.onVideoPlayStateChanged) { 351 this.onVideoPlayStateChanged(wantParam.state as VideoPlayerState) 352 } 353 console.info('PhotoPickerComponent onReceive: onVideoPlayStateChanged = ' + JSON.stringify(wantParam)); 354 } 355 356 private handleCreateCallback(wantParam: Record<string, Object>): void { 357 this.pickerController.actionCreateCallback(wantParam['grantUri'] as string, wantParam['date'] as number, 358 wantParam['code'] as number, wantParam['message'] as string); 359 console.info('PhotoPickerComponent onReceive: handleCreateCallback'); 360 } 361 362 private handleReplaceCallback(wantParam: Record<string, Object>): void { 363 this.pickerController.actionReplaceCallback(wantParam['date'] as number, 364 { 'name': '', 'code': wantParam['code'] as number, 'message': wantParam['message'] as string }); 365 console.info('PhotoPickerComponent onReceive: handleReplaceCallback'); 366 } 367 368 private handleSaveCallback(wantParam: Record<string, Object>): void { 369 this.pickerController.actionSaveCallback(wantParam['date'] as number, 370 { 'name': '', 'code': wantParam['code'] as number, 'message': wantParam['error'] as string }, 371 wantParam['data'] as Array<string>); 372 console.info('PhotoPickerComponent onReceive: handleSaveCallback'); 373 } 374 375 private convertMIMETypeToFilterType(mimeType: photoAccessHelper.PhotoViewMIMETypes): string { 376 let filterType: string; 377 if (mimeType === photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE) { 378 filterType = FILTER_MEDIA_TYPE_IMAGE; 379 } else if (mimeType === photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE) { 380 filterType = FILTER_MEDIA_TYPE_VIDEO; 381 } else if (mimeType === photoAccessHelper.PhotoViewMIMETypes.MOVING_PHOTO_IMAGE_TYPE) { 382 filterType = FILTER_MEDIA_TYPE_IMAGE_MOVING_PHOTO; 383 } else { 384 filterType = FILTER_MEDIA_TYPE_ALL; 385 } 386 console.info('PhotoPickerComponent convertMIMETypeToFilterType: ' + JSON.stringify(filterType)); 387 return filterType; 388 } 389} 390 391export type ItemsDeletedCallback = (baseItemInfos: Array<BaseItemInfo>) => void; 392 393export type ExceedMaxSelectedCallback = (exceedMaxCountType: MaxCountType) => void; 394 395export type CurrentAlbumDeletedCallback = () => void; 396 397export type VideoPlayStateChanged = (state: VideoPlayerState) => {} void; 398 399@Observed 400export class PickerController { 401 data?: Map<string, Object>; 402 replaceCallbackMap: Map<number, Object> = new Map<number, Object>(); 403 saveCallbackMap: Map<number, Object> = new Map<number, Object>(); 404 createCallbackMap: Map<number, Object> = new Map<number, Object>(); 405 406 setData(type: DataType, data: Object) { 407 if (data === undefined) { 408 return; 409 } 410 if (type === DataType.SET_SELECTED_URIS) { 411 if (data instanceof Array) { 412 let uriLists: Array<string> = data as Array<string>; 413 if (uriLists) { 414 this.data = new Map([['SET_SELECTED_URIS', [...uriLists]]]); 415 console.info('PhotoPickerComponent SET_SELECTED_URIS' + this.encrypt(JSON.stringify(uriLists))); 416 } 417 } 418 } else if (type === DataType.SET_ALBUM_URI) { 419 let albumUri: string = data as string; 420 if (albumUri !== undefined) { 421 this.data = new Map([['SET_ALBUM_URI', albumUri]]); 422 console.info('PhotoPickerComponent SET_ALBUM_URI' + this.encrypt(JSON.stringify(albumUri))); 423 } 424 } else { 425 console.info('PhotoPickerComponent setData: other case'); 426 } 427 } 428 429 setMaxSelected(maxSelected: MaxSelected) { 430 if (maxSelected) { 431 this.data = new Map([['SET_MAX_SELECT_COUNT', maxSelected]]); 432 console.info('PhotoPickerComponent SET_MAX_SELECT_COUNT' + JSON.stringify(maxSelected)); 433 } 434 } 435 436 setPhotoBrowserItem(uri: string, photoBrowserRange?: PhotoBrowserRange) { 437 let photoBrowserRangeInfo: PhotoBrowserRangeInfo = new PhotoBrowserRangeInfo(); 438 photoBrowserRangeInfo.uri = uri; 439 let newPhotoBrowserRange = photoBrowserRange ? photoBrowserRange : PhotoBrowserRange.ALL; 440 photoBrowserRangeInfo.photoBrowserRange = newPhotoBrowserRange; 441 this.data = new Map([['SET_PHOTO_BROWSER_ITEM', photoBrowserRangeInfo]]); 442 console.info('PhotoPickerComponent SET_PHOTO_BROWSER_ITEM' + this.encrypt(JSON.stringify(photoBrowserRangeInfo))); 443 } 444 445 exitPhotoBrowser() { 446 this.data = new Map([['EXIT_PHOTO_BROWSER', true]]); 447 console.info('PhotoPickerComponent EXIT_PHOTO_BROWSER'); 448 } 449 450 setPhotoBrowserUIElementVisibility(elements: Array<PhotoBrowserUIElement>, isVisible?: boolean) { 451 let photoBrowserUIElementVisibility: PhotoBrowserUIElementVisibility = new PhotoBrowserUIElementVisibility(); 452 photoBrowserUIElementVisibility.elements = elements; 453 photoBrowserUIElementVisibility.isVisible = isVisible; 454 this.data = new Map([['SET_PHOTO_BROWSER_UI_ELEMENT_VISIBILITY', photoBrowserUIElementVisibility]]); 455 console.info('PhotoPickerComponent SET_PHOTO_BROWSER_UI_ELEMENT_VISIBILITY ' + 456 JSON.stringify(photoBrowserUIElementVisibility)); 457 } 458 459 private async getAppName(): Promise<string> { 460 let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_ABILITY | // for appName 461 bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_HAP_MODULE | // for appName 462 bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO | // for appId 463 bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION; // for appInfo 464 let bundleInfo = bundleManager.getBundleInfoForSelfSync(flags); 465 let labelId = bundleInfo.appInfo.labelId; 466 let appName = ''; 467 let moduleName = ''; 468 for (let hapInfo of bundleInfo.hapModulesInfo) { 469 if (labelId === hapInfo.labelId) { 470 moduleName = hapInfo.name; 471 } 472 } 473 appName = await getContext(this).createModuleContext(moduleName).resourceManager.getStringValue(labelId); 474 return appName; 475 } 476 477 replacePhotoPickerPreview(selectedMediaUri: string, replaceUri: string, callback: AsyncCallback<void>) { 478 try { 479 let fd = fs.openSync(replaceUri).fd; 480 fs.close(fd); 481 } catch (err) { 482 callback({'code': 13900002, 'message': 'No such file', name: ''}); 483 return; 484 } 485 let date = Math.random(); 486 this.data = new Map([['CREATE_URI', [selectedMediaUri, replaceUri, date]]]); 487 this.createCallbackMap.set(date, (grantUri: string, code: number, message: string) => { 488 if (code !== 0) { 489 callback({ 'name': '', 'code': code, 'message': message }); 490 return; 491 } 492 let createFd = 0; 493 let replaceFd = 0; 494 try { 495 createFd = fs.openSync(grantUri, fs.OpenMode.READ_WRITE).fd; 496 replaceFd = fs.openSync(replaceUri, fs.OpenMode.READ_ONLY).fd; 497 fs.copyFileSync(replaceFd, createFd); 498 this.data = new Map([['REPLACE_URI', [selectedMediaUri, grantUri, date]]]); 499 this.replaceCallbackMap.set(date, callback); 500 } catch (err) { 501 callback({ 'code': 14000011, 'message': 'System inner fail', name: '' }); 502 } finally { 503 fs.close(createFd); 504 fs.close(replaceFd); 505 } 506 }) 507 } 508 509 saveTrustedPhotoAssets(selectedMediaUris: Array<string>, callback: AsyncCallback<Array<string>>, 510 config?: Array<photoAccessHelper.PhotoCreationConfig>, saveMode?: SaveMode) { 511 if (!selectedMediaUris || selectedMediaUris.length === 0) { 512 callback({'code': 14000002, 'message': 'Invalid URI', name: ''}, []); 513 return; 514 } 515 this.getAppName().then((appName: string)=>{ 516 let date = Math.random(); 517 this.data = new Map([['SAVE_TRUSTED_PHOTO_ASSETS', [selectedMediaUris, config, saveMode, appName, date]]]); 518 this.saveCallbackMap.set(date, callback); 519 }) 520 console.info('PhotoPickerComponent SAVE_TRUSTED_PHOTO_ASSETS '); 521 } 522 523 actionCreateCallback(grantUri: string, date: number, code: number, message: string) { 524 if (this.createCallbackMap.has(date)) { 525 let callback = this.createCallbackMap.get(date) as Function; 526 if (callback) { 527 callback(grantUri, code, message); 528 this.createCallbackMap.delete(date); 529 } 530 } 531 } 532 533 actionReplaceCallback(date: number, err: BusinessError) { 534 if (this.replaceCallbackMap.has(date)) { 535 let callback = this.replaceCallbackMap.get(date) as Function; 536 if (callback) { 537 callback(err); 538 this.replaceCallbackMap.delete(date); 539 } 540 } 541 } 542 543 actionSaveCallback(date: number, err: BusinessError, data: Array<string>) { 544 if (this.saveCallbackMap.has(date)) { 545 let callback = this.saveCallbackMap.get(date) as Function; 546 if (callback) { 547 callback(err, data); 548 this.saveCallbackMap.delete(date); 549 } 550 } 551 } 552 553 encrypt(data) { 554 if (!data || data?.indexOf('file:///data/storage/') !== -1) { 555 return ''; 556 } 557 return data.replace(/(\/\w+)\./g, '/******.'); 558 } 559} 560 561export class PickerOptions extends photoAccessHelper.BaseSelectOptions { 562 checkBoxColor?: string; 563 backgroundColor?: string; 564 isRepeatSelectSupported?: boolean; 565 checkboxTextColor?: string; 566 photoBrowserBackgroundColorMode?: PickerColorMode; 567 maxSelectedReminderMode?: ReminderMode; 568 orientation?: PickerOrientation; 569 selectMode?: SelectMode; 570 maxPhotoSelectNumber?: number; 571 maxVideoSelectNumber?: number; 572 isSlidingSelectionSupported?: boolean; 573 photoBrowserCheckboxPosition?: [number, number]; 574 gridMargin?: Margin; 575 photoBrowserMargin?: Margin; 576} 577 578export class BaseItemInfo { 579 uri?: string; 580 mimeType?: string; 581 width?: number; 582 height?: number; 583 size?: number; 584 duration?: number; 585} 586 587export class ItemInfo extends BaseItemInfo { 588 itemType?: ItemType; 589} 590 591export class PhotoBrowserInfo { 592 animatorParams?: AnimatorParams; 593} 594 595export class AnimatorParams { 596 duration?: number; 597 curve?: Curve | ICurve | string; 598} 599 600export class MaxSelected { 601 data?: Map<MaxCountType, number>; 602} 603 604class PhotoBrowserRangeInfo { 605 uri?: string; 606 photoBrowserRange?: PhotoBrowserRange; 607} 608 609class PhotoBrowserUIElementVisibility { 610 elements?: Array<PhotoBrowserUIElement>; 611 isVisible?: boolean; 612} 613 614export enum DataType { 615 SET_SELECTED_URIS = 1, 616 SET_ALBUM_URI = 2 617} 618 619export enum ItemType { 620 THUMBNAIL = 0, 621 CAMERA = 1 622} 623 624export enum ClickType { 625 SELECTED = 0, 626 DESELECTED = 1 627} 628 629export enum PickerOrientation { 630 VERTICAL = 0, 631 HORIZONTAL = 1 632} 633 634export enum SelectMode { 635 SINGLE_SELECT = 0, 636 MULTI_SELECT = 1 637} 638 639export enum PickerColorMode { 640 AUTO = 0, 641 LIGHT = 1, 642 DARK = 2 643} 644 645export enum ReminderMode { 646 NONE = 0, 647 TOAST = 1, 648 MASK = 2 649} 650 651export enum MaxCountType { 652 TOTAL_MAX_COUNT = 0, 653 PHOTO_MAX_COUNT = 1, 654 VIDEO_MAX_COUNT = 2 655} 656 657export enum PhotoBrowserRange { 658 ALL = 0, 659 SELECTED_ONLY = 1 660} 661 662export enum PhotoBrowserUIElement { 663 CHECKBOX = 0, 664 BACK_BUTTON = 1 665} 666 667export enum VideoPlayerState { 668 PLAYING = 0, 669 PAUSED = 1, 670 STOPPED = 3, 671 SEEK_START = 4, 672 SEEK_FINISH = 5 673} 674 675export enum SaveMode { 676 SAVE_AS = 0, 677 OVERWRITE = 1 678}