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