• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = requireNapi('file.photoAccessHelperNative');
17const bundleManager = requireNapi('bundle.bundleManager');
18const deviceinfo = requireInternal('deviceInfo');
19const rpc = requireInternal('rpc');
20
21const ARGS_ZERO = 0;
22const ARGS_ONE = 1;
23const ARGS_TWO = 2;
24const ARGS_THREE = 3;
25
26const WRITE_PERMISSION = 'ohos.permission.WRITE_IMAGEVIDEO';
27const ACROSS_ACCOUNTS_PERMISSION = 'ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS';
28
29const PERMISSION_DENIED = 13900012;
30const ERR_CODE_PARAMERTER_INVALID = 13900020;
31const ERR_CODE_OHOS_PERMISSION_DENIED = 201;
32const ERR_CODE_OHOS_PARAMERTER_INVALID = 401;
33const REQUEST_CODE_SUCCESS = 0;
34const PERMISSION_STATE_ERROR = -1;
35const ERROR_MSG_WRITE_PERMISSION = 'not have ohos.permission.WRITE_IMAGEVIDEO';
36const ERROR_MSG_ACROSS_ACCOUNTS_PERMISSION = 'not have ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS';
37const ERROR_MSG_USER_DENY = 'user deny';
38const ERROR_MSG_PARAMERTER_INVALID = 'input parmaeter invalid';
39const ERROR_MSG_INNER_FAIL = 'System inner fail';
40const ERROR_MSG_OHOS_INNER_FAIL = 'Internal system error';
41
42const SECONDS_OF_ONE_DAY = 24 * 60 * 60;
43const DELAY_MILLSECONDS = 33;
44const RETRY_COUNTER = 10;
45const RPC_TOKEN_RECENT_PHOTO_INFO = 'rpcRecentPhotoInfoServiceAbility';
46const RPC_MSGID_RECENT_PHOTO_INFO = 1;
47
48const MAX_DELETE_NUMBER = 300;
49const MIN_DELETE_NUMBER = 1;
50const MAX_CONFIRM_NUMBER = 100;
51const MIN_CONFIRM_NUMBER = 1;
52
53let gContext = undefined;
54
55class BusinessError extends Error {
56  constructor(msg, code) {
57    super(msg);
58    this.code = code || PERMISSION_DENIED;
59  }
60}
61
62function checkArrayAndSize(array, minSize, maxSize) {
63  // check whether input is array
64  if (!Array.isArray(array)) {
65    console.error('photoAccessHelper invalid, array is null.');
66    return false;
67  }
68
69  // check whether array length is valid
70  let len = array.length;
71  if ((len < minSize) || (len > maxSize)) {
72    console.error('photoAccessHelper invalid, array size invalid.');
73    return false;
74  }
75
76  return true;
77}
78
79function checkIsUriValid(uri, isAppUri) {
80  if (!uri) {
81    console.error('photoAccessHelper invalid, uri is null.');
82    return false;
83  }
84
85  if (typeof uri !== 'string') {
86    console.error('photoAccessHelper invalid, uri type is not string.');
87    return false;
88  }
89
90  // media library uri starts with 'file://media/Photo/', createDeleteReques delete media library resource should check
91  if (!isAppUri) {
92    return uri.includes('file://media/Photo/');
93  }
94
95  // showAssetsCreationDialog store third part application resource to media library, no need to check it
96  return true;
97}
98
99function checkParams(uriList, asyncCallback) {
100  if (arguments.length > ARGS_TWO) {
101    return false;
102  }
103  if (!checkArrayAndSize(uriList, MIN_DELETE_NUMBER, MAX_DELETE_NUMBER)) {
104    return false;
105  }
106  if (asyncCallback && typeof asyncCallback !== 'function') {
107    return false;
108  }
109  for (let uri of uriList) {
110    if (!checkIsUriValid(uri, false)) {
111      console.info(`photoAccessHelper invalid uri: ${uri}`);
112      return false;
113    }
114  }
115  return true;
116}
117function errorResult(rej, asyncCallback) {
118  if (asyncCallback) {
119    return asyncCallback(rej);
120  }
121  return new Promise((resolve, reject) => {
122    reject(rej);
123  });
124}
125
126function getAbilityResource(bundleInfo) {
127  console.info('getAbilityResource enter.');
128  let labelId = 0;
129  for (let hapInfo of bundleInfo.hapModulesInfo) {
130    if (hapInfo.type === bundleManager.ModuleType.ENTRY) {
131      labelId = getLabelId(hapInfo);
132    }
133  }
134  return labelId;
135}
136
137function getLabelId(hapInfo) {
138  let labelId = 0;
139  for (let abilityInfo of hapInfo.abilitiesInfo) {
140    let abilitiesInfoName = '';
141    if (abilityInfo.name.includes('.')) {
142      let abilitiesInfoLength = abilityInfo.name.split('.').length;
143      abilitiesInfoName = abilityInfo.name.split('.')[abilitiesInfoLength - 1];
144    } else {
145      abilitiesInfoName = abilityInfo.name;
146    }
147    if (abilitiesInfoName === hapInfo.mainElementName) {
148      labelId = abilityInfo.labelId;
149    }
150  }
151  return labelId;
152}
153
154async function getAppName() {
155  let appName = '';
156  try {
157    const flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_ABILITY | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_HAP_MODULE;
158    const bundleInfo = await bundleManager.getBundleInfoForSelf(flags);
159    console.info(`photoAccessHelper bundleInfo: ${JSON.stringify(bundleInfo)}`);
160    if (bundleInfo === undefined || bundleInfo.hapModulesInfo === undefined || bundleInfo.hapModulesInfo.length === 0) {
161      return appName;
162    }
163    const labelId = getAbilityResource(bundleInfo);
164    const resourceMgr = gContext.resourceManager;
165    appName = await resourceMgr.getStringValue(labelId);
166    console.info(`photoAccessHelper appName: ${appName}`);
167  } catch (error) {
168    console.info(`photoAccessHelper error: ${JSON.stringify(error)}`);
169  }
170
171  return appName;
172}
173
174async function createPhotoDeleteRequestParamsOk(uriList, asyncCallback) {
175  let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
176  let { reqPermissionDetails, permissionGrantStates } = await bundleManager.getBundleInfoForSelf(flags);
177  let permissionIndex = -1;
178  for (let i = 0; i < reqPermissionDetails.length; i++) {
179    if (reqPermissionDetails[i].name === WRITE_PERMISSION) {
180      permissionIndex = i;
181    }
182  }
183  if (permissionIndex < 0 || permissionGrantStates[permissionIndex] === PERMISSION_STATE_ERROR) {
184    console.info('photoAccessHelper permission error');
185    return errorResult(new BusinessError(ERROR_MSG_WRITE_PERMISSION), asyncCallback);
186  }
187  const appName = await getAppName();
188  if (appName.length === 0) {
189    console.info(`photoAccessHelper appName not found`);
190    return errorResult(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_PARAMERTER_INVALID), asyncCallback);
191  }
192  try {
193    if (asyncCallback) {
194      return photoAccessHelper.createDeleteRequest(getContext(this), appName, uriList, result => {
195        if (result.result === REQUEST_CODE_SUCCESS) {
196          asyncCallback();
197        } else if (result.result == PERMISSION_DENIED) {
198          asyncCallback(new BusinessError(ERROR_MSG_USER_DENY));
199        } else {
200          asyncCallback(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
201        }
202      });
203    } else {
204      return new Promise((resolve, reject) => {
205        photoAccessHelper.createDeleteRequest(getContext(this), appName, uriList, result => {
206          if (result.result === REQUEST_CODE_SUCCESS) {
207            resolve();
208          } else if (result.result == PERMISSION_DENIED) {
209            reject(new BusinessError(ERROR_MSG_USER_DENY));
210          } else {
211            reject(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
212          }
213        });
214      });
215    }
216  } catch (error) {
217    return errorResult(new BusinessError(error.message, error.code), asyncCallback);
218  }
219}
220
221function createDeleteRequest(...params) {
222  if (!checkParams(...params)) {
223    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_PARAMERTER_INVALID);
224  }
225  return createPhotoDeleteRequestParamsOk(...params);
226}
227
228function checkIsPhotoCreationConfigValid(config) {
229  if (!config) {
230    console.error('photoAccessHelper invalid, config is null.');
231    return false;
232  }
233
234  // check whether input is a object
235  if (typeof config !== 'object') {
236    console.error('photoAccessHelper invalid, config type is not object.');
237    return false;
238  }
239
240  // check whether title is string if exsit
241  if ((config.title) && (typeof config.title !== 'string')) {
242    console.error('photoAccessHelper invalid, config.title type is not string.');
243    return false;
244  }
245
246  // check whether fileNameExtension is string
247  if (!config.fileNameExtension) {
248    console.error('photoAccessHelper invalid, config.fileNameExtension is null.');
249    return false;
250  }
251  if (typeof config.fileNameExtension !== 'string') {
252    console.error('photoAccessHelper invalid, config.fileNameExtension type is not string.');
253    return false;
254  }
255
256  // check whether photoType is number
257  if (!config.photoType) {
258    console.error('photoAccessHelper invalid, config.photoType is null.');
259    return false;
260  }
261  if (typeof config.photoType !== 'number') {
262    console.error('photoAccessHelper invalid, config.photoType type is not number.');
263    return false;
264  }
265
266  // check whether subtype is number if exsit
267  if ((config.subtype) && (typeof config.subtype !== 'number')) {
268    console.error('photoAccessHelper invalid, config.subtype type is not number.');
269    return false;
270  }
271
272  return true;
273}
274
275function checkConfirmBoxParams(srcFileUris, photoCreationConfigs) {
276  // check param number
277  if (arguments.length > ARGS_TWO) {
278    return false;
279  }
280
281  // check whether input array is valid
282  if (!checkArrayAndSize(srcFileUris, MIN_CONFIRM_NUMBER, MAX_CONFIRM_NUMBER)) {
283    return false;
284  }
285  if (!checkArrayAndSize(photoCreationConfigs, MIN_CONFIRM_NUMBER, MAX_CONFIRM_NUMBER)) {
286    return false;
287  }
288  if (srcFileUris.length !== photoCreationConfigs.length) {
289    return false;
290  }
291
292  // check whether srcFileUris element is valid
293  for (let srcFileUri of srcFileUris) {
294    if (!checkIsUriValid(srcFileUri, true)) {
295      console.error('photoAccessHelper invalid uri: ${srcFileUri}.');
296      return false;
297    }
298  }
299
300  // check whether photoCreationConfigs element is valid
301  for (let photoCreateConfig of photoCreationConfigs) {
302    if (!checkIsPhotoCreationConfigValid(photoCreateConfig)) {
303      return false;
304    }
305  }
306
307  return true;
308}
309
310function getBundleInfo() {
311  let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_ABILITY | // for appName
312    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_HAP_MODULE | // for appName
313    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO | // for appId
314    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION; // for appInfo
315  let bundleInfo = bundleManager.getBundleInfoForSelfSync(flags);
316  if (((bundleInfo === undefined) || (bundleInfo.name === undefined)) ||
317      ((bundleInfo.hapModulesInfo === undefined) || (bundleInfo.hapModulesInfo.length === 0)) ||
318      ((bundleInfo.signatureInfo === undefined) || (bundleInfo.signatureInfo.appId === undefined)) ||
319    ((bundleInfo.appInfo === undefined) || (bundleInfo.appInfo.labelId === 0))) {
320    console.error('photoAccessHelper failed to get bundle info.');
321    return undefined;
322  }
323
324  return bundleInfo;
325}
326
327function showAssetsCreationDialogResult(result, reject, resolve) {
328  if (result.result !== REQUEST_CODE_SUCCESS) {
329    reject(new BusinessError(ERROR_MSG_OHOS_INNER_FAIL, result.result));
330  }
331
332  if (result.data === undefined) {
333    result.data = [];
334  }
335
336  resolve(result.data);
337}
338
339async function showAssetsCreationDialogParamsOk(srcFileUris, photoCreationConfigs) {
340  let bundleInfo = getBundleInfo();
341  if (bundleInfo === undefined) {
342    return new Promise((resolve, reject) => {
343      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
344    });
345  }
346
347  // get bundleName and appId and appName
348  let bundleName = bundleInfo.name;
349  let appId = bundleInfo.signatureInfo.appId;
350  console.info('photoAccessHelper bundleName is ' + bundleName + '.');
351  console.info('photoAccessHelper appId is ' + appId + '.');
352
353  let labelId = bundleInfo.appInfo.labelId;
354  console.info('photoAccessHelper labelId is ' + appId + '.');
355  let appName = '';
356
357  try {
358    let modeleName = '';
359    for (let hapInfo of bundleInfo.hapModulesInfo) {
360      if (labelId === hapInfo.labelId) {
361        modeleName = hapInfo.name;
362      }
363    }
364    console.info('photoAccessHelper modeleName is ' + modeleName + '.');
365    appName = await gContext.createModuleContext(modeleName).resourceManager.getStringValue(labelId);
366    console.info('photoAccessHelper appName is ' + appName + '.');
367    // only promise type
368    return new Promise((resolve, reject) => {
369      photoAccessHelper.showAssetsCreationDialog(getContext(this), srcFileUris, photoCreationConfigs, bundleName,
370        appName, appId, result => {
371          showAssetsCreationDialogResult(result, reject, resolve);
372      });
373    });
374  } catch (error) {
375    return errorResult(new BusinessError(error.message, error.code), null);
376  }
377}
378
379function showAssetsCreationDialog(...params) {
380  if (!checkConfirmBoxParams(...params)) {
381    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
382  }
383  return showAssetsCreationDialogParamsOk(...params);
384}
385
386async function requestPhotoUrisReadPermission(srcFileUris) {
387  console.info('requestPhotoUrisReadPermission enter');
388
389  //check whether srcFileUris is valid
390  if (srcFileUris === undefined || srcFileUris.length < MIN_CONFIRM_NUMBER) {
391    console.error('photoAccessHelper invalid, array size invalid.');
392    return false;
393  }
394  for (let srcFileUri of srcFileUris) {
395    if (!checkIsUriValid(srcFileUri, true)) {
396      console.error('photoAccesshelper invalid uri : ${srcFileUri}.');
397      return false;
398    }
399  }
400
401  let context = gContext;
402  if (context === undefined) {
403    console.info('photoAccessHelper gContet undefined');
404    context = getContext(this);
405  }
406
407  let bundleInfo = getBundleInfo();
408  if (bundleInfo === undefined) {
409    return new Promise((resolve, reject) => {
410      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
411    });
412  }
413  let labelId = bundleInfo.appInfo.labelId;
414  console.info('photoAccessHelper labelId is ' + labelId + '.');
415  let appName = '';
416
417  try {
418    let moduleName = '';
419    for (let hapInfo of bundleInfo.hapModulesInfo) {
420      if (labelId === hapInfo.labelId) {
421        moduleName = hapInfo.name;
422      }
423    }
424    console.info('photoAccessHelper moduleName is ' + moduleName + '.');
425    appName = await gContext.createModuleContext(moduleName).resourceManager.getStringValue(labelId);
426    console.info('photoAccessHelper appName is ' + appName + '.');
427    return new Promise((resolve, reject) => {
428      photoAccessHelper.requestPhotoUrisReadPermission(context, srcFileUris, appName, result => {
429        showAssetsCreationDialogResult(result, reject, resolve);
430      });
431    });
432  } catch (error) {
433    console.error('requestPhotoUrisReadPermission catch error.');
434    return errorResult(new BusinessError(ERROR_MSG_INNER_FAIL, error.code), null);
435  }
436}
437
438async function createAssetWithShortTermPermissionOk(photoCreationConfig) {
439  let bundleInfo = getBundleInfo();
440  if (bundleInfo === undefined) {
441    return new Promise((resolve, reject) => {
442      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
443    });
444  }
445
446  let bundleName = bundleInfo.name;
447  let appId = bundleInfo.signatureInfo.appId;
448  console.info('photoAccessHelper bundleName is ' + bundleName + '.');
449  console.info('photoAccessHelper appId is ' + appId + '.');
450
451  let labelId = bundleInfo.appInfo.labelId;
452  console.info('photoAccessHelper labelId is ' + appId + '.');
453  let appName = '';
454  let tokenId = bundleInfo.appInfo.accessTokenId;
455  console.info('photoAccessHelper tokenId is ' + tokenId + '.');
456
457  try {
458    let modeleName = '';
459    for (let hapInfo of bundleInfo.hapModulesInfo) {
460      if (labelId === hapInfo.labelId) {
461        modeleName = hapInfo.name;
462      }
463    }
464    console.info('photoAccessHelper modeleName is ' + modeleName + '.');
465    appName = await gContext.createModuleContext(modeleName).resourceManager.getStringValue(labelId);
466    console.info('photoAccessHelper appName is ' + appName + '.');
467
468    if (photoAccessHelper.checkShortTermPermission()) {
469      let photoCreationConfigs = [photoCreationConfig];
470      let desFileUris = await getPhotoAccessHelper(getContext(this)).createAssetsHasPermission(bundleName, appName, tokenId,
471        photoCreationConfigs);
472      return new Promise((resolve, reject) => {
473        resolve(desFileUris[0]);
474      });
475    }
476    return new Promise((resolve, reject) => {
477      photoAccessHelper.createAssetWithShortTermPermission(getContext(this), photoCreationConfig, bundleName, appName,
478        appId, result => {
479          showAssetsCreationDialogResult(result, reject, resolve);
480        });
481    });
482  } catch (error) {
483    return errorResult(new BusinessError(ERROR_MSG_INNER_FAIL, error.code), null);
484  }
485}
486
487function createAssetWithShortTermPermission(photoCreationConfig) {
488  if (!checkIsPhotoCreationConfigValid(photoCreationConfig)) {
489    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
490  }
491  return createAssetWithShortTermPermissionOk(photoCreationConfig);
492}
493
494function getPhotoPickerComponentDefaultAlbumName() {
495  let bundleInfo = getBundleInfo();
496  if (bundleInfo === undefined) {
497    return new Promise((resolve, reject) => {
498      reject(new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID));
499    });
500  }
501
502  try {
503    return new Promise((resolve, reject) => {
504      photoAccessHelper.getPhotoPickerComponentDefaultAlbumName(getContext(this), result => {
505          showAssetsCreationDialogResult(result, reject, resolve);
506        });
507    });
508  } catch (error) {
509    return errorResult(new BusinessError(ERROR_MSG_INNER_FAIL, error.code), null);
510  }
511}
512
513async function delayFunc() {
514  return new Promise(resolve => setTimeout(resolve, DELAY_MILLSECONDS));
515}
516
517function convertMIMETypeToFilterType(e) {
518    let o;
519    if (e === PhotoViewMIMETypes.IMAGE_TYPE) {
520        o = PHOTO_VIEW_MIME_TYPE_MAP.get(e);
521    } else if (e === PhotoViewMIMETypes.VIDEO_TYPE) {
522        o = PHOTO_VIEW_MIME_TYPE_MAP.get(e);
523    } else if (e === PhotoViewMIMETypes.MOVING_PHOTO_IMAGE_TYPE) {
524        o = PHOTO_VIEW_MIME_TYPE_MAP.get(e);
525    } else {
526        o = PHOTO_VIEW_MIME_TYPE_MAP.get(PhotoViewMIMETypes.IMAGE_VIDEO_TYPE);
527    }
528    console.info('convertMIMETypeToFilterType: ' + JSON.stringify(o));
529    return o;
530}
531
532function checkIsRecentPhotoOptionValid(option) {
533  if (!option) {
534    console.error('photoAccessHelper invalid, option is null.');
535    return false;
536  }
537  // check whether input type is object
538  if (typeof option !== 'object') {
539    console.error('photoAccessHelper invalid, option type is not object.');
540    return false;
541  }
542  // check whether period is number when it exist
543  if (!option.period) {
544    option.period = SECONDS_OF_ONE_DAY;
545  }
546  if (typeof option.period !== 'number') {
547    console.error('photoAccessHelper invalid, option.period type is not number.');
548    return false;
549  }
550  if (option.period <= 0 || option.period > SECONDS_OF_ONE_DAY) {
551    option.period = SECONDS_OF_ONE_DAY;
552  }
553  // check whether MIMEType is PhotoViewMIMETypes
554  if (!option.MIMEType) {
555    option.MIMEType = PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
556  }
557  if (typeof option.MIMEType !== 'string') {
558    console.error('photoAccessHelper invalid, option.MIMEType is not string.');
559    return false;
560  }
561  // convert MIMEType string
562  option.MIMEType = convertMIMETypeToFilterType(option.MIMEType);
563  const PhotoSource = {
564    ALL: 0,
565    CAMERA: 1,
566    SCREENSHOT: 2
567  };
568  // check whether photoSource valid
569  if (!option.photoSource) {
570    option.photoSource = PhotoSource.ALL;
571  }
572  if (typeof option.photoSource !== 'number') {
573    console.error('photoAccessHelper invalid, option.photoSource is not number');
574    return false;
575  }
576  if (option.photoSource < PhotoSource.ALL || option.photoSource > PhotoSource.SCREENSHOT) {
577    option.photoSource = PhotoSource.ALL;
578  }
579  return true;
580}
581
582async function rpcGetRecentPhotoInfoGetProxy() {
583  let proxy = undefined;
584  let want = {
585    'bundleName': 'com.ohos.photos',
586    'abilityName': 'RecentPhotoInfoAbility'
587  };
588  let connect = {
589    onConnect: (elementName, remoteProxy) => {
590      console.info('RpcClient: js onConnect called');
591      proxy = remoteProxy;
592    },
593    onDisconnect: (elementName) => {
594      console.info('RpcClient: onDisconnect');
595    },
596    onFailed: () => {
597      console.info('RpcClient: onFailed');
598    }
599  };
600  let context = gContext;
601  if (context === undefined) {
602    console.info('photoAccessHelper gContext undefined.');
603    context = getContext(this);
604  }
605  try {
606    let connectId = context.connectServiceExtensionAbility(want, connect);
607    let retryConter = RETRY_COUNTER;
608    while (proxy === undefined) {
609      retryConter -= 1;
610      if (retryConter < 0) {
611        break;
612      }
613      await delayFunc();
614    }
615  } catch (error) {
616    console.error('rpcGetRecentPhotoInfo Error: ' + error);
617  }
618  return proxy;
619}
620
621async function rpcGetRecentPhotoInfo(recentPhotoOption) {
622  let proxy = await rpcGetRecentPhotoInfoGetProxy();
623  if (proxy === undefined) {
624    console.error('rpcGetRecentPhotoInfo proxy is undefined');
625    return undefined;
626  }
627  let option = new rpc.MessageOption();
628  let data = rpc.MessageSequence.create();
629  let reply = rpc.MessageSequence.create();
630  try { // rpc Request
631    data.writeInterfaceToken(RPC_TOKEN_RECENT_PHOTO_INFO);
632    data.writeInt(recentPhotoOption.period);
633    data.writeString(recentPhotoOption.MIMEType);
634    data.writeInt(recentPhotoOption.photoSource);
635    let result = await proxy.sendMessageRequest(RPC_MSGID_RECENT_PHOTO_INFO, data, reply, option);
636    if (result.errCode !== 0) {
637      console.error('rpcGetRecentPhotoInfo sendMessageRequest failed, errCode: ' + result.errCode);
638      return undefined;
639    }
640    let dateTaken = result.reply.readLong();
641    let identifier = result.reply.readString();
642    console.info('rpcGetRecentPhotoInfo sendMessageRequest succ, result: ' + dateTaken);
643    return {'dateTaken': dateTaken, 'identifier': identifier};
644  } catch (err) {
645    console.error('rpcGetRecentPhotoInfo sendMessageRequest failed: ' + err);
646    return undefined;
647  } finally {
648    data.reclaim();
649    reply.reclaim();
650  }
651}
652
653async function getRecentPhotoInfoOk(recentPhotoOption) {
654  try {
655    console.info('getRecentPhotoInfoOk enter');
656    let photoInfo = rpcGetRecentPhotoInfo(recentPhotoOption);
657    if (!photoInfo) {
658      photoInfo = { dateTaken: -1, identifier: '-1' };
659    }
660    if (photoInfo.dateTaken === 0) {
661      photoInfo.identifier = '0';
662    }
663    console.info('recentPhotoInfo result: ' + photoInfo.identifier);
664    return new Promise((resolve, reject) => {
665      resolve(photoInfo);
666    });
667  } catch (error) {
668    return errorResult(new BusinessError(ERROR_MSG_INNER_FAIL, error.code), null);
669  }
670}
671
672function getRecentPhotoInfo(recentPhotoOption) {
673  if (!checkIsRecentPhotoOptionValid(recentPhotoOption)) {
674    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
675  }
676  return getRecentPhotoInfoOk(recentPhotoOption);
677}
678
679function getPhotoAccessHelper(context, userId = -1) {
680  if (context === undefined) {
681    console.log('photoAccessHelper gContext undefined');
682    throw Error('photoAccessHelper gContext undefined');
683  }
684  gContext = context;
685  let helper = photoAccessHelper.getPhotoAccessHelper(gContext, userId);
686  if (helper !== undefined && helper.constructor.prototype.createDeleteRequest === undefined) {
687    console.log('photoAccessHelper getPhotoAccessHelper inner add createDeleteRequest and showAssetsCreationDialog');
688    helper.constructor.prototype.createDeleteRequest = createDeleteRequest;
689    helper.constructor.prototype.showAssetsCreationDialog = showAssetsCreationDialog;
690    helper.constructor.prototype.createAssetWithShortTermPermission = createAssetWithShortTermPermission;
691    helper.constructor.prototype.requestPhotoUrisReadPermission = requestPhotoUrisReadPermission;
692    helper.constructor.prototype.getPhotoPickerComponentDefaultAlbumName = getPhotoPickerComponentDefaultAlbumName;
693    helper.constructor.prototype.getRecentPhotoInfo = getRecentPhotoInfo;
694  }
695  return helper;
696}
697
698function startPhotoPicker(context, config) {
699  if (context === undefined) {
700    console.log('photoAccessHelper gContext undefined');
701    throw Error('photoAccessHelper gContext undefined');
702  }
703  if (config === undefined) {
704    console.log('photoAccessHelper config undefined');
705    throw Error('photoAccessHelper config undefined');
706  }
707  gContext = context;
708  let helper = photoAccessHelper.startPhotoPicker(gContext, config);
709  if (helper !== undefined) {
710    console.log('photoAccessHelper startPhotoPicker inner add createDeleteRequest');
711    helper.createDeleteRequest = createDeleteRequest;
712  }
713  return helper;
714}
715
716function getPhotoAccessHelperAsync(context, asyncCallback) {
717  if (context === undefined) {
718    console.log('photoAccessHelper gContext undefined');
719    throw Error('photoAccessHelper gContext undefined');
720  }
721  gContext = context;
722  if (arguments.length === 1) {
723    return photoAccessHelper.getPhotoAccessHelperAsync(gContext)
724      .then((helper) => {
725        if (helper !== undefined) {
726          console.log('photoAccessHelper getPhotoAccessHelperAsync inner add createDeleteRequest' +
727            ' and showAssetsCreationDialog');
728          helper.createDeleteRequest = createDeleteRequest;
729          helper.showAssetsCreationDialog = showAssetsCreationDialog;
730          helper.createAssetWithShortTermPermission = createAssetWithShortTermPermission;
731          helper.requestPhotoUrisReadPermission = requestPhotoUrisReadPermission;
732          helper.getPhotoPickerComponentDefaultAlbumName = getPhotoPickerComponentDefaultAlbumName;
733          helper.getRecentPhotoInfo = getRecentPhotoInfo;
734        }
735        return helper;
736      })
737      .catch((err) => {
738        console.log('photoAccessHelper getPhotoAccessHelperAsync err ' + err);
739        throw Error(err);
740      });
741  } else if (arguments.length === ARGS_TWO && typeof asyncCallback === 'function') {
742    photoAccessHelper.getPhotoAccessHelperAsync(gContext, (err, helper) => {
743      console.log('photoAccessHelper getPhotoAccessHelperAsync callback ' + err);
744      if (err) {
745        asyncCallback(err);
746      } else {
747        if (helper !== undefined) {
748          console.log('photoAccessHelper getPhotoAccessHelperAsync callback add createDeleteRequest' +
749            ' and showAssetsCreationDialog');
750          helper.createDeleteRequest = createDeleteRequest;
751          helper.showAssetsCreationDialog = showAssetsCreationDialog;
752          helper.createAssetWithShortTermPermission = createAssetWithShortTermPermission;
753          helper.requestPhotoUrisReadPermission = requestPhotoUrisReadPermission;
754          helper.getPhotoPickerComponentDefaultAlbumName = getPhotoPickerComponentDefaultAlbumName;
755          helper.getRecentPhotoInfo = getRecentPhotoInfo;
756        }
757        asyncCallback(err, helper);
758      }
759    });
760  } else {
761    console.log('photoAccessHelper getPhotoAccessHelperAsync param invalid');
762    throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
763  }
764  return undefined;
765}
766
767const RecommendationType = {
768  // Indicates that QR code or barcode photos can be recommended
769  QR_OR_BAR_CODE: 1,
770
771  // Indicates that QR code photos can be recommended
772  QR_CODE: 2,
773
774  // Indicates that barcode photos can be recommended
775  BAR_CODE: 3,
776
777  // Indicates that QR code or barcode photos can be recommended
778  ID_CARD: 4,
779
780  // Indicates that profile picture photos can be recommended
781  PROFILE_PICTURE: 5,
782
783  // Indicates that passport photos can be recommended
784  PASSPORT: 6,
785
786  // Indicates that bank card photos can be recommended
787  BANK_CARD: 7,
788
789  // Indicates that driver license photos can be recommended
790  DRIVER_LICENSE: 8,
791
792  // Indicates that driving license photos can be recommended
793  DRIVING_LICENSE: 9,
794
795  // Indicates that featured single portrait photos can be recommended
796  FEATURED_SINGLE_PORTRAIT: 10
797};
798
799const PhotoViewMIMETypes = {
800  IMAGE_TYPE: 'image/*',
801  VIDEO_TYPE: 'video/*',
802  IMAGE_VIDEO_TYPE: '*/*',
803  MOVING_PHOTO_IMAGE_TYPE: 'image/movingPhoto',
804  JPEG_IMAGE_TYPE: 'image/jpeg',
805  GIF_IMAGE_TYPE: 'image/gif',
806  PNG_IMAGE_TYPE: 'image/png',
807  HEIC_IMAGE_TYPE: 'image/heic',
808  HEIF_IMAGE_TYPE: 'image/heif',
809  BMP_IMAGE_TYPE: 'image/bmp',
810  WEBP_IMAGE_TYPE: 'image/webp',
811  AVIF_IMAGE_TYPE: 'image/avif',
812  MP4_VIDEO_TYPE: 'video/mp4',
813  MOV_VIDEO_TYPE: 'video/quicktime',
814  INVALID_TYPE: ''
815};
816
817const FilterOperator = {
818  INVALID_OPERATOR: -1,
819  EQUAL_TO:  0,
820  NOT_EQUAL_TO: 1,
821  MORE_THAN: 2,
822  LESS_THAN: 3,
823  MORE_THAN_OR_EQUAL_TO:  4,
824  LESS_THAN_OR_EQUAL_TO: 5,
825  BETWEEN: 6,
826};
827
828const SingleSelectionMode = {
829  BROWSER_MODE: 0,
830  SELECT_MODE: 1,
831  BROWSER_AND_SELECT_MODE: 2,
832};
833
834const ErrCode = {
835  INVALID_ARGS: 13900020,
836  RESULT_ERROR: 13900042,
837  CONTEXT_NO_EXIST: 16000011,
838};
839
840const CompleteButtonText = {
841  TEXT_DONE: 0,
842  TEXT_SEND: 1,
843  TEXT_ADD: 2,
844};
845
846const ERRCODE_MAP = new Map([
847  [ErrCode.INVALID_ARGS, 'Invalid argument'],
848  [ErrCode.RESULT_ERROR, 'Unknown error'],
849  [ErrCode.CONTEXT_NO_EXIST, 'Current ability failed to obtain context'],
850]);
851
852const PHOTO_VIEW_MIME_TYPE_MAP = new Map([
853  [PhotoViewMIMETypes.IMAGE_TYPE, 'FILTER_MEDIA_TYPE_IMAGE'],
854  [PhotoViewMIMETypes.VIDEO_TYPE, 'FILTER_MEDIA_TYPE_VIDEO'],
855  [PhotoViewMIMETypes.IMAGE_VIDEO_TYPE, 'FILTER_MEDIA_TYPE_ALL'],
856  [PhotoViewMIMETypes.MOVING_PHOTO_IMAGE_TYPE, 'FILTER_MEDIA_TYPE_IMAGE_MOVING_PHOTO'],
857  [PhotoViewMIMETypes.JPEG_IMAGE_TYPE, 'JPEG_IMAGE_TYPE'],
858  [PhotoViewMIMETypes.GIF_IMAGE_TYPE, 'GIF_IMAGE_TYPE'],
859  [PhotoViewMIMETypes.PNG_IMAGE_TYPE, 'PNG_IMAGE_TYPE'],
860  [PhotoViewMIMETypes.HEIC_IMAGE_TYPE, 'HEIC_IMAGE_TYPE'],
861  [PhotoViewMIMETypes.HEIF_IMAGE_TYPE, 'HEIF_IMAGE_TYPE'],
862  [PhotoViewMIMETypes.BMP_IMAGE_TYPE, 'BMP_IMAGE_TYPE'],
863  [PhotoViewMIMETypes.WEBP_IMAGE_TYPE, 'WEBP_IMAGE_TYPE'],
864  [PhotoViewMIMETypes.AVIF_IMAGE_TYPE, 'AVIF_IMAGE_TYPE'],
865  [PhotoViewMIMETypes.MP4_VIDEO_TYPE, 'MP4_VIDEO_TYPE'],
866  [PhotoViewMIMETypes.MOV_VIDEO_TYPE, 'MOV_VIDEO_TYPE'],
867]);
868
869function checkArguments(args) {
870  let checkArgumentsResult = undefined;
871
872  if (args.length === ARGS_TWO && typeof args[ARGS_ONE] !== 'function') {
873    checkArgumentsResult = getErr(ErrCode.INVALID_ARGS);
874  }
875
876  if (args.length > 0 && typeof args[ARGS_ZERO] === 'object') {
877    let option = args[ARGS_ZERO];
878    if (option.maxSelectNumber !== undefined) {
879      if (option.maxSelectNumber.toString().indexOf('.') !== -1) {
880        checkArgumentsResult = getErr(ErrCode.INVALID_ARGS);
881      }
882    }
883  }
884
885  return checkArgumentsResult;
886}
887
888function getErr(errCode) {
889  return { code: errCode, message: ERRCODE_MAP.get(errCode) };
890}
891
892function parsePhotoPickerSelectOption(args) {
893  let config = {
894    action: 'ohos.want.action.photoPicker',
895    type: 'multipleselect',
896    parameters: {
897      uri: 'multipleselect',
898    },
899  };
900
901  if (args.length > ARGS_ZERO && typeof args[ARGS_ZERO] === 'object') {
902    let option = args[ARGS_ZERO];
903    if (option.maxSelectNumber && option.maxSelectNumber > 0) {
904      let select = (option.maxSelectNumber === 1) ? 'singleselect' : 'multipleselect';
905      config.type = select;
906      config.parameters.uri = select;
907      config.parameters.maxSelectCount = option.maxSelectNumber;
908    }
909    if (option.MIMEType && PHOTO_VIEW_MIME_TYPE_MAP.has(option.MIMEType)) {
910      config.parameters.filterMediaType = PHOTO_VIEW_MIME_TYPE_MAP.get(option.MIMEType);
911    }
912    config.parameters.isSearchSupported = option.isSearchSupported === undefined || option.isSearchSupported;
913    config.parameters.isPhotoTakingSupported = option.isPhotoTakingSupported === undefined || option.isPhotoTakingSupported;
914    config.parameters.isEditSupported = option.isEditSupported === undefined || option.isEditSupported;
915    config.parameters.recommendationOptions = option.recommendationOptions;
916    config.parameters.preselectedUris = option.preselectedUris;
917    config.parameters.isPreviewForSingleSelectionSupported = option.isPreviewForSingleSelectionSupported;
918    config.parameters.singleSelectionMode = option.singleSelectionMode;
919    config.parameters.isOriginalSupported = option.isOriginalSupported;
920    config.parameters.subWindowName = option.subWindowName;
921    config.parameters.themeColor = option.themeColor;
922    config.parameters.completeButtonText = option.completeButtonText;
923    config.parameters.userId = option.userId;
924    config.parameters.mimeTypeFilter = parseMimeTypeFilter(option.mimeTypeFilter);
925    config.parameters.fileSizeFilter = option.fileSizeFilter;
926    config.parameters.videoDurationFilter = option.videoDurationFilter;
927    config.parameters.photoViewMimeTypeFileSizeFilters = option.photoViewMimeTypeFileSizeFilters;
928    config.parameters.combinedMediaTypeFilter = option.combinedMediaTypeFilter;
929    config.parameters.isPc = deviceinfo.deviceType === '2in1';
930  }
931
932  return config;
933}
934
935function parseMimeTypeFilter(filter) {
936  if (!filter) {
937      return undefined;
938  }
939  let o = {};
940  o.mimeTypeArray = [];
941  if (filter.mimeTypeArray) {
942    for (let mimeType of filter.mimeTypeArray) {
943      if (PHOTO_VIEW_MIME_TYPE_MAP.has(mimeType)) {
944        o.mimeTypeArray.push(PHOTO_VIEW_MIME_TYPE_MAP.get(mimeType));
945      } else {
946        o.mimeTypeArray.push(mimeType);
947      }
948    }
949  }
950  return o;
951}
952
953function getPhotoPickerSelectResult(args) {
954  let selectResult = {
955    error: undefined,
956    data: undefined,
957  };
958
959  if (args.resultCode === 0) {
960    let uris = args.uris;
961    let isOrigin = args.isOrigin;
962    selectResult.data = new PhotoSelectResult(uris, isOrigin);
963  } else if (args.resultCode === -1) {
964    selectResult.data = new PhotoSelectResult([], undefined);
965  } else {
966    selectResult.error = getErr(ErrCode.RESULT_ERROR);
967  }
968
969  return selectResult;
970}
971
972async function photoPickerSelect(...args) {
973  let checkArgsResult = checkArguments(args);
974  if (checkArgsResult !== undefined) {
975    console.log('[picker] Invalid argument');
976    throw checkArgsResult;
977  }
978
979  const config = parsePhotoPickerSelectOption(args);
980  console.log('[picker] config: ' + encrypt(JSON.stringify(config)));
981  if (config.parameters.userId && config.parameters.userId > 0) {
982    let check = await checkInteractAcrossLocalAccounts();
983    if (!check) {
984      console.log('[picker] error: ' + ERROR_MSG_ACROSS_ACCOUNTS_PERMISSION);
985      return undefined;
986    }
987  }
988
989  let context = undefined;
990  try {
991    context = getContext(this);
992  } catch (getContextError) {
993    console.error('[picker] getContext error: ' + getContextError);
994    throw getErr(ErrCode.CONTEXT_NO_EXIST);
995  }
996  try {
997    if (context === undefined) {
998      throw getErr(ErrCode.CONTEXT_NO_EXIST);
999    }
1000    let result = await startPhotoPicker(context, config);
1001    console.log('[picker] result: ' + encrypt(JSON.stringify(result)));
1002    const selectResult = getPhotoPickerSelectResult(result);
1003    console.log('[picker] selectResult: ' + encrypt(JSON.stringify(selectResult)));
1004    if (args.length === ARGS_TWO && typeof args[ARGS_ONE] === 'function') {
1005      return args[ARGS_ONE](selectResult.error, selectResult.data);
1006    } else if (args.length === ARGS_ONE && typeof args[ARGS_ZERO] === 'function') {
1007      return args[ARGS_ZERO](selectResult.error, selectResult.data);
1008    }
1009    return new Promise((resolve, reject) => {
1010      if (selectResult.data !== undefined) {
1011        resolve(selectResult.data);
1012      } else {
1013        reject(selectResult.error);
1014      }
1015    });
1016  } catch (error) {
1017    console.error('[picker] error: ' + JSON.stringify(error));
1018  }
1019  return undefined;
1020}
1021
1022async function checkInteractAcrossLocalAccounts() {
1023  let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
1024  let { reqPermissionDetails, permissionGrantStates } = await bundleManager.getBundleInfoForSelf(flags);
1025  let permissionIndex = -1;
1026  for (let i = 0; i < reqPermissionDetails.length; i++) {
1027    if (reqPermissionDetails[i].name === ACROSS_ACCOUNTS_PERMISSION) {
1028      permissionIndex = i;
1029    }
1030  }
1031  if (permissionIndex < 0 || permissionGrantStates[permissionIndex] === PERMISSION_STATE_ERROR) {
1032    return false;
1033  } else {
1034    return true;
1035  }
1036}
1037
1038function MimeTypeFilter() {
1039  this.mimeTypeArray = [];
1040}
1041
1042function FileSizeFilter() {
1043  this.filterOperator = -1;
1044  this.fileSize = -1;
1045}
1046
1047function VideoDurationFilter() {
1048  this.filterOperator = -1;
1049  this.videoDuration = -1;
1050}
1051
1052function FileSizeFilterArray() {
1053  this.photoViewMimeTypeFileSizeFilters = [];
1054}
1055
1056function BaseSelectOptions() {
1057  this.MIMEType = PhotoViewMIMETypes.INVALID_TYPE;
1058  this.maxSelectNumber = -1;
1059  this.isSearchSupported = true;
1060  this.isPhotoTakingSupported = true;
1061  this.isPreviewForSingleSelectionSupported = true;
1062  this.singleSelectionMode = SingleSelectionMode.BROWSER_MODE;
1063}
1064
1065function PhotoSelectOptions() {
1066  this.MIMEType = PhotoViewMIMETypes.INVALID_TYPE;
1067  this.maxSelectNumber = -1;
1068  this.isSearchSupported = true;
1069  this.isPhotoTakingSupported = true;
1070  this.isEditSupported = true;
1071  this.isOriginalSupported = false;
1072  this.completeButtonText = CompleteButtonText.TEXT_DONE;
1073  this.userId = -1;
1074}
1075
1076function PhotoSelectResult(uris, isOriginalPhoto) {
1077  this.photoUris = uris;
1078  this.isOriginalPhoto = isOriginalPhoto;
1079}
1080
1081function PhotoViewPicker() {
1082  this.select = photoPickerSelect;
1083}
1084
1085function RecommendationOptions() {
1086}
1087
1088function encrypt(data) {
1089  if (!data || data?.indexOf('file:///data/storage/') !== -1) {
1090    return '';
1091  }
1092  return data.replace(/(\/\w+)\./g, '/******.');
1093}
1094
1095class MediaAssetChangeRequest extends photoAccessHelper.MediaAssetChangeRequest {
1096  static deleteAssets(context, assets, asyncCallback) {
1097    if (arguments.length > ARGS_THREE || arguments.length < ARGS_TWO) {
1098      throw new BusinessError(ERROR_MSG_PARAMERTER_INVALID, ERR_CODE_OHOS_PARAMERTER_INVALID);
1099    }
1100
1101    try {
1102      if (asyncCallback) {
1103        return super.deleteAssets(context, result => {
1104          if (result.result === REQUEST_CODE_SUCCESS) {
1105            asyncCallback();
1106          } else if (result.result === PERMISSION_DENIED) {
1107            asyncCallback(new BusinessError(ERROR_MSG_USER_DENY, ERR_CODE_OHOS_PERMISSION_DENIED));
1108          } else {
1109            asyncCallback(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
1110          }
1111        }, assets, asyncCallback);
1112      }
1113
1114      return new Promise((resolve, reject) => {
1115        super.deleteAssets(context, result => {
1116          if (result.result === REQUEST_CODE_SUCCESS) {
1117            resolve();
1118          } else if (result.result === PERMISSION_DENIED) {
1119            reject(new BusinessError(ERROR_MSG_USER_DENY, ERR_CODE_OHOS_PERMISSION_DENIED));
1120          } else {
1121            reject(new BusinessError(ERROR_MSG_INNER_FAIL, result.result));
1122          }
1123        }, assets, (err) => {
1124          if (err) {
1125            reject(err);
1126          } else {
1127            resolve();
1128          }
1129        });
1130      });
1131    } catch (error) {
1132      return errorResult(new BusinessError(error.message, error.code), asyncCallback);
1133    }
1134  }
1135}
1136
1137export default {
1138  getPhotoAccessHelper,
1139  startPhotoPicker,
1140  getPhotoAccessHelperAsync,
1141  PhotoType: photoAccessHelper.PhotoType,
1142  ThumbnailType: photoAccessHelper.ThumbnailType,
1143  PhotoCreationConfig: photoAccessHelper.PhotoCreationConfig,
1144  PhotoKeys: photoAccessHelper.PhotoKeys,
1145  AlbumKeys: photoAccessHelper.AlbumKeys,
1146  AlbumType: photoAccessHelper.AlbumType,
1147  AlbumSubtype: photoAccessHelper.AlbumSubtype,
1148  AnalysisAlbum: photoAccessHelper.AnalysisAlbum,
1149  HighlightAlbum: photoAccessHelper.HighlightAlbum,
1150  PositionType: photoAccessHelper.PositionType,
1151  PhotoSubtype: photoAccessHelper.PhotoSubtype,
1152  PhotoPermissionType: photoAccessHelper.PhotoPermissionType,
1153  HideSensitiveType: photoAccessHelper.HideSensitiveType,
1154  NotifyType: photoAccessHelper.NotifyType,
1155  DefaultChangeUri: photoAccessHelper.DefaultChangeUri,
1156  HiddenPhotosDisplayMode: photoAccessHelper.HiddenPhotosDisplayMode,
1157  AnalysisType: photoAccessHelper.AnalysisType,
1158  HighlightAlbumInfoType: photoAccessHelper.HighlightAlbumInfoType,
1159  HighlightUserActionType: photoAccessHelper.HighlightUserActionType,
1160  RequestPhotoType: photoAccessHelper.RequestPhotoType,
1161  PhotoViewMIMETypes: PhotoViewMIMETypes,
1162  SingleSelectionMode: SingleSelectionMode,
1163  MimeTypeFilter: MimeTypeFilter,
1164  FileSizeFilter: FileSizeFilter,
1165  VideoDurationFilter: VideoDurationFilter,
1166  PhotoViewMimeTypeFileSizeFilters: FileSizeFilterArray,
1167  FilterOperator: FilterOperator,
1168  DeliveryMode: photoAccessHelper.DeliveryMode,
1169  SourceMode: photoAccessHelper.SourceMode,
1170  AuthorizationMode: photoAccessHelper.AuthorizationMode,
1171  CompatibleMode: photoAccessHelper.CompatibleMode,
1172  BaseSelectOptions: BaseSelectOptions,
1173  PhotoSelectOptions: PhotoSelectOptions,
1174  PhotoSelectResult: PhotoSelectResult,
1175  PhotoViewPicker: PhotoViewPicker,
1176  RecommendationType: RecommendationType,
1177  RecommendationOptions: RecommendationOptions,
1178  ResourceType: photoAccessHelper.ResourceType,
1179  MediaAssetEditData: photoAccessHelper.MediaAssetEditData,
1180  MediaAssetChangeRequest: MediaAssetChangeRequest,
1181  MediaAssetsChangeRequest: photoAccessHelper.MediaAssetsChangeRequest,
1182  MediaAlbumChangeRequest: photoAccessHelper.MediaAlbumChangeRequest,
1183  MediaAnalysisAlbumChangeRequest: photoAccessHelper.MediaAnalysisAlbumChangeRequest,
1184  MediaAssetManager: photoAccessHelper.MediaAssetManager,
1185  MovingPhoto: photoAccessHelper.MovingPhoto,
1186  MovingPhotoEffectMode: photoAccessHelper.MovingPhotoEffectMode,
1187  CompleteButtonText: CompleteButtonText,
1188  ImageFileType: photoAccessHelper.ImageFileType,
1189  CloudEnhancement: photoAccessHelper.CloudEnhancement,
1190  CloudEnhancementTaskStage: photoAccessHelper.CloudEnhancementTaskStage,
1191  CloudEnhancementState: photoAccessHelper.CloudEnhancementState,
1192  CloudEnhancementTaskState: photoAccessHelper.CloudEnhancementTaskState,
1193  WatermarkType: photoAccessHelper.WatermarkType,
1194  VideoEnhancementType: photoAccessHelper.VideoEnhancementType,
1195  CloudMediaAssetManager: photoAccessHelper.CloudMediaAssetManager,
1196  CloudMediaDownloadType: photoAccessHelper.CloudMediaDownloadType,
1197  CloudMediaRetainType: photoAccessHelper.CloudMediaRetainType,
1198  CloudMediaAssetTaskStatus: photoAccessHelper.CloudMediaAssetTaskStatus,
1199  CloudMediaTaskPauseCause: photoAccessHelper.CloudMediaTaskPauseCause,
1200  CloudMediaAssetStatus: photoAccessHelper.CloudMediaAssetStatus,
1201  PhotoAssetCustomRecordManager: photoAccessHelper.PhotoAssetCustomRecordManager,
1202  PhotoAssetCustomRecord: photoAccessHelper.PhotoAssetCustomRecord,
1203  NotifyChangeType: photoAccessHelper.NotifyChangeType,
1204  ThumbnailChangeStatus: photoAccessHelper.ThumbnailChangeStatus,
1205  StrongAssociationType: photoAccessHelper.StrongAssociationType,
1206};
1207