1/*
2 * Copyright (c) 2023-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 */
15const pickerHelper = requireInternal('file.picker');
16
17let gContext = undefined;
18
19const PhotoViewMIMETypes = {
20  IMAGE_TYPE: 'image/*',
21  VIDEO_TYPE: 'video/*',
22  IMAGE_VIDEO_TYPE: '*/*',
23  INVALID_TYPE: ''
24};
25
26const DocumentSelectMode = {
27  FILE: 0,
28  FOLDER: 1,
29  MIXED: 2,
30};
31
32const DocumentPickerMode = {
33  DEFAULT: 0,
34  DOWNLOAD: 1,
35};
36
37const ExtTypes = {
38  DOWNLOAD_TYPE: 'filePicker',
39  AUDIO_PICKER_TYPE: 'audioPicker',
40  PHOTO_PICKER_TYPE: 'photoPicker',
41};
42
43const PickerDetailType = {
44  FILE_MGR_AUTH: 'downloadAuth',
45  FILE_MGR_SELECT:'select',
46  FILE_MGR_SAVE:'save',
47};
48
49const ErrCode = {
50  INVALID_ARGS: 13900020,
51  RESULT_ERROR: 13900042,
52  NAME_TOO_LONG: 13900030,
53  CONTEXT_NO_EXIST: 16000011,
54};
55
56const ERRCODE_MAP = new Map([
57  [ErrCode.INVALID_ARGS, 'Invalid argument'],
58  [ErrCode.RESULT_ERROR, 'Unknown error'],
59  [ErrCode.NAME_TOO_LONG, 'File name too long'],
60  [ErrCode.CONTEXT_NO_EXIST, 'Current ability failed to obtain context'],
61]);
62
63const PHOTO_VIEW_MIME_TYPE_MAP = new Map([
64  [PhotoViewMIMETypes.IMAGE_TYPE, 'FILTER_MEDIA_TYPE_IMAGE'],
65  [PhotoViewMIMETypes.VIDEO_TYPE, 'FILTER_MEDIA_TYPE_VIDEO'],
66  [PhotoViewMIMETypes.IMAGE_VIDEO_TYPE, 'FILTER_MEDIA_TYPE_ALL'],
67]);
68
69const ACTION = {
70  SELECT_ACTION: 'ohos.want.action.OPEN_FILE',
71  SELECT_ACTION_MODAL: 'ohos.want.action.OPEN_FILE_SERVICE',
72  SAVE_ACTION: 'ohos.want.action.CREATE_FILE',
73  SAVE_ACTION_MODAL: 'ohos.want.action.CREATE_FILE_SERVICE',
74};
75
76const CREATE_FILE_NAME_LENGTH_LIMIT = 256;
77const ARGS_ZERO = 0;
78const ARGS_ONE = 1;
79const ARGS_TWO = 2;
80const RESULT_CODE_ERROR = -1;
81const RESULT_CODE_OK = 0;
82const FILENAME_LENGTH = 3;
83
84/*
85* UTF-8字符编码数值对应的存储长度:
86* 0000 - 0x007F (eg: a~z A~Z 0~9)
87* 0080 - 0x07FF (eg: 希腊字母)
88* 0800 - 0xFFFF (eg: 中文)
89* 其他 (eg: 平面符号)
90*/
91function strSizeUTF8(str) {
92  let strLen = str.length;
93  let bytesLen = 0;
94  let greeceLen = 2;
95  let chineseLen = 3;
96  let othersLen = 4;
97  for (let i = 0; i < strLen; i++) {
98    let charCode = str.charCodeAt(i);
99    if (charCode <= 0x007f) {
100      bytesLen++;
101    } else if (charCode <= 0x07ff) {
102      bytesLen += greeceLen;
103    } else if (charCode <= 0xffff) {
104      bytesLen += chineseLen;
105    } else {
106      bytesLen += othersLen;
107    }
108  }
109  return bytesLen;
110}
111
112function checkArguments(args) {
113  let checkArgumentsResult = undefined;
114  if (args.length === ARGS_TWO && typeof args[ARGS_ONE] !== 'function') {
115    checkArgumentsResult = getErr(ErrCode.INVALID_ARGS);
116  }
117
118  if (args.length > 0 && typeof args[ARGS_ZERO] === 'object') {
119    let option = args[ARGS_ZERO];
120    if (option.maxSelectNumber !== undefined) {
121      if (option.maxSelectNumber.toString().indexOf('.') !== -1) {
122        checkArgumentsResult = getErr(ErrCode.INVALID_ARGS);
123      }
124    }
125
126    if (option.newFileNames === undefined || option.newFileNames.length <= 0) {
127      return checkArgumentsResult;
128    }
129
130    for (let i = 0; i < option.newFileNames.length; i++) {
131      let value = option.newFileNames[i];
132      if (strSizeUTF8(value) >= CREATE_FILE_NAME_LENGTH_LIMIT) {
133        console.log('[picker] checkArguments Invalid name: ' + value);
134        checkArgumentsResult = getErr(ErrCode.NAME_TOO_LONG);
135      }
136    }
137  }
138
139  return checkArgumentsResult;
140}
141
142function getErr(errCode) {
143  return {code: errCode, message: ERRCODE_MAP.get(errCode)};
144}
145
146function parsePhotoPickerSelectOption(args) {
147  let config = {
148    action: 'ohos.want.action.photoPicker',
149    type: 'multipleselect',
150    parameters: {
151      uri: 'multipleselect',
152      extType: ExtTypes.PHOTO_PICKER_TYPE,
153    },
154  };
155
156  if (args.length > ARGS_ZERO && typeof args[ARGS_ZERO] === 'object') {
157    let option = args[ARGS_ZERO];
158    if (option.maxSelectNumber && option.maxSelectNumber > 0) {
159      let select = (option.maxSelectNumber === 1) ? 'singleselect' : 'multipleselect';
160      config.type = select;
161      config.parameters.uri = select;
162      config.parameters.maxSelectCount = option.maxSelectNumber;
163    }
164    if (option.MIMEType && PHOTO_VIEW_MIME_TYPE_MAP.has(option.MIMEType)) {
165      config.parameters.filterMediaType = PHOTO_VIEW_MIME_TYPE_MAP.get(option.MIMEType);
166    }
167  }
168
169  return config;
170}
171
172function anonymousPathArray(geturi) {
173  let anonymousPathArrays = [];
174  let anonymousPath = '';
175  if (geturi === undefined) {
176    return anonymousPathArrays;
177  }
178  for (let i = 0; i < geturi.length; ++i) {
179    let lastSlashIndex = geturi[i].lastIndexOf('/');
180    if (lastSlashIndex === -1) {
181      anonymousPathArrays.push(geturi[i]);
182    } else {
183      let dirPath = geturi[i].substring(0, lastSlashIndex + 1);
184      let fileName = geturi[i].substring(lastSlashIndex + 1);
185      if (fileName.length <= 0) {
186        anonymousPath = '******';
187      } else {
188        let lastLetter = fileName.slice(-1);
189        let maskedName = '******' + lastLetter;
190        anonymousPath = dirPath + maskedName;
191      }
192      anonymousPathArrays.push(anonymousPath);
193    }
194    }
195  return anonymousPathArrays;
196}
197
198function getPhotoPickerSelectResult(args) {
199  let selectResult = {
200    error: undefined,
201    data: undefined,
202  };
203
204  if (args.resultCode === 0) {
205    let uris = args.photoUris;
206    let isOriginal = args.isOriginal;
207    selectResult.data = new PhotoSelectResult(uris, isOriginal);
208  } else if (args.resultCode === -1) {
209    selectResult.data = new PhotoSelectResult([], undefined);
210  } else {
211    selectResult.error = getErr(ErrCode.RESULT_ERROR);
212  }
213
214  return selectResult;
215}
216
217async function photoPickerSelect(...args) {
218  let checkPhotoArgsResult = checkArguments(args);
219  if (checkPhotoArgsResult !== undefined) {
220    console.log('[picker] Photo Invalid argument');
221    throw checkPhotoArgsResult;
222  }
223
224  const config = parsePhotoPickerSelectOption(args);
225  console.log('[picker] Photo config: ' + JSON.stringify(config));
226
227  let photoSelectContext = undefined;
228  let photoSelectWindow = undefined;
229  try {
230    if (this.context !== undefined) {
231      photoSelectContext = this.context;
232    } else {
233      photoSelectContext = getContext(this);
234    }
235  } catch (getContextError) {
236    console.error('[picker] getContext error: ' + getContextError);
237    throw getErr(ErrCode.CONTEXT_NO_EXIST);
238  }
239  try {
240    if (photoSelectContext === undefined) {
241      console.error('[picker] photoSelectContext == undefined');
242      throw getErr(ErrCode.CONTEXT_NO_EXIST);
243    }
244    let modalSelectResult = await modalPicker(photoSelectContext, config, photoSelectWindow);
245    console.log('[picker] photo select result: ' + JSON.stringify(modalSelectResult));
246    const photoSelectResult = getPhotoPickerSelectResult(modalSelectResult);
247    console.log('[picker] photoSelectResult: ' + JSON.stringify(photoSelectResult));
248    if (args.length === ARGS_TWO && typeof args[ARGS_ONE] === 'function') {
249      return args[ARGS_ONE](photoSelectResult.error, photoSelectResult.data);
250    } else if (args.length === ARGS_ONE && typeof args[ARGS_ZERO] === 'function') {
251      return args[ARGS_ZERO](photoSelectResult.error, photoSelectResult.data);
252    }
253    return new Promise((resolve, reject) => {
254      if (photoSelectResult.data !== undefined) {
255        resolve(photoSelectResult.data);
256      } else {
257        reject(photoSelectResult.error);
258      }
259    });
260  } catch (error) {
261    console.error('[picker] photo select error: ' + error);
262  }
263  return undefined;
264}
265
266function parseDocumentPickerSelectOption(args, action) {
267  let config = {
268    action: action,
269    parameters: {
270      startMode: 'choose',
271      extType: ExtTypes.DOWNLOAD_TYPE,
272      pickerType: PickerDetailType.FILE_MGR_SELECT,
273    }
274  };
275
276  if (args.length > ARGS_ZERO && typeof args[ARGS_ZERO] === 'object') {
277    let option = args[ARGS_ZERO];
278    config.parameters.key_select_mode = option.selectMode;
279    console.log('[picker] parseDocumentPickerSelectOption: ' + JSON.stringify(option));
280
281    if ((option.maxSelectNumber !== undefined) && option.maxSelectNumber > 0) {
282      config.parameters.key_pick_num = option.maxSelectNumber;
283    }
284    if (option.defaultFilePathUri !== undefined) {
285      config.parameters.key_pick_dir_path = option.defaultFilePathUri;
286    }
287    if ((option.fileSuffixFilters !== undefined) && option.fileSuffixFilters.length > 0) {
288      config.parameters.key_file_suffix_filter = option.fileSuffixFilters;
289    }
290    if (option.authMode !== undefined) {
291      config.parameters.key_auth_mode = option.authMode;
292    }
293  }
294
295  console.log('[picker] document select config: ' + JSON.stringify(config));
296  return config;
297}
298
299function parseAudioPickerSelectOption(args, action) {
300  let config = {
301    action: action,
302    parameters: {
303      extType: ExtTypes.AUDIO_PICKER_TYPE,
304    }
305  };
306  if (args.length > ARGS_ZERO && typeof args[ARGS_ZERO] === 'object') {
307    let option = args[ARGS_ZERO];
308    if ((option.maxSelectNumber !== undefined) && option.maxSelectNumber > 0) {
309      config.parameters.key_pick_num = option.maxSelectNumber;
310    }
311  }
312  console.log('[picker] audio select config: ' + JSON.stringify(config));
313  return config;
314}
315
316function getDocumentPickerSelectResult(args) {
317  let selectResult = {
318    error: undefined,
319    data: undefined
320  };
321  if (args === undefined || args.resultCode === undefined) {
322    selectResult.error = getErr(ErrCode.RESULT_ERROR);
323    console.log('[picker] document select selectResult: ' + JSON.stringify(selectResult));
324    return selectResult;
325  }
326  if (args.resultCode === RESULT_CODE_OK) {
327    if (args.ability_params_stream) {
328      selectResult.data = args.ability_params_stream;
329      selectResult.error = args.resultCode;
330    }
331  } else if (args.resultCode === RESULT_CODE_ERROR) {
332    selectResult.data = [];
333    selectResult.error = args.resultCode;
334  }
335
336  console.log('[picker] document select selectResult: : errorcode is = ' + selectResult.error +
337              ', selecturi is = ' + anonymousPathArray(selectResult.data));
338  return selectResult;
339}
340
341async function documentPickerSelect(...args) {
342  let checkDocumentSelectArgsResult = checkArguments(args);
343  if (checkDocumentSelectArgsResult !== undefined) {
344    console.log('[picker] Document Select Invalid argument');
345    throw checkDocumentSelectArgsResult;
346  }
347
348  let documentSelectContext = undefined;
349  let documentSelectConfig = undefined;
350  let documentSelectResult = undefined;
351  let selectResult = undefined;
352  let documentSelectWindow = undefined;
353
354  try {
355    if (this.context !== undefined) {
356      documentSelectContext = this.context;
357    } else {
358      documentSelectContext = getContext(this);
359    }
360  } catch (getContextError) {
361    console.error('[picker] getContext error: ' + getContextError);
362    throw getErr(ErrCode.CONTEXT_NO_EXIST);
363  }
364  try {
365    if (documentSelectContext === undefined) {
366      console.error('[picker] documentSelectContext == undefined');
367      throw getErr(ErrCode.CONTEXT_NO_EXIST);
368    }
369    if (this.window !== undefined) {
370        documentSelectWindow = this.window;
371    }
372    documentSelectConfig = parseDocumentPickerSelectOption(args, ACTION.SELECT_ACTION_MODAL);
373    console.error('[picker] DocumentSelect documentSelectConfig: ' + JSON.stringify(documentSelectConfig));
374    documentSelectResult = await modalPicker(documentSelectContext, documentSelectConfig, documentSelectWindow);
375  } catch (paramError) {
376    console.error('[picker] DocumentSelect paramError: ' + JSON.stringify(paramError));
377  }
378  selectResult = getDocumentPickerSelectResult(documentSelectResult);
379  return sendResult(args, selectResult);
380}
381
382function parseDocumentPickerSaveOption(args, action) {
383  let config = {
384    action: action,
385    parameters: {
386      startMode: 'save',
387      pickerMode: DocumentPickerMode.DEFAULT,
388      extType: ExtTypes.DOWNLOAD_TYPE,
389      pickerType: PickerDetailType.FILE_MGR_SAVE,
390    }
391  };
392
393  if (args.length > ARGS_ZERO && typeof args[ARGS_ZERO] === 'object') {
394    let option = args[ARGS_ZERO];
395    console.log('[picker] document save option: ' + JSON.stringify(option));
396    if ((option.newFileNames !== undefined) && option.newFileNames.length > 0) {
397      config.parameters.key_pick_file_name = option.newFileNames;
398      config.parameters.saveFile = option.newFileNames[0];
399    }
400
401    if (option.defaultFilePathUri !== undefined) {
402      config.parameters.key_pick_dir_path = option.defaultFilePathUri;
403    }
404    if ((option.fileSuffixChoices !== undefined) && option.fileSuffixChoices.length > 0) {
405      config.parameters.key_file_suffix_choices = option.fileSuffixChoices;
406    }
407    if (option.pickerMode === DocumentPickerMode.DOWNLOAD) {
408      config.parameters.pickerMode = option.pickerMode;
409      config.parameters.pickerType = PickerDetailType.FILE_MGR_AUTH;
410    }
411  }
412
413  console.log('[picker] document save config: ' + JSON.stringify(config));
414  return config;
415}
416
417function getAudioPickerSelectResult(args) {
418  let selectResult = {
419    error: undefined,
420    data: undefined
421  };
422  if (args === undefined || args.resultCode === undefined) {
423    selectResult.error = getErr(ErrCode.RESULT_ERROR);
424    console.log('[picker] getAudioPickerSelectResult selectResult: ' + JSON.stringify(selectResult));
425    return selectResult;
426  }
427  if (args.resultCode === RESULT_CODE_OK) {
428    if (args.uriArr) {
429      selectResult.data = args.uriArr;
430      selectResult.error = args.resultCode;
431    } else {
432      selectResult.data = [];
433      selectResult.error = args.resultCode;
434    }
435  } else if (args.resultCode === RESULT_CODE_ERROR) {
436    selectResult.data = [];
437    selectResult.error = args.resultCode;
438  }
439
440  console.log('[picker] getAudioPickerSelectResult selectResult: errorcode is = ' + selectResult.error +
441              ', selecturi is = ' + anonymousPathArray(selectResult.data));
442  return selectResult;
443}
444
445
446function getDocumentPickerSaveResult(args) {
447  let saveResult = {
448    error: undefined,
449    data: undefined,
450    suffix: -1
451  };
452  if (args === undefined || args.resultCode === undefined) {
453    saveResult.error = getErr(ErrCode.RESULT_ERROR);
454    console.log('[picker] getDocumentPickerSaveResult saveResult: ' + JSON.stringify(saveResult));
455    return saveResult;
456  }
457  if (args.resultCode === RESULT_CODE_OK) {
458    if (args.ability_params_stream) {
459      saveResult.data = args.ability_params_stream;
460      saveResult.error = args.resultCode;
461      if (args.userSuffixIndex >= 0) {
462        saveResult.suffix = args.userSuffixIndex;
463      }
464    }
465  } else if (args.resultCode === RESULT_CODE_ERROR) {
466    saveResult.data = [];
467    saveResult.error = args.resultCode;
468  }
469
470  console.log('[picker] getDocumentPickerSaveResult saveResult: errorcode is = ' + saveResult.error +
471              ', selecturi is = ' + anonymousPathArray(saveResult.data) + ', usersavesuffix = ' + saveResult.suffix);
472  return saveResult;
473}
474
475function startModalPicker(context, config, window) {
476  if (context === undefined) {
477    throw Error('[picker] Context undefined.');
478  }
479  if (config === undefined) {
480    throw Error('[picker] Config undefined.');
481  }
482  gContext = context;
483  if (pickerHelper === undefined) {
484    throw Error('[picker] PickerHelper undefined.');
485  }
486  let helper;
487  if (window !== undefined) {
488    helper = pickerHelper.startModalPicker(gContext, config, window);
489  } else {
490    helper = pickerHelper.startModalPicker(gContext, config);
491  }
492  if (helper === undefined) {
493    throw Error('[picker] Please check the parameter you entered.');
494  }
495  return helper;
496}
497
498async function modalPicker(context, config, window) {
499  try {
500    console.log('[picker] Config: ' + JSON.stringify(config));
501    let modalResult = await startModalPicker(context, config, window);
502    return modalResult;
503  } catch (resultError) {
504    console.error('[picker] Result error: ' + resultError);
505    return undefined;
506  }
507}
508
509async function documentPickerSave(...args) {
510  let checkDocumentSaveArgsResult = checkArguments(args);
511  if (checkDocumentSaveArgsResult !== undefined) {
512    console.log('[picker] Document Save Invalid argument');
513    throw checkDocumentSaveArgsResult;
514  }
515
516  let documentSaveContext = undefined;
517  let documentSaveConfig = undefined;
518  let documentSaveResult = undefined;
519  let saveResult = undefined;
520  let documentSaveWindow = undefined;
521
522  try {
523    if (this.context !== undefined) {
524      documentSaveContext = this.context;
525    } else {
526      documentSaveContext = getContext(this);
527    }
528  } catch (getContextError) {
529    console.error('[picker] getContext error: ' + getContextError);
530    throw getErr(ErrCode.CONTEXT_NO_EXIST);
531  }
532  if (this.window !== undefined) {
533      documentSaveWindow = this.window;
534  }
535
536  documentSaveConfig = parseDocumentPickerSaveOption(args, ACTION.SAVE_ACTION_MODAL);
537  console.log('[picker] document save start');
538
539  documentSaveResult = await modalPicker(documentSaveContext, documentSaveConfig, documentSaveWindow);
540  saveResult = getDocumentPickerSaveResult(documentSaveResult);
541  this.suffixIndex = saveResult.suffix;
542  return sendResult(args, saveResult);
543}
544
545function getSelectedSuffixIndex() {
546  console.log('[picker] Get Selected Suffix Index start');
547  let index = this.suffixIndex;
548  this.suffixIndex = -1;
549  console.log('[picker] Get Selected Suffix Index end: ' + index);
550  return index;
551}
552
553async function sendResult(args, result) {
554  try {
555    if (result === undefined) {
556      console.log('[picker] result is undefined.');
557      return undefined;
558    }
559    if (args.length === ARGS_TWO && typeof args[ARGS_ONE] === 'function') {
560      return args[ARGS_ONE](result.error, result.data);
561    } else if (args.length === ARGS_ONE && typeof args[ARGS_ZERO] === 'function') {
562      return args[ARGS_ZERO](result.error, result.data);
563    }
564    return new Promise((resolve, reject) => {
565      if (result.data !== undefined) {
566        resolve(result.data);
567      } else {
568        reject(result.error);
569      }
570    });
571  } catch (resultError) {
572    console.error('[picker] Result error: ' + resultError);
573  }
574  return undefined;
575}
576
577async function audioPickerSelect(...args) {
578  let checkAudioArgsResult = checkArguments(args);
579  if (checkAudioArgsResult !== undefined) {
580    console.log('[picker] Audio Invalid argument');
581    throw checkAudioArgsResult;
582  }
583
584  const audioSelectConfig = parseAudioPickerSelectOption(args, ACTION.SELECT_ACTION);
585  console.log('[picker] audio select config: ' + JSON.stringify(audioSelectConfig));
586
587  let audioSelectContext = undefined;
588  let audipSelectWindow = undefined;
589  try {
590    if (this.context !== undefined) {
591      audioSelectContext = this.context;
592    } else {
593      audioSelectContext = getContext(this);
594    }
595  } catch (getContextError) {
596    console.error('[picker] getContext error: ' + getContextError);
597    throw getErr(ErrCode.CONTEXT_NO_EXIST);
598  }
599  try {
600    if (audioSelectContext === undefined) {
601      console.error('[picker] audioSelectContext == undefined');
602      throw getErr(ErrCode.CONTEXT_NO_EXIST);
603    }
604    let modalSelectResult = await modalPicker(audioSelectContext, audioSelectConfig, audipSelectWindow);
605    let saveResult = getAudioPickerSelectResult(modalSelectResult);
606    return sendResult(args, saveResult);
607  } catch (error) {
608    console.error('[picker] audio select error: ' + error);
609  }
610  return undefined;
611}
612
613function PhotoSelectOptions() {
614  this.MIMEType = PhotoViewMIMETypes.INVALID_TYPE;
615  this.maxSelectNumber = -1;
616}
617
618function PhotoSelectResult(uris, isOriginalPhoto) {
619  this.photoUris = uris;
620  this.isOriginalPhoto = isOriginalPhoto;
621}
622
623function PhotoSaveOptions() {
624  this.newFileNames = undefined;
625}
626
627function DocumentSelectOptions() {
628  this.defaultFilePathUri = undefined;
629  this.fileSuffixFilters = undefined;
630  this.maxSelectNumber = undefined;
631  this.selectMode = DocumentSelectMode.FILE;
632}
633
634function DocumentSaveOptions() {
635  this.newFileNames = undefined;
636  this.defaultFilePathUri = undefined;
637  this.fileSuffixChoices = undefined;
638  this.pickerMode = DocumentPickerMode.DEFAULT;
639}
640
641function AudioSelectOptions() {}
642
643function AudioSaveOptions() {
644  this.newFileNames = undefined;
645}
646
647function ParseContext(args)
648{
649  if (args.length > ARGS_TWO || args.length < ARGS_ZERO || typeof args[ARGS_ZERO] !== 'object') {
650    return undefined;
651  }
652  return args[ARGS_ZERO];
653}
654
655function parseWindow(args)
656{
657  if (args.length !== ARGS_TWO) {
658    console.log('[picker] ParseWindow: not window mode.');
659    return undefined;
660  }
661  if (args.length === ARGS_TWO && typeof args[ARGS_ONE] !== 'object') {
662    console.log('[picker] ParseWindow: not window mode or type err.');
663    return undefined;
664  }
665  console.log('[picker] ParseWindow: window mode.');
666  return args[ARGS_ONE];
667}
668
669function PhotoViewPicker(...args) {
670  this.select = photoPickerSelect;
671  this.save = documentPickerSave;
672  this.context = ParseContext(args);
673}
674
675function DocumentViewPicker(...args) {
676  this.select = documentPickerSelect;
677  this.save = documentPickerSave;
678  this.context = ParseContext(args);
679  this.window = parseWindow(args);
680  this.getSelectedIndex = getSelectedSuffixIndex;
681  this.suffixIndex = -1;
682}
683
684function AudioViewPicker(...args) {
685  this.select = audioPickerSelect;
686  this.save = documentPickerSave;
687  this.context = ParseContext(args);
688}
689
690export default {
691  getSelectedSuffixIndex,
692  startModalPicker,
693  ExtTypes : ExtTypes,
694  PickerDetailType: PickerDetailType,
695  PhotoViewMIMETypes : PhotoViewMIMETypes,
696  PhotoSelectOptions : PhotoSelectOptions,
697  PhotoSelectResult : PhotoSelectResult,
698  PhotoSaveOptions : PhotoSaveOptions,
699  DocumentSelectMode : DocumentSelectMode,
700  DocumentPickerMode : DocumentPickerMode,
701  DocumentSelectOptions : DocumentSelectOptions,
702  DocumentSaveOptions : DocumentSaveOptions,
703  AudioSelectOptions : AudioSelectOptions,
704  AudioSaveOptions : AudioSaveOptions,
705  PhotoViewPicker : PhotoViewPicker,
706  DocumentViewPicker: DocumentViewPicker,
707  AudioViewPicker : AudioViewPicker,
708};
709