• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}