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 */
15
16const photoAccessHelper = requireInternal('file.photoAccessHelper');
17const bundleManager = requireNapi('bundle.bundleManager');
18
19const ARGS_ZERO = 0;
20const ARGS_ONE = 1;
21const ARGS_TWO = 2;
22const ARGS_THREE = 3;
23
24const WRITE_PERMISSION = 'ohos.permission.WRITE_IMAGEVIDEO';
25
26const PERMISSION_DENIED = 13900012;
27const ERR_CODE_PARAMERTER_INVALID = 13900020;
28const ERR_CODE_OHOS_PERMISSION_DENIED = 201;
29const ERR_CODE_OHOS_PARAMERTER_INVALID = 401;
30const REQUEST_CODE_SUCCESS = 0;
31const PERMISSION_STATE_ERROR = -1;
32const ERROR_MSG_WRITE_PERMISSION = 'not have ohos.permission.WRITE_IMAGEVIDEO';
33const ERROR_MSG_USER_DENY = 'user deny';
34const ERROR_MSG_PARAMERTER_INVALID = 'input parmaeter invalid';
35const ERROR_MSG_INNER_FAIL = 'System inner fail';
36const ERROR_MSG_OHOS_INNER_FAIL = 'Internal system error';
37
38const MAX_DELETE_NUMBER = 300;
39const MIN_DELETE_NUMBER = 1;
40const MAX_CONFIRM_NUMBER = 100;
41const MIN_CONFIRM_NUMBER = 1;
42
43let gContext = undefined;
44
45class BusinessError extends Error {
46  constructor(msg, code) {
47    super(msg);
48    this.code = code || PERMISSION_DENIED;
49  }
50}
51
52function checkArrayAndSize(array, minSize, maxSize) {
53  // check whether input is array
54  if (!Array.isArray(array)) {
55    console.error('photoAccessHelper invalid, array is null.');
56    return false;
57  }
58
59  // check whether array length is valid
60  let len = array.length;
61  if ((len < minSize) || (len > maxSize)) {
62    console.error('photoAccessHelper invalid, array size invalid.');
63    return false;
64  }
65
66  return true;
67}
68
69function checkIsUriValid(uri, isAppUri) {
70  if (!uri) {
71    console.error('photoAccessHelper invalid, uri is null.');
72    return false;
73  }
74
75  if (typeof uri !== 'string') {
76    console.error('photoAccessHelper invalid, uri type is not string.');
77    return false;
78  }
79
80  // media library uri starts with 'file://media/Photo/', createDeleteReques delete media library resource should check
81  if (!isAppUri) {
82    return uri.includes('file://media/Photo/');
83  }
84
85  // showAssetsCreationDialog store third part application resource to media library, no need to check it
86  return true;
87}
88
89function checkParams(uriList, asyncCallback) {
90  if (arguments.length > ARGS_TWO) {
91    return false;
92  }
93  if (!checkArrayAndSize(uriList, MIN_DELETE_NUMBER, MAX_DELETE_NUMBER)) {
94    return false;
95  }
96  if (asyncCallback && typeof asyncCallback !== 'function') {
97    return false;
98  }
99  for (let uri of uriList) {
100    if (!checkIsUriValid(uri, false)) {
101      console.info(`photoAccessHelper invalid uri: ${uri}`);
102      return false;
103    }
104  }
105  return true;
106}
107function errorResult(rej, asyncCallback) {
108  if (asyncCallback) {
109    return asyncCallback(rej);
110  }
111  return new Promise((resolve, reject) => {
112    reject(rej);
113  });
114}
115
116function getAbilityResource(bundleInfo) {
117  console.info('getAbilityResource enter.');
118  let labelId = 0;
119  for (let hapInfo of bundleInfo.hapModulesInfo) {
120    if (hapInfo.type === bundleManager.ModuleType.ENTRY) {
121      labelId = getLabelId(hapInfo);
122    }
123  }
124  return labelId;
125}
126
127function getLabelId(hapInfo) {
128  let labelId = 0;
129  for (let abilityInfo of hapInfo.abilitiesInfo) {
130    let abilitiesInfoName = '';
131    if (abilityInfo.name.includes('.')) {
132      let abilitiesInfoLength = abilityInfo.name.split('.').length;
133      abilitiesInfoName = abilityInfo.name.split('.')[abilitiesInfoLength - 1];
134    } else {
135      abilitiesInfoName = abilityInfo.name;
136    }
137    if (abilitiesInfoName === hapInfo.mainElementName) {
138      labelId = abilityInfo.labelId;
139    }
140  }
141  return labelId;
142}
143
144async function getAppName() {
145  let appName = '';
146  try {
147    const flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_ABILITY | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_HAP_MODULE;
148    const bundleInfo = await bundleManager.getBundleInfoForSelf(flags);
149    console.info(`photoAccessHelper bundleInfo: ${JSON.stringify(bundleInfo)}`);
150    if (bundleInfo === undefined || bundleInfo.hapModulesInfo === undefined || bundleInfo.hapModulesInfo.length === 0) {
151      return appName;
152    }
153    const labelId = getAbilityResource(bundleInfo);
154    const resourceMgr = gContext.resourceManager;
155    appName = await resourceMgr.getStringValue(labelId);
156    console.info(`photoAccessHelper appName: ${appName}`);
157  } catch (error) {
158    console.info(`photoAccessHelper error: ${JSON.stringify(error)}`);
159  }
160
161  return appName;
162}
163
164async function createPhotoDeleteRequestParamsOk(uriList, asyncCallback) {
165  let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
166  let { reqPermissionDetails, permissionGrantStates } = await bundleManager.getBundleInfoForSelf(flags);
167  let permissionIndex = -1;
168  for (let i = 0; i < reqPermissionDetails.length; i++) {
169    if (reqPermissionDetails[i].name === WRITE_PERMISSION) {
170      permissionIndex = i;
171    }
172  }
173  if (permissionIndex < 0 || permissionGrantStates[permissionIndex] === PERMISSION_STATE_ERROR) {
174    console.info('photoAccessHelper permission error');
175    return errorResult(new BusinessError(ERROR_MSG_WRITE_PERMISSION), asyncCallback);
176  }
177  const appName = await getAppName();
178  if (appName.length === 0) {
179    console.info('photoAccessHelper appName not found');
180    return errorResult(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_PARAMERTER_INVALID), asyncCallback);
181  }
182  try {
183    if (asyncCallback) {
184      return photoAccessHelper.createDeleteRequest(getContext(this), appName, uriList, result => {
185        if (result.result === REQUEST_CODE_SUCCESS) {
186          asyncCallback();
187        } else if (result.result === PERMISSION_DENIED) {
188          asyncCallback(new BusinessError(ERROR_MSG_USER_DENY));
189        } else {
190          asyncCallback(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
191        }
192      });
193    } else {
194      return new Promise((resolve, reject) => {
195        photoAccessHelper.createDeleteRequest(getContext(this), appName, uriList, result => {
196          if (result.result === REQUEST_CODE_SUCCESS) {
197            resolve();
198          } else if (result.result === PERMISSION_DENIED) {
199            reject(new BusinessError(ERROR_MSG_USER_DENY));
200          } else {
201            reject(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
202          }
203        });
204      });
205    }
206  } catch (error) {
207    return errorResult(new BusinessError(error.message, error.code), asyncCallback);
208  }
209}
210
211function createDeleteRequest(...params) {
212  if (!checkParams(...params)) {
213    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_PARAMERTER_INVALID);
214  }
215  return createPhotoDeleteRequestParamsOk(...params);
216}
217
218function checkIsPhotoCreationConfigValid(config) {
219  if (!config) {
220    console.error('photoAccessHelper invalid, config is null.');
221    return false;
222  }
223
224  // check whether input is a object
225  if (typeof config !== 'object') {
226    console.error('photoAccessHelper invalid, config type is not object.');
227    return false;
228  }
229
230  // check whether title is string if exsit
231  if ((config.title) && (typeof config.title !== 'string')) {
232    console.error('photoAccessHelper invalid, config.title type is not string.');
233    return false;
234  }
235
236  // check whether fileNameExtension is string
237  if (!config.fileNameExtension) {
238    console.error('photoAccessHelper invalid, config.fileNameExtension is null.');
239    return false;
240  }
241  if (typeof config.fileNameExtension !== 'string') {
242    console.error('photoAccessHelper invalid, config.fileNameExtension type is not string.');
243    return false;
244  }
245
246  // check whether photoType is number
247  if (!config.photoType) {
248    console.error('photoAccessHelper invalid, config.photoType is null.');
249    return false;
250  }
251  if (typeof config.photoType !== 'number') {
252    console.error('photoAccessHelper invalid, config.photoType type is not number.');
253    return false;
254  }
255
256  // check whether subtype is number if exsit
257  if ((config.subtype) && (typeof config.subtype !== 'number')) {
258    console.error('photoAccessHelper invalid, config.subtype type is not number.');
259    return false;
260  }
261
262  return true;
263}
264
265function checkConfirmBoxParams(srcFileUris, photoCreationConfigs) {
266  // check param number
267  if (arguments.length > ARGS_TWO) {
268    return false;
269  }
270
271  // check whether input array is valid
272  if (!checkArrayAndSize(srcFileUris, MIN_CONFIRM_NUMBER, MAX_CONFIRM_NUMBER)) {
273    return false;
274  }
275  if (!checkArrayAndSize(photoCreationConfigs, MIN_CONFIRM_NUMBER, MAX_CONFIRM_NUMBER)) {
276    return false;
277  }
278  if (srcFileUris.length !== photoCreationConfigs.length) {
279    return false;
280  }
281
282  // check whether srcFileUris element is valid
283  for (let srcFileUri of srcFileUris) {
284    if (!checkIsUriValid(srcFileUri, true)) {
285      console.error('photoAccessHelper invalid uri: ${srcFileUri}.');
286      return false;
287    }
288  }
289
290  // check whether photoCreationConfigs element is valid
291  for (let photoCreateConfig of photoCreationConfigs) {
292    if (!checkIsPhotoCreationConfigValid(photoCreateConfig)) {
293      return false;
294    }
295  }
296
297  return true;
298}
299
300function getBundleInfo() {
301  let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_ABILITY | // for appName
302    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_HAP_MODULE | // for appName
303    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO | // for appId
304    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION; // for appInfo
305  let bundleInfo = bundleManager.getBundleInfoForSelfSync(flags);
306  if (((bundleInfo === undefined) || (bundleInfo.name === undefined)) ||
307      ((bundleInfo.hapModulesInfo === undefined) || (bundleInfo.hapModulesInfo.length === 0)) ||
308      ((bundleInfo.signatureInfo === undefined) || (bundleInfo.signatureInfo.appId === undefined)) ||
309      ((bundleInfo.appInfo === undefined) || (bundleInfo.appInfo.labelId === 0))) {
310    console.error('photoAccessHelper failed to get bundle info.');
311    return undefined;
312  }
313
314  return bundleInfo;
315}
316
317function showAssetsCreationDialogResult(result, reject, resolve) {
318  if (result.result !== REQUEST_CODE_SUCCESS) {
319    reject(new BusinessError(ERROR_MSG_OHOS_INNER_FAIL, result.result));
320  }
321
322  if (result.data === undefined) {
323    result.data = [];
324  }
325
326  resolve(result.data);
327}
328
329async function showAssetsCreationDialogParamsOk(srcFileUris, photoCreationConfigs) {
330  let bundleInfo = getBundleInfo();
331  if (bundleInfo === undefined) {
332    return new Promise((resolve, reject) => {
333      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
334    });
335  }
336
337  // get bundleName and appId and appName
338  let bundleName = bundleInfo.name;
339  let appId = bundleInfo.signatureInfo.appId;
340  console.info('photoAccessHelper bundleName is ' + bundleName + '.');
341  console.info('photoAccessHelper appId is ' + appId + '.');
342
343  let labelId = bundleInfo.appInfo.labelId;
344  console.info('photoAccessHelper labelId is ' + appId + '.');
345  let appName = '';
346
347  try {
348    let modeleName = '';
349    for (let hapInfo of bundleInfo.hapModulesInfo) {
350      if (labelId === hapInfo.labelId) {
351        modeleName = hapInfo.name;
352      }
353    }
354    console.info('photoAccessHelper modeleName is ' + modeleName + '.');
355    appName = await gContext.createModuleContext(modeleName).resourceManager.getStringValue(labelId);
356    console.info('photoAccessHelper appName is ' + appName + '.');
357
358    // only promise type
359    return new Promise((resolve, reject) => {
360      photoAccessHelper.showAssetsCreationDialog(getContext(this), srcFileUris, photoCreationConfigs, bundleName,
361        appName, appId, result => {
362          showAssetsCreationDialogResult(result, reject, resolve);
363      });
364    });
365  } catch (error) {
366    return errorResult(new BusinessError(error.message, error.code), null);
367  }
368}
369
370function showAssetsCreationDialog(...params) {
371  if (!checkConfirmBoxParams(...params)) {
372    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
373  }
374  return showAssetsCreationDialogParamsOk(...params);
375}
376
377async function createAssetWithShortTermPermissionOk(photoCreationConfig) {
378  let bundleInfo = getBundleInfo();
379  if (bundleInfo === undefined) {
380    return new Promise((resolve, reject) => {
381      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
382    });
383  }
384
385  let bundleName = bundleInfo.name;
386  let appId = bundleInfo.signatureInfo.appId;
387  console.info('photoAccessHelper bundleName is ' + bundleName + '.');
388  console.info('photoAccessHelper appId is ' + appId + '.');
389
390  let labelId = bundleInfo.appInfo.labelId;
391  console.info('photoAccessHelper labelId is ' + appId + '.');
392  let appName = '';
393
394  try {
395    let modeleName = '';
396    for (let hapInfo of bundleInfo.hapModulesInfo) {
397      if (labelId === hapInfo.labelId) {
398        modeleName = hapInfo.name;
399      }
400    }
401    console.info('photoAccessHelper modeleName is ' + modeleName + '.');
402    appName = await gContext.createModuleContext(modeleName).resourceManager.getStringValue(labelId);
403    console.info('photoAccessHelper appName is ' + appName + '.');
404
405    if (photoAccessHelper.checkShortTermPermission()) {
406      let photoCreationConfigs = [photoCreationConfig];
407      let desFileUris = await getPhotoAccessHelper(getContext(this)).createAssetsHasPermission(bundleName, appName, appId,
408        photoCreationConfigs);
409      return new Promise((resolve, reject) => {
410        resolve(desFileUris[0]);
411      });
412    }
413    return new Promise((resolve, reject) => {
414      photoAccessHelper.createAssetWithShortTermPermission(getContext(this), photoCreationConfig, bundleName, appName,
415        appId, result => {
416          showAssetsCreationDialogResult(result, reject, resolve);
417        });
418    });
419  } catch (error) {
420    return errorResult(new BusinessError(ERROR_MSG_INNER_FAIL, error.code), null);
421  }
422}
423
424function createAssetWithShortTermPermission(photoCreationConfig) {
425  if (!checkIsPhotoCreationConfigValid(photoCreationConfig)) {
426    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
427  }
428  return createAssetWithShortTermPermissionOk(photoCreationConfig);
429}
430
431async function requestPhotoUrisReadPermission(srcFileUris) {
432  console.info('requestPhotoUrisReadPermission enter');
433
434  //check whether srcFileUris is valid
435  if (srcFileUris === undefined || srcFileUris.length < MIN_CONFIRM_NUMBER) {
436    console.error('photoAccessHelper invalid, array size invalid.');
437    return false;
438  }
439  for (let srcFileUri of srcFileUris) {
440    if (!checkIsUriValid(srcFileUri, true)) {
441      console.error('photoAccesshelper invalid uri : ${srcFileUri}.');
442      return false;
443    }
444  }
445
446  let context = gContext;
447  if (context === undefined) {
448    console.info('photoAccessHelper gContet undefined');
449    context = getContext(this);
450  }
451
452  let bundleInfo = getBundleInfo();
453  if (bundleInfo === undefined) {
454    return new Promise((resolve, reject) => {
455      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
456    });
457  }
458  let labelId = bundleInfo.appInfo.labelId;
459  console.info('photoAccessHelper labelId is ' + labelId + '.');
460  let appName = '';
461
462  try {
463    let moduleName = '';
464    for (let hapInfo of bundleInfo.hapModulesInfo) {
465      if (labelId === hapInfo.labelId) {
466        moduleName = hapInfo.name;
467      }
468    }
469    console.info('photoAccessHelper moduleName is ' + moduleName + '.');
470    appName = await gContext.createModuleContext(moduleName).resourceManager.getStringValue(labelId);
471    console.info('photoAccessHelper appName is ' + appName + '.');
472    return new Promise((resolve, reject) => {
473      photoAccessHelper.requestPhotoUrisReadPermission(context, srcFileUris, appName, result => {
474        showAssetsCreationDialogResult(result, reject, resolve);
475      });
476    });
477  } catch (error) {
478    console.error('requestPhotoUrisReadPermission catch error.');
479    return errorResult(new BusinessError(ERROR_MSG_INNER_FAIL, error.code), null);
480  }
481}
482
483function getPhotoAccessHelper(context) {
484  if (context === undefined) {
485    console.log('photoAccessHelper gContext undefined');
486    throw Error('photoAccessHelper gContext undefined');
487  }
488  gContext = context;
489  let helper = photoAccessHelper.getPhotoAccessHelper(gContext);
490  if (helper !== undefined) {
491    console.log('photoAccessHelper getPhotoAccessHelper inner add createDeleteRequest and showAssetsCreationDialog');
492    helper.createDeleteRequest = createDeleteRequest;
493    helper.showAssetsCreationDialog = showAssetsCreationDialog;
494    helper.createAssetWithShortTermPermission = createAssetWithShortTermPermission;
495    helper.requestPhotoUrisReadPermission = requestPhotoUrisReadPermission;
496  }
497  return helper;
498}
499
500function startPhotoPicker(context, config) {
501  if (context === undefined) {
502    console.log('photoAccessHelper gContext undefined');
503    throw Error('photoAccessHelper gContext undefined');
504  }
505  if (config === undefined) {
506    console.log('photoAccessHelper config undefined');
507    throw Error('photoAccessHelper config undefined');
508  }
509  gContext = context;
510  let helper = photoAccessHelper.startPhotoPicker(gContext, config);
511  if (helper !== undefined) {
512    console.log('photoAccessHelper startPhotoPicker inner add createDeleteRequest');
513    helper.createDeleteRequest = createDeleteRequest;
514  }
515  return helper;
516}
517
518function getPhotoAccessHelperAsync(context, asyncCallback) {
519  if (context === undefined) {
520    console.log('photoAccessHelper gContext undefined');
521    throw Error('photoAccessHelper gContext undefined');
522  }
523  gContext = context;
524  if (arguments.length === 1) {
525    return photoAccessHelper.getPhotoAccessHelperAsync(gContext)
526      .then((helper) => {
527        if (helper !== undefined) {
528          console.log('photoAccessHelper getPhotoAccessHelperAsync inner add createDeleteRequest' +
529            ' and showAssetsCreationDialog');
530          helper.createDeleteRequest = createDeleteRequest;
531          helper.showAssetsCreationDialog = showAssetsCreationDialog;
532          helper.createAssetWithShortTermPermission = createAssetWithShortTermPermission;
533          helper.requestPhotoUrisReadPermission = requestPhotoUrisReadPermission;
534        }
535        return helper;
536      })
537      .catch((err) => {
538        console.log('photoAccessHelper getPhotoAccessHelperAsync err ' + err);
539        throw Error(err);
540      });
541  } else if (arguments.length === ARGS_TWO && typeof asyncCallback === 'function') {
542    photoAccessHelper.getPhotoAccessHelperAsync(gContext, (err, helper) => {
543      console.log('photoAccessHelper getPhotoAccessHelperAsync callback ' + err);
544      if (err) {
545        asyncCallback(err);
546      } else {
547        if (helper !== undefined) {
548          console.log('photoAccessHelper getPhotoAccessHelperAsync callback add createDeleteRequest' +
549            ' and showAssetsCreationDialog');
550          helper.createDeleteRequest = createDeleteRequest;
551          helper.showAssetsCreationDialog = showAssetsCreationDialog;
552          helper.createAssetWithShortTermPermission = createAssetWithShortTermPermission;
553          helper.requestPhotoUrisReadPermission = requestPhotoUrisReadPermission;
554        }
555        asyncCallback(err, helper);
556      }
557    });
558  } else {
559    console.log('photoAccessHelper getPhotoAccessHelperAsync param invalid');
560    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
561  }
562  return undefined;
563}
564
565const RecommendationType = {
566  // Indicates that QR code or barcode photos can be recommended
567  QR_OR_BAR_CODE: 1,
568
569  // Indicates that QR code photos can be recommended
570  QR_CODE: 2,
571
572  // Indicates that barcode photos can be recommended
573  BAR_CODE: 3,
574
575  // Indicates that QR code or barcode photos can be recommended
576  ID_CARD: 4,
577
578  // Indicates that profile picture photos can be recommended
579  PROFILE_PICTURE: 5,
580
581  // Indicates that passport photos can be recommended
582  PASSPORT: 6,
583
584  // Indicates that bank card photos can be recommended
585  BANK_CARD: 7,
586
587  // Indicates that driver license photos can be recommended
588  DRIVER_LICENSE: 8,
589
590  // Indicates that driving license photos can be recommended
591  DRIVING_LICENSE: 9,
592
593  // Indicates that featured single portrait photos can be recommended
594  FEATURED_SINGLE_PORTRAIT: 10
595};
596
597const PhotoViewMIMETypes = {
598  IMAGE_TYPE: 'image/*',
599  VIDEO_TYPE: 'video/*',
600  IMAGE_VIDEO_TYPE: '*/*',
601  MOVING_PHOTO_IMAGE_TYPE: 'image/movingPhoto',
602  INVALID_TYPE: ''
603};
604
605const ErrCode = {
606  INVALID_ARGS: 13900020,
607  RESULT_ERROR: 13900042,
608};
609
610const CompleteButtonText = {
611  TEXT_DONE: 0,
612  TEXT_SEND: 1,
613  TEXT_ADD: 2,
614};
615
616const ERRCODE_MAP = new Map([
617  [ErrCode.INVALID_ARGS, 'Invalid argument'],
618  [ErrCode.RESULT_ERROR, 'Unknown error'],
619]);
620
621const PHOTO_VIEW_MIME_TYPE_MAP = new Map([
622  [PhotoViewMIMETypes.IMAGE_TYPE, 'FILTER_MEDIA_TYPE_IMAGE'],
623  [PhotoViewMIMETypes.VIDEO_TYPE, 'FILTER_MEDIA_TYPE_VIDEO'],
624  [PhotoViewMIMETypes.IMAGE_VIDEO_TYPE, 'FILTER_MEDIA_TYPE_ALL'],
625  [PhotoViewMIMETypes.MOVING_PHOTO_IMAGE_TYPE, 'FILTER_MEDIA_TYPE_IMAGE_MOVING_PHOTO'],
626]);
627
628function checkArguments(args) {
629  let checkArgumentsResult = undefined;
630
631  if (args.length === ARGS_TWO && typeof args[ARGS_ONE] !== 'function') {
632    checkArgumentsResult = getErr(ErrCode.INVALID_ARGS);
633  }
634
635  if (args.length > 0 && typeof args[ARGS_ZERO] === 'object') {
636    let option = args[ARGS_ZERO];
637    if (option.maxSelectNumber !== undefined) {
638      if (option.maxSelectNumber.toString().indexOf('.') !== -1) {
639        checkArgumentsResult = getErr(ErrCode.INVALID_ARGS);
640      }
641    }
642  }
643
644  return checkArgumentsResult;
645}
646
647function getErr(errCode) {
648  return { code: errCode, message: ERRCODE_MAP.get(errCode) };
649}
650
651function parsePhotoPickerSelectOption(args) {
652  let config = {
653    action: 'ohos.want.action.photoPicker',
654    type: 'multipleselect',
655    parameters: {
656      uri: 'multipleselect',
657    },
658  };
659
660  if (args.length > ARGS_ZERO && typeof args[ARGS_ZERO] === 'object') {
661    let option = args[ARGS_ZERO];
662    if (option.maxSelectNumber && option.maxSelectNumber > 0) {
663      let select = (option.maxSelectNumber === 1) ? 'singleselect' : 'multipleselect';
664      config.type = select;
665      config.parameters.uri = select;
666      config.parameters.maxSelectCount = option.maxSelectNumber;
667    }
668    if (option.MIMEType && PHOTO_VIEW_MIME_TYPE_MAP.has(option.MIMEType)) {
669      config.parameters.filterMediaType = PHOTO_VIEW_MIME_TYPE_MAP.get(option.MIMEType);
670    }
671    config.parameters.isSearchSupported = option.isSearchSupported === undefined || option.isSearchSupported;
672    config.parameters.isPhotoTakingSupported = option.isPhotoTakingSupported === undefined || option.isPhotoTakingSupported;
673    config.parameters.isEditSupported = option.isEditSupported === undefined || option.isEditSupported;
674    config.parameters.recommendationOptions = option.recommendationOptions;
675    config.parameters.preselectedUris = option.preselectedUris;
676    config.parameters.isPreviewForSingleSelectionSupported = option.isPreviewForSingleSelectionSupported;
677    config.parameters.isOriginalSupported = option.isOriginalSupported;
678    config.parameters.subWindowName = option.subWindowName;
679    config.parameters.themeColor = option.themeColor;
680    config.parameters.completeButtonText = option.completeButtonText;
681  }
682
683  return config;
684}
685
686function getPhotoPickerSelectResult(args) {
687  let selectResult = {
688    error: undefined,
689    data: undefined,
690  };
691
692  if (args.resultCode === 0) {
693    let uris = args.uris;
694    let isOrigin = args.isOrigin;
695    selectResult.data = new PhotoSelectResult(uris, isOrigin);
696  } else if (args.resultCode === -1) {
697    selectResult.data = new PhotoSelectResult([], undefined);
698  } else {
699    selectResult.error = getErr(ErrCode.RESULT_ERROR);
700  }
701
702  return selectResult;
703}
704
705async function photoPickerSelect(...args) {
706  let checkArgsResult = checkArguments(args);
707  if (checkArgsResult !== undefined) {
708    console.log('[picker] Invalid argument');
709    throw checkArgsResult;
710  }
711
712  const config = parsePhotoPickerSelectOption(args);
713  console.log('[picker] config: ' + JSON.stringify(config));
714
715  try {
716    let context = getContext(this);
717    let result = await startPhotoPicker(context, config);
718    console.log('[picker] result: ' + JSON.stringify(result));
719    const selectResult = getPhotoPickerSelectResult(result);
720    console.log('[picker] selectResult: ' + JSON.stringify(selectResult));
721    if (args.length === ARGS_TWO && typeof args[ARGS_ONE] === 'function') {
722      return args[ARGS_ONE](selectResult.error, selectResult.data);
723    } else if (args.length === ARGS_ONE && typeof args[ARGS_ZERO] === 'function') {
724      return args[ARGS_ZERO](selectResult.error, selectResult.data);
725    }
726    return new Promise((resolve, reject) => {
727      if (selectResult.data !== undefined) {
728        resolve(selectResult.data);
729      } else {
730        reject(selectResult.error);
731      }
732    });
733  } catch (error) {
734    console.log('[picker] error: ' + error);
735  }
736  return undefined;
737}
738
739function BaseSelectOptions() {
740  this.MIMEType = PhotoViewMIMETypes.INVALID_TYPE;
741  this.maxSelectNumber = -1;
742  this.isSearchSupported = true;
743  this.isPhotoTakingSupported = true;
744  this.isPreviewForSingleSelectionSupported = true;
745}
746
747function PhotoSelectOptions() {
748  this.MIMEType = PhotoViewMIMETypes.INVALID_TYPE;
749  this.maxSelectNumber = -1;
750  this.isSearchSupported = true;
751  this.isPhotoTakingSupported = true;
752  this.isEditSupported = true;
753  this.isOriginalSupported = false;
754  this.completeButtonText = CompleteButtonText.TEXT_DONE;
755}
756
757function PhotoSelectResult(uris, isOriginalPhoto) {
758  this.photoUris = uris;
759  this.isOriginalPhoto = isOriginalPhoto;
760}
761
762function PhotoViewPicker() {
763  this.select = photoPickerSelect;
764}
765
766function RecommendationOptions() {
767}
768
769class MediaAssetChangeRequest extends photoAccessHelper.MediaAssetChangeRequest {
770  static deleteAssets(context, assets, asyncCallback) {
771    if (arguments.length > ARGS_THREE || arguments.length < ARGS_TWO) {
772      throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
773    }
774
775    try {
776      if (asyncCallback) {
777        return super.deleteAssets(context, result => {
778          if (result.result === REQUEST_CODE_SUCCESS) {
779            asyncCallback();
780          } else if (result.result === PERMISSION_DENIED) {
781            asyncCallback(new BusinessError(ERROR_MSG_USER_DENY, ERR_CODE_OHOS_PERMISSION_DENIED));
782          } else {
783            asyncCallback(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
784          }
785        }, assets, asyncCallback);
786      }
787
788      return new Promise((resolve, reject) => {
789        super.deleteAssets(context, result => {
790          if (result.result === REQUEST_CODE_SUCCESS) {
791            resolve();
792          } else if (result.result === PERMISSION_DENIED) {
793            reject(new BusinessError(ERROR_MSG_USER_DENY, ERR_CODE_OHOS_PERMISSION_DENIED));
794          } else {
795            reject(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
796          }
797        }, assets, (err) => {
798          if (err) {
799            reject(err);
800          } else {
801            resolve();
802          }
803        });
804      });
805    } catch (error) {
806      return errorResult(new BusinessError(error.message, error.code), asyncCallback);
807    }
808  }
809}
810
811export default {
812  getPhotoAccessHelper,
813  startPhotoPicker,
814  getPhotoAccessHelperAsync,
815  PhotoType: photoAccessHelper.PhotoType,
816  PhotoCreationConfig: photoAccessHelper.PhotoCreationConfig,
817  PhotoKeys: photoAccessHelper.PhotoKeys,
818  AlbumKeys: photoAccessHelper.AlbumKeys,
819  AlbumType: photoAccessHelper.AlbumType,
820  AlbumSubtype: photoAccessHelper.AlbumSubtype,
821  HighlightAlbum: photoAccessHelper.HighlightAlbum,
822  PositionType: photoAccessHelper.PositionType,
823  PhotoSubtype: photoAccessHelper.PhotoSubtype,
824  PhotoPermissionType: photoAccessHelper.PhotoPermissionType,
825  HideSensitiveType: photoAccessHelper.HideSensitiveType,
826  NotifyType: photoAccessHelper.NotifyType,
827  DefaultChangeUri: photoAccessHelper.DefaultChangeUri,
828  HiddenPhotosDisplayMode: photoAccessHelper.HiddenPhotosDisplayMode,
829  RequestPhotoType: photoAccessHelper.RequestPhotoType,
830  AnalysisType: photoAccessHelper.AnalysisType,
831  HighlightAlbumInfoType: photoAccessHelper.HighlightAlbumInfoType,
832  HighlightUserActionType: photoAccessHelper.HighlightUserActionType,
833  RequestPhotoType: photoAccessHelper.RequestPhotoType,
834  PhotoViewMIMETypes: PhotoViewMIMETypes,
835  DeliveryMode: photoAccessHelper.DeliveryMode,
836  SourceMode: photoAccessHelper.SourceMode,
837  AuthorizationMode: photoAccessHelper.AuthorizationMode,
838  BaseSelectOptions: BaseSelectOptions,
839  PhotoSelectOptions: PhotoSelectOptions,
840  PhotoSelectResult: PhotoSelectResult,
841  PhotoViewPicker: PhotoViewPicker,
842  RecommendationType: RecommendationType,
843  RecommendationOptions: RecommendationOptions,
844  ResourceType: photoAccessHelper.ResourceType,
845  MediaAssetEditData: photoAccessHelper.MediaAssetEditData,
846  MediaAssetChangeRequest: MediaAssetChangeRequest,
847  MediaAssetsChangeRequest: photoAccessHelper.MediaAssetsChangeRequest,
848  MediaAlbumChangeRequest: photoAccessHelper.MediaAlbumChangeRequest,
849  MediaAssetManager: photoAccessHelper.MediaAssetManager,
850  MovingPhoto: photoAccessHelper.MovingPhoto,
851  MovingPhotoEffectMode: photoAccessHelper.MovingPhotoEffectMode,
852  CompleteButtonText: CompleteButtonText,
853  ImageFileType: photoAccessHelper.ImageFileType,
854  CloudEnhancement: photoAccessHelper.CloudEnhancement,
855  CloudEnhancementTaskStage: photoAccessHelper.CloudEnhancementTaskStage,
856  CloudEnhancementState: photoAccessHelper.CloudEnhancementState,
857  CloudEnhancementTaskState: photoAccessHelper.CloudEnhancementTaskState,
858  VideoEnhancementType: photoAccessHelper.VideoEnhancementType,
859  WatermarkType: photoAccessHelper.WatermarkType,
860  CloudMediaAssetManager: photoAccessHelper.CloudMediaAssetManager,
861  CloudMediaDownloadType: photoAccessHelper.CloudMediaDownloadType,
862  CloudMediaRetainType: photoAccessHelper.CloudMediaRetainType,
863  CloudMediaAssetTaskStatus: photoAccessHelper.CloudMediaAssetTaskStatus,
864  CloudMediaTaskPauseCause: photoAccessHelper.CloudMediaTaskPauseCause,
865  CloudMediaAssetStatus: photoAccessHelper.CloudMediaAssetStatus,
866};
867