• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE "ability.want.params.uiExtensionTargetType"
17 #define OHOS_WANT_ACTION_PHOTOPICKER "ohos.want.action.photoPicker"
18 
19 #include "photo_accesshelper_impl.h"
20 
21 #include <fcntl.h>
22 #include <functional>
23 #include <sys/sendfile.h>
24 
25 #include "array_wrapper.h"
26 #include "confirm_callback.h"
27 #include "context.h"
28 #include "int_wrapper.h"
29 #include "media_file_utils.h"
30 #include "medialibrary_client_errno.h"
31 #include "medialibrary_data_manager.h"
32 #include "medialibrary_db_const.h"
33 #include "modal_ui_callback.h"
34 #include "modal_ui_extension_config.h"
35 #include "napi_base_context.h"
36 #include "napi_common_want.h"
37 #include "story_album_column.h"
38 #include "string_wrapper.h"
39 #include "ui_content.h"
40 #include "ui_extension_context.h"
41 #include "userfilemgr_uri.h"
42 #include "vision_column.h"
43 #include "want.h"
44 #include "want_params.h"
45 #include "want_params_wrapper.h"
46 #include "window.h"
47 
48 using namespace std;
49 using namespace OHOS::AppExecFwk;
50 using namespace OHOS::DataShare;
51 using namespace OHOS::FFI;
52 
53 namespace OHOS {
54 namespace Media {
55 using ChangeType = AAFwk::ChangeInfo::ChangeType;
56 thread_local unique_ptr<ChangeListener> g_listObj = nullptr;
57 mutex PhotoAccessHelperImpl::sUserFileClientMutex_;
58 mutex PhotoAccessHelperImpl::sOnOffMutex_;
59 int64_t PhotoAccessHelperImpl::contextId;
60 
61 static map<string, FfiListenerType> FfiListenerTypeMaps = {
62     {"audioChange", FfiListenerType::CJ_AUDIO_LISTENER},
63     {"videoChange", FfiListenerType::CJ_VIDEO_LISTENER},
64     {"imageChange", FfiListenerType::CJ_IMAGE_LISTENER},
65     {"fileChange", FfiListenerType::CJ_FILE_LISTENER},
66     {"albumChange", FfiListenerType::CJ_ALBUM_LISTENER},
67     {"deviceChange", FfiListenerType::CJ_DEVICE_LISTENER},
68     {"remoteFileChange", FfiListenerType::CJ_REMOTECJ_FILE_LISTENER}
69 };
70 
71 static map<int32_t, string> PHOTO_VIEW_MIME_TYPE_MAP = {
72     {0, "FILTER_MEDIA_TYPE_IMAGE"},
73     {1, "FILTER_MEDIA_TYPE_VIDEO"},
74     {2, "FILTER_MEDIA_TYPE_ALL"},
75     {3, "FILTER_MEDIA_TYPE_IMAGE_MOVING_PHOTO"}
76 };
77 
78 const int32_t SLEEP_TIME = 100;
79 const int32_t MAX_QUERY_LIMIT = 500;
80 const int32_t DEFAULT_SESSION_ID = 0;
81 constexpr uint32_t CONFIRM_BOX_ARRAY_MIN_LENGTH = 1;
82 constexpr uint32_t CONFIRM_BOX_ARRAY_MAX_LENGTH = 100;
83 
84 const std::string EXTENSION = "fileNameExtension";
85 const std::string PHOTO_TYPE = "photoType";
86 const std::string PHOTO_SUB_TYPE = "subtype";
87 const std::string SHORT_TERM_TITLE = "title";
88 const std::string CONFIRM_BOX_PACKAGE_NAME = "com.ohos.photos";
89 const std::string CONFIRM_BOX_EXT_ABILITY_NAME = "SaveUIExtensionAbility";
90 const std::string CONFIRM_BOX_EXTENSION_TYPE = "ability.want.params.uiExtensionType";
91 const std::string CONFIRM_BOX_REQUEST_TYPE = "sysDialog/common";
92 const std::string CONFIRM_BOX_SRC_FILE_URIS = "ability.params.stream";
93 const std::string CONFIRM_BOX_TITLE_ARRAY = "titleArray";
94 const std::string CONFIRM_BOX_EXTENSION_ARRAY = "extensionArray";
95 const std::string CONFIRM_BOX_PHOTO_TYPE_ARRAY = "photoTypeArray";
96 const std::string CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY = "photoSubTypeArray";
97 const std::string CONFIRM_BOX_BUNDLE_NAME = "bundleName";
98 const std::string CONFIRM_BOX_APP_NAME = "appName";
99 const std::string CONFIRM_BOX_APP_ID = "appId";
100 
OnChange(FfiMediaChangeListener & listener)101 void ChangeListener::OnChange(FfiMediaChangeListener &listener)
102 {
103     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(listener.callbackRef, listener.changeInfo, listener.strUri);
104     if (msg == nullptr) {
105         LOGE("OnChange initialize UvChangeMsg failed.");
106         return;
107     }
108     if (!listener.changeInfo.uris_.empty()) {
109         if (listener.changeInfo.changeType_ == DataShare::DataShareObserver::ChangeType::OTHER) {
110             LOGE("changeInfo.changeType_ is other");
111             delete msg;
112             return;
113         }
114         if (msg->changeInfo_.size_ > 0) {
115             msg->data_ = static_cast<uint8_t *>(malloc(msg->changeInfo_.size_));
116             if (msg->data_ == nullptr) {
117                 LOGE("new msg->data failed");
118                 delete msg;
119                 return;
120             }
121             int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
122             if (copyRet != 0) {
123                 LOGE("Parcel data copy failed, err = %{public}d", copyRet);
124             }
125         }
126     }
127     UvQueueWork(msg);
128     free(msg->data_);
129     delete msg;
130 }
131 
SetUrisArray(const std::list<Uri> listValue,ChangeData & changeData)132 static void SetUrisArray(const std::list<Uri> listValue, ChangeData &changeData)
133 {
134     CArrString uris = { .head = nullptr, .size = 0 };
135     uris.head = static_cast<char **>(malloc(sizeof(char *) * listValue.size()));
136     if (uris.head == nullptr) {
137         LOGE("SetUrisArray uris.head malloc failed.");
138         return;
139     }
140     int i = 0;
141     for (auto uri : listValue) {
142         uris.head[i++] = MallocCString(uri.ToString());
143     }
144     uris.size = static_cast<int64_t>(listValue.size());
145     changeData.uris = uris;
146 }
147 
SetSubUris(const shared_ptr<MessageParcel> parcel,ChangeData & changeData)148 static void SetSubUris(const shared_ptr<MessageParcel> parcel, ChangeData &changeData)
149 {
150     uint32_t len = 0;
151     if (!parcel->ReadUint32(len)) {
152         LOGE("Failed to read sub uri list length");
153         return;
154     }
155     if (len > MAX_QUERY_LIMIT) {
156         LOGE("suburi length exceed the limit.");
157         return;
158     }
159     CArrString subUriArray = { .head = nullptr, .size = 0 };
160     subUriArray.head = static_cast<char **>(malloc(sizeof(char *) * len));
161     if (subUriArray.head == nullptr) {
162         LOGE("SetSubUris subUriArray.head malloc failed.");
163         return;
164     }
165     for (uint32_t i = 0; i < len; i++) {
166         string subUri = parcel->ReadString();
167         if (subUri.empty()) {
168             LOGE("Failed to read sub uri");
169             for (uint32_t j = 0; j < i; j++) {
170                 free(subUriArray.head[j]);
171             }
172             free(subUriArray.head);
173             subUriArray.head = nullptr;
174             return;
175         }
176         subUriArray.head[i] = MallocCString(subUri);
177     }
178     subUriArray.size = static_cast<int64_t>(len);
179     changeData.extraUris = subUriArray;
180 }
181 
SolveOnChange(UvChangeMsg * msg,ChangeData & changeData)182 void ChangeListener::SolveOnChange(UvChangeMsg *msg, ChangeData &changeData)
183 {
184     if (msg->changeInfo_.uris_.empty()) {
185         return;
186     }
187     SetUrisArray(msg->changeInfo_.uris_, changeData);
188     if (msg->data_ != nullptr && msg->changeInfo_.size_ > 0) {
189         if ((int)msg->changeInfo_.changeType_ == ChangeType::INSERT) {
190             changeData.type = static_cast<int32_t>(NotifyType::NOTIFY_ALBUM_ADD_ASSET);
191         } else {
192             changeData.type = static_cast<int32_t>(NotifyType::NOTIFY_ALBUM_REMOVE_ASSET);
193         }
194         shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
195         if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(msg->data_), msg->changeInfo_.size_)) {
196             SetSubUris(parcel, changeData);
197         }
198     } else {
199         changeData.type = static_cast<int32_t>(msg->changeInfo_.changeType_);
200     }
201 }
202 
UvQueueWork(UvChangeMsg * msg)203 void ChangeListener::UvQueueWork(UvChangeMsg *msg)
204 {
205     ChangeData changeData = {
206         .type = 0,
207         .uris = { .head = nullptr, .size = 0 },
208         .extraUris = { .head = nullptr, .size = 0}
209     };
210     SolveOnChange(msg, changeData);
211     msg->callbackRef(changeData);
212     for (auto i = 0; i< changeData.uris.size; i++) {
213         free(changeData.uris.head[i]);
214     }
215     for (auto i = 0; i< changeData.extraUris.size; i++) {
216         free(changeData.extraUris.head[i]);
217     }
218     free(changeData.uris.head);
219     free(changeData.extraUris.head);
220 }
221 
CheckWhetherInitSuccess(const sptr<IRemoteObject> & token)222 bool PhotoAccessHelperImpl::CheckWhetherInitSuccess(const sptr<IRemoteObject> &token)
223 {
224     if (!UserFileClient::IsValid()) {
225         unique_lock<mutex> helperLock(sUserFileClientMutex_);
226         UserFileClient::Init(token);
227         if (!UserFileClient::IsValid()) {
228             LOGE("UserFileClient creation failed");
229             helperLock.unlock();
230             return false;
231         }
232         helperLock.unlock();
233         return true;
234     }
235     return true;
236 }
237 
GetPhotoAccessHelper(int64_t id)238 bool PhotoAccessHelperImpl::GetPhotoAccessHelper(int64_t id)
239 {
240     auto context = FFIData::GetData<AbilityRuntime::CJAbilityContext>(id);
241     if (context == nullptr) {
242         LOGE("get context failed.");
243         return false;
244     }
245     contextId = id;
246     sptr<IRemoteObject> token = context->GetToken();
247     if (!CheckWhetherInitSuccess(token)) {
248         LOGE("Init MediaLibrary Instance is failed");
249         return false;
250     }
251     g_listObj = make_unique<ChangeListener>();
252     return true;
253 }
254 
ParseArgsGetAssets(COptions options,DataSharePredicates & predicates,vector<string> & fetchColumn,ExtraInfo & extraInfo,int32_t & errCode)255 static void ParseArgsGetAssets(COptions options, DataSharePredicates &predicates,
256     vector<string> &fetchColumn, ExtraInfo &extraInfo, int32_t &errCode)
257 {
258     extraInfo.fetchOptType = ASSET_FETCH_OPT;
259     GetFetchOption(options, predicates, fetchColumn, extraInfo, errCode);
260     AddDefaultAssetColumns(fetchColumn, PhotoColumn::IsPhotoColumn, TYPE_PHOTO, errCode);
261     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
262     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
263     predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
264     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
265     predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
266         to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
267 }
268 
GetAssets(COptions options,int32_t & errCode)269 shared_ptr<FetchResult<FileAsset>> PhotoAccessHelperImpl::GetAssets(COptions options, int32_t &errCode)
270 {
271     DataSharePredicates predicates;
272     vector<string> fetchColumn;
273     ExtraInfo extraInfo;
274     ParseArgsGetAssets(options, predicates, fetchColumn, extraInfo, errCode);
275     if (errCode != E_SUCCESS) {
276         LOGE("ParseArgsGetAssets failed.");
277         return nullptr;
278     }
279     string queryUri;
280     if (extraInfo.uri == URI_FIND_ALL_DUPLICATE_ASSETS) {
281         queryUri = PAH_FIND_ALL_DUPLICATE_ASSETS;
282     } else if (extraInfo.uri == URI_FIND_ALL_DUPLICATE_ASSETS_TO_DELETE) {
283         queryUri = PAH_FIND_DUPLICATE_ASSETS_TO_DELETE;
284     } else {
285         queryUri = PAH_QUERY_PHOTO;
286     }
287     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
288     Uri uri(queryUri);
289     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
290         predicates, fetchColumn, errCode);
291     if (resultSet == nullptr && !extraInfo.uri.empty() && errCode == E_PERMISSION_DENIED) {
292         Uri queryWithUri(extraInfo.uri);
293         resultSet = UserFileClient::Query(queryWithUri, predicates, fetchColumn, errCode);
294     }
295     if (resultSet == nullptr) {
296         if (errCode < 0) {
297             errCode = MediaLibraryNapiUtils::TransErrorCode("GetAssets", errCode);
298         }
299         return nullptr;
300     }
301     shared_ptr<FetchResult<FileAsset>> fetchResult = make_shared<FetchResult<FileAsset>>(move(resultSet));
302     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
303     return fetchResult;
304 }
305 
ParseArgsGetBurstAssets(char * cBurstKey,COptions options,DataSharePredicates & predicates,vector<string> & fetchColumn,ExtraInfo & extraInfo)306 static int32_t ParseArgsGetBurstAssets(char* cBurstKey, COptions options, DataSharePredicates &predicates,
307     vector<string> &fetchColumn, ExtraInfo &extraInfo)
308 {
309     int32_t errCode = E_SUCCESS;
310     string burstKey(cBurstKey);
311     if (burstKey.size() > PATH_MAX) {
312         burstKey = burstKey.substr(0, PATH_MAX);
313     }
314     if (burstKey.empty()) {
315         LOGE("The input burstkey cannot be empty");
316         errCode = OHOS_INVALID_PARAM_CODE;
317         return errCode;
318     }
319     extraInfo.fetchOptType = ASSET_FETCH_OPT;
320     GetFetchOption(options, predicates, fetchColumn, extraInfo, errCode);
321     if (errCode != E_SUCCESS) {
322         LOGE("GetFetchOption failed");
323         return errCode;
324     }
325     AddDefaultAssetColumns(fetchColumn, PhotoColumn::IsPhotoColumn,
326         TYPE_PHOTO, errCode);
327     predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_KEY, burstKey);
328     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
329     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
330     predicates.OrderByAsc(MediaColumn::MEDIA_NAME);
331     return errCode;
332 }
333 
GetBurstAssets(char * cBurstKey,COptions options,int32_t & errCode)334 shared_ptr<FetchResult<FileAsset>> PhotoAccessHelperImpl::GetBurstAssets(char* cBurstKey,
335     COptions options, int32_t &errCode)
336 {
337     DataSharePredicates predicates;
338     vector<string> fetchColumn;
339     ExtraInfo extraInfo;
340     errCode = ParseArgsGetBurstAssets(cBurstKey, options, predicates, fetchColumn, extraInfo);
341     if (errCode != E_SUCCESS) {
342         LOGE("ParseArgsGetBurstAssets failed.");
343         return nullptr;
344     }
345     string queryUri = PAH_QUERY_PHOTO;
346     if (extraInfo.uri == URI_FIND_ALL_DUPLICATE_ASSETS) {
347         queryUri = PAH_FIND_ALL_DUPLICATE_ASSETS;
348     } else if (extraInfo.uri == URI_FIND_ALL_DUPLICATE_ASSETS_TO_DELETE) {
349         queryUri = PAH_FIND_DUPLICATE_ASSETS_TO_DELETE;
350     } else {
351         queryUri = PAH_QUERY_PHOTO;
352     }
353     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
354     Uri uri(queryUri);
355     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
356         predicates, fetchColumn, errCode);
357     if (resultSet == nullptr && !extraInfo.uri.empty() && errCode == E_PERMISSION_DENIED) {
358         Uri queryWithUri(extraInfo.uri);
359         resultSet = UserFileClient::Query(queryWithUri, predicates, fetchColumn, errCode);
360     }
361     if (resultSet == nullptr) {
362         if (errCode < 0) {
363             errCode = MediaLibraryNapiUtils::TransErrorCode("getBurstAssets", errCode);
364         }
365         return nullptr;
366     }
367     shared_ptr<FetchResult<FileAsset>> fetchResult = make_shared<FetchResult<FileAsset>>(move(resultSet));
368     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
369     return fetchResult;
370 }
371 
ParseAlbumTypes(int32_t albumType,int32_t albumSubType,DataSharePredicates & predicates,vector<string> & fetchColumn,int32_t & errCode)372 void PhotoAccessHelperImpl::ParseAlbumTypes(int32_t albumType, int32_t albumSubType,
373     DataSharePredicates &predicates, vector<string> &fetchColumn, int32_t &errCode)
374 {
375     if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
376         errCode = JS_ERR_PARAMETER_INVALID;
377         return;
378     }
379     isAnalysisAlbum = (albumType == PhotoAlbumType::SMART) ? 1 : 0;
380     if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
381         errCode = JS_ERR_PARAMETER_INVALID;
382         return;
383     }
384     if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
385         isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
386         fetchColumn.insert(fetchColumn.end(),
387             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
388             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
389         MediaLibraryNapiUtils::GetAllLocationPredicates(predicates);
390         errCode = JS_INNER_FAIL;
391         return;
392     } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
393         fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
394         isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
395         string onClause = PhotoAlbumColumns::ALBUM_NAME  + " = " + CITY_ID;
396         predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
397         predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
398     }
399     predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
400     if (albumSubType != ANY) {
401         predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
402     }
403     if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
404         predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
405     }
406     if (albumSubType == PhotoAlbumSubType::HIGHLIGHT || albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
407         isHighlightAlbum = albumSubType;
408         vector<string> onClause = {
409             ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
410             HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
411         };
412         predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
413         predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
414     }
415 }
416 
AddDefaultPhotoAlbumColumns(vector<string> & fetchColumn,int32_t & errCode)417 static bool AddDefaultPhotoAlbumColumns(vector<string> &fetchColumn, int32_t &errCode)
418 {
419     auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
420     for (const auto &column : fetchColumn) {
421         if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
422             validFetchColumns.insert(column);
423         } else if (column.compare(MEDIA_DATA_DB_URI) == 0) {
424             // uri is default property of album
425             continue;
426         } else {
427             LOGE("unknown columns:%{public}s", column.c_str());
428             errCode = JS_ERR_PARAMETER_INVALID;
429             return false;
430         }
431     }
432     fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
433     return true;
434 }
435 
ParseArgsGetPhotoAlbum(int32_t type,int32_t subtype,COptions options,DataSharePredicates & predicates,vector<string> & fetchColumn,ExtraInfo & extraInfo,int32_t & errCode)436 void PhotoAccessHelperImpl::ParseArgsGetPhotoAlbum(int32_t type, int32_t subtype, COptions options,
437     DataSharePredicates &predicates, vector<string> &fetchColumn, ExtraInfo &extraInfo, int32_t &errCode)
438 {
439     extraInfo.fetchOptType = ALBUM_FETCH_OPT;
440     GetFetchOption(options, predicates, fetchColumn, extraInfo, errCode);
441     if (!extraInfo.uri.empty()) {
442         if (extraInfo.uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != string::npos) {
443             isAnalysisAlbum = true; // 1:is an analysis album
444         }
445     }
446     if (errCode != E_SUCCESS) {
447         LOGE("GetFetchOption failed.");
448         return;
449     }
450     ParseAlbumTypes(type, subtype, predicates, fetchColumn, errCode);
451     if (!MediaLibraryNapiUtils::IsSystemApp()) {
452         predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
453             to_string(PhotoAlbumSubType::USER_GENERIC),
454             to_string(PhotoAlbumSubType::FAVORITE),
455             to_string(PhotoAlbumSubType::VIDEO),
456             to_string(PhotoAlbumSubType::IMAGE),
457             to_string(PhotoAlbumSubType::CLOUD_ENHANCEMENT),
458         }));
459     } else {
460         predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
461     }
462     if (isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
463         isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
464         if (!AddDefaultPhotoAlbumColumns(fetchColumn, errCode)) {
465             LOGE("AddDefaultPhotoAlbumColumns failed.");
466             return;
467         }
468         if (!isAnalysisAlbum) {
469             fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
470             fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
471         }
472         if (isHighlightAlbum) {
473             fetchColumn.erase(std::remove(fetchColumn.begin(), fetchColumn.end(),
474                 PhotoAlbumColumns::ALBUM_ID), fetchColumn.end());
475             fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
476             PhotoAlbumColumns::ALBUM_ID);
477         }
478     }
479 }
480 
GetAlbums(int32_t type,int32_t subtype,COptions options,int32_t & errCode)481 shared_ptr<FetchResult<PhotoAlbum>> PhotoAccessHelperImpl::GetAlbums(int32_t type, int32_t subtype,
482     COptions options, int32_t &errCode)
483 {
484     DataSharePredicates predicates;
485     vector<string> fetchColumn;
486     ExtraInfo extraInfo;
487     ParseArgsGetPhotoAlbum(type, subtype, options, predicates, fetchColumn, extraInfo, errCode);
488     if (errCode != E_SUCCESS) {
489         LOGE("ParseArgsGetPhotoAlbum failed.");
490         return nullptr;
491     }
492     string queryUri;
493     if (hiddenOnly || hiddenAlbumFetchMode == ASSETS_MODE) {
494         queryUri = PAH_QUERY_HIDDEN_ALBUM;
495     } else if (isAnalysisAlbum) {
496         queryUri = isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
497             PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
498     } else {
499         queryUri = PAH_QUERY_PHOTO_ALBUM;
500     }
501     Uri uri(queryUri);
502     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
503     if (resultSet == nullptr) {
504         LOGE("resultSet == nullptr, errCode is %{public}d", errCode);
505         if (errCode == E_PERMISSION_DENIED) {
506             errCode = MediaLibraryNapiUtils::TransErrorCode("GetAlbums", E_PERMISSION_DENIED);
507         } else {
508             errCode = MediaLibraryNapiUtils::TransErrorCode("GetAlbums", E_HAS_DB_ERROR);
509         }
510         return nullptr;
511     }
512     shared_ptr<FetchResult<PhotoAlbum>> fetchPhotoAlbumResult =
513         make_shared<FetchResult<PhotoAlbum>>(move(resultSet));
514     fetchPhotoAlbumResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
515     fetchPhotoAlbumResult->SetHiddenOnly(hiddenOnly);
516     fetchPhotoAlbumResult->SetLocationOnly(isLocationAlbum ==
517         PhotoAlbumSubType::GEOGRAPHY_LOCATION);
518     return fetchPhotoAlbumResult;
519 }
520 
CheckRef(ChangeListener & listObj,bool isOff,const string & uri,int64_t funcId)521 bool PhotoAccessHelperImpl::CheckRef(ChangeListener &listObj, bool isOff, const string &uri, int64_t funcId)
522 {
523     bool isSame = false;
524     shared_ptr<DataShare::DataShareObserver> obs;
525     string obsUri;
526     {
527         lock_guard<mutex> lock(sOnOffMutex_);
528         for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
529             isSame = (funcId == (*it)->funcId);
530             if (isSame) {
531                 obsUri = (*it)->uri_;
532                 if ((isOff) && (uri.compare(obsUri) == 0)) {
533                     obs = static_cast<shared_ptr<DataShare::DataShareObserver>>(*it);
534                     listObj.observers_.erase(it);
535                     break;
536                 }
537                 if (uri.compare(obsUri) != 0) {
538                     return true;
539                 }
540                 return false;
541             }
542         }
543     }
544     if (isSame && isOff) {
545         if (obs != nullptr) {
546             UserFileClient::UnregisterObserverExt(Uri(obsUri), obs);
547         }
548     }
549     return true;
550 }
551 
RegisterNotifyChange(const std::string & uri,bool isDerived,int64_t funcId,ChangeListener & listObj,int32_t & errCode)552 void PhotoAccessHelperImpl::RegisterNotifyChange(const std::string &uri, bool isDerived,
553     int64_t funcId, ChangeListener &listObj, int32_t &errCode)
554 {
555     Uri notifyUri(uri);
556     auto func = reinterpret_cast<void(*)(ChangeData)>(funcId);
557     auto callbackRef = CJLambda::Create(func);
558     if (callbackRef == nullptr) {
559         LOGE("RegisterNotifyChange on register callback is nullptr.");
560         errCode = JS_ERR_PARAMETER_INVALID;
561         return;
562     }
563     shared_ptr<FfiMediaOnNotifyObserver> observer =
564         make_shared<FfiMediaOnNotifyObserver>(listObj, uri, funcId, callbackRef);
565     UserFileClient::RegisterObserverExt(notifyUri,
566         static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), isDerived);
567     lock_guard<mutex> lock(sOnOffMutex_);
568     listObj.observers_.push_back(observer);
569 }
570 
RegisterChange(char * uri,bool forChildUris,int64_t funcId,int32_t & errCode)571 void PhotoAccessHelperImpl::RegisterChange(char* uri, bool forChildUris, int64_t funcId, int32_t &errCode)
572 {
573     string fileUri(uri);
574     if (fileUri.size() > ARG_BUF_SIZE) {
575         fileUri = fileUri.substr(0, ARG_BUF_SIZE);
576     }
577     if (CheckRef(*g_listObj, false, fileUri, funcId)) {
578         RegisterNotifyChange(fileUri, forChildUris, funcId, *g_listObj, errCode);
579     } else {
580         errCode = JS_ERR_PARAMETER_INVALID;
581     }
582 }
583 
GetFfiListenerType(const string & str)584 static int32_t GetFfiListenerType(const string &str)
585 {
586     auto iter = FfiListenerTypeMaps.find(str);
587     if (iter == FfiListenerTypeMaps.end()) {
588         LOGE("Invalid Listener Type %{public}s", str.c_str());
589         return CJ_INVALID_LISTENER;
590     }
591 
592     return iter->second;
593 }
594 
UnRegisterChange(const string & type,ChangeListener & listObj)595 void PhotoAccessHelperImpl::UnRegisterChange(const string &type, ChangeListener &listObj)
596 {
597     MediaType mediaType;
598     int32_t typeEnum = GetFfiListenerType(type);
599 
600     switch (typeEnum) {
601         case CJ_AUDIO_LISTENER:
602             mediaType = MEDIA_TYPE_AUDIO;
603             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
604             listObj.audioDataObserver_ = nullptr;
605             break;
606         case CJ_VIDEO_LISTENER:
607             mediaType = MEDIA_TYPE_VIDEO;
608             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
609             listObj.videoDataObserver_ = nullptr;
610             break;
611         case CJ_IMAGE_LISTENER:
612             mediaType = MEDIA_TYPE_IMAGE;
613             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
614             listObj.imageDataObserver_ = nullptr;
615             break;
616         case CJ_FILE_LISTENER:
617             mediaType = MEDIA_TYPE_FILE;
618             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
619             listObj.fileDataObserver_ = nullptr;
620             break;
621         case CJ_SMARTCJ_ALBUM_LISTENER:
622             mediaType = MEDIA_TYPE_SMARTALBUM;
623             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
624                 listObj.smartAlbumDataObserver_);
625             listObj.smartAlbumDataObserver_ = nullptr;
626             break;
627         case CJ_ALBUM_LISTENER:
628             mediaType = MEDIA_TYPE_ALBUM;
629             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
630             listObj.albumDataObserver_ = nullptr;
631             break;
632         default:
633             LOGE("Invalid Media Type");
634             return;
635     }
636     if (listObj.callbackRef!= nullptr) {
637         FfiMediaChangeListener listener;
638         listener.mediaType = mediaType;
639         listener.callbackRef = listObj.callbackRef;
640         listObj.OnChange(listener);
641     }
642 }
643 
UnRegisterNotifyChange(const std::string & uri,int64_t funcId,ChangeListener & listObj)644 void PhotoAccessHelperImpl::UnRegisterNotifyChange(const std::string &uri, int64_t funcId, ChangeListener &listObj)
645 {
646     if (funcId != -1) {
647         CheckRef(listObj, true, uri, funcId);
648         return;
649     }
650     if (listObj.observers_.size() == 0) {
651         return;
652     }
653     std::vector<std::shared_ptr<FfiMediaOnNotifyObserver>> offObservers;
654     {
655         lock_guard<mutex> lock(sOnOffMutex_);
656         for (auto iter = listObj.observers_.begin(); iter != listObj.observers_.end();) {
657             if (uri.compare((*iter)->uri_) == 0) {
658                 offObservers.push_back(*iter);
659                 vector<shared_ptr<FfiMediaOnNotifyObserver>>::iterator tmp = iter;
660                 iter = listObj.observers_.erase(tmp);
661             } else {
662                 iter++;
663             }
664         }
665     }
666     for (auto obs : offObservers) {
667         UserFileClient::UnregisterObserverExt(Uri(uri),
668             static_cast<shared_ptr<DataShare::DataShareObserver>>(obs));
669     }
670 }
671 
UnRegisterChange(char * uri,int64_t funcId)672 void PhotoAccessHelperImpl::UnRegisterChange(char* uri, int64_t funcId)
673 {
674     string fileUri(uri);
675     if (fileUri.size() > ARG_BUF_SIZE) {
676         fileUri = fileUri.substr(0, ARG_BUF_SIZE);
677     }
678     if (FfiListenerTypeMaps.find(fileUri) != FfiListenerTypeMaps.end()) {
679         UnRegisterChange(fileUri, *g_listObj);
680         return;
681     }
682     UnRegisterNotifyChange(fileUri, funcId, *g_listObj);
683 }
684 
Release()685 void PhotoAccessHelperImpl::Release()
686 {
687     contextId = -1;
688 }
689 
ParseAndSetFileUriArray(OHOS::AAFwk::Want & want,CArrString srcFileUris,int32_t & errCode)690 static bool ParseAndSetFileUriArray(OHOS::AAFwk::Want &want, CArrString srcFileUris, int32_t &errCode)
691 {
692     if (srcFileUris.size > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
693         errCode = OHOS_INVALID_PARAM_CODE;
694         LOGE("Array size over 100.");
695         return false;
696     }
697     if (srcFileUris.size < CONFIRM_BOX_ARRAY_MIN_LENGTH) {
698         errCode = OHOS_INVALID_PARAM_CODE;
699         LOGE("Array size invalid");
700         return false;
701     }
702     vector<string> srcFileUri;
703     for (int64_t i = 0; i < srcFileUris.size; i++) {
704         srcFileUri.emplace_back(string(srcFileUris.head[i]));
705     }
706     want.SetParam(CONFIRM_BOX_SRC_FILE_URIS, srcFileUri);
707     return true;
708 }
709 
ParseAndSetConfigArray(OHOS::AAFwk::Want & want,PhotoCreationConfigs & photoCreationConfigs,int32_t & errCode)710 static bool ParseAndSetConfigArray(OHOS::AAFwk::Want &want,
711     PhotoCreationConfigs &photoCreationConfigs, int32_t &errCode)
712 {
713     if (photoCreationConfigs.size > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
714         errCode = OHOS_INVALID_PARAM_CODE;
715         LOGE("Array size over 100.");
716         return false;
717     }
718     if (photoCreationConfigs.size < CONFIRM_BOX_ARRAY_MIN_LENGTH) {
719         errCode = OHOS_INVALID_PARAM_CODE;
720         LOGE("Array size invalid");
721         return false;
722     }
723     vector<string> titleList;
724     vector<string> extensionList;
725     vector<int32_t> photoTypeList;
726     vector<int32_t> photoSubTypeList;
727     for (int64_t i = 0; i < photoCreationConfigs.size; i++) {
728         string title(photoCreationConfigs.head[i].title);
729         string fileNameExtension(photoCreationConfigs.head[i].fileNameExtension);
730         int32_t photoType = photoCreationConfigs.head[i].photoType;
731         if (!((photoType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) || (
732             photoType == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO)))) {
733             LOGE("Param photoType is not valid.");
734             errCode = OHOS_INVALID_PARAM_CODE;
735             return false;
736         }
737         int32_t subtype = photoCreationConfigs.head[i].subtype;
738         if (!((subtype == static_cast<int32_t>(PhotoSubType::DEFAULT)) || (
739             subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)))) {
740             LOGE("Param subtype is not valid.");
741             errCode = OHOS_INVALID_PARAM_CODE;
742             return false;
743         }
744         titleList.emplace_back(title);
745         extensionList.emplace_back(fileNameExtension);
746         photoTypeList.emplace_back(photoType);
747         photoSubTypeList.emplace_back(subtype);
748     }
749     want.SetParam(CONFIRM_BOX_TITLE_ARRAY, titleList);
750     want.SetParam(CONFIRM_BOX_EXTENSION_ARRAY, extensionList);
751     want.SetParam(CONFIRM_BOX_PHOTO_TYPE_ARRAY, photoTypeList);
752     want.SetParam(CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY, photoSubTypeList);
753     return true;
754 }
755 
InitConfirmRequest(OHOS::AAFwk::Want & want,shared_ptr<ConfirmCallback> & callback,CArrString srcFileUris,PhotoCreationConfigs & photoCreationConfigs,int32_t & errCode)756 static bool InitConfirmRequest(OHOS::AAFwk::Want &want, shared_ptr<ConfirmCallback> &callback,
757     CArrString srcFileUris, PhotoCreationConfigs &photoCreationConfigs, int32_t &errCode)
758 {
759     if (srcFileUris.size != photoCreationConfigs.size) {
760         errCode = OHOS_INVALID_PARAM_CODE;
761         LOGE("the length of srcFileUris and photoCreationConfigs must be same.");
762         return false;
763     }
764     want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
765     want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
766     want.AddFlags(Want::FLAG_AUTH_READ_URI_PERMISSION);
767 
768     if (!ParseAndSetFileUriArray(want, srcFileUris, errCode)) {
769         LOGE("ParseAndSetFileUriArray failed.");
770         return false;
771     }
772     if (!ParseAndSetConfigArray(want, photoCreationConfigs, errCode)) {
773         LOGE("ParseAndSetConfigArray failed.");
774         return false;
775     }
776     return true;
777 }
778 
GetUIContentForDialog(int64_t contextId,int32_t & errCode)779 static Ace::UIContent* GetUIContentForDialog(int64_t contextId, int32_t &errCode)
780 {
781     auto context = FFIData::GetData<AbilityRuntime::CJAbilityContext>(contextId);
782     if (context == nullptr) {
783         LOGE("get context failed.");
784         errCode = JS_ERR_PARAMETER_INVALID;
785         return nullptr;
786     }
787     shared_ptr<AbilityRuntime::AbilityContext> abilityContext = context->GetAbilityContext();
788     if (abilityContext == nullptr) {
789         LOGE("AbilityContext is null");
790         errCode = JS_ERR_PARAMETER_INVALID;
791         return nullptr;
792     }
793     // get uiContent from abilityContext, this api should be called after loadContent, otherwise uiContent is nullptr
794     auto uiContent = abilityContext->GetUIContent();
795     if (uiContent == nullptr) {
796         LOGE("UiContent is null");
797         errCode = JS_ERR_PARAMETER_INVALID;
798         return nullptr;
799     }
800     return uiContent;
801 }
802 
ShowAssetsCreationDialog(CArrString & srcFileUris,PhotoCreationConfigs & photoCreationConfigs,int64_t funcId,FfiBundleInfo & cBundleInfo,int32_t & errCode)803 void PhotoAccessHelperImpl::ShowAssetsCreationDialog(CArrString &srcFileUris,
804     PhotoCreationConfigs &photoCreationConfigs, int64_t funcId, FfiBundleInfo &cBundleInfo, int32_t &errCode)
805 {
806 #ifdef HAS_ACE_ENGINE_PART
807     auto uiContent = GetUIContentForDialog(contextId, errCode);
808     if (uiContent == nullptr) {
809         LOGE("GetUIContentForDialog failed.");
810         return;
811     }
812     // set want
813     OHOS::AAFwk::Want want;
814     want.SetParam(CONFIRM_BOX_BUNDLE_NAME, string(cBundleInfo.bundleName));
815     want.SetParam(CONFIRM_BOX_APP_NAME, string(cBundleInfo.appName));
816     want.SetParam(CONFIRM_BOX_APP_ID, string(cBundleInfo.appId));
817     auto callback = make_shared<ConfirmCallback>(uiContent, funcId);
818     if (!InitConfirmRequest(want, callback, srcFileUris, photoCreationConfigs, errCode)) {
819         LOGE("Parse input fail.");
820         errCode = JS_ERR_PARAMETER_INVALID;
821         return;
822     }
823     // regist callback and config
824     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
825         [callback](int32_t releaseCode) {
826             callback->OnRelease(releaseCode);
827         },
828         [callback](int32_t resultCode, const AAFwk::Want &result) {
829             callback->OnResult(resultCode, result);
830         },
831         [callback](const AAFwk::WantParams &receive) {
832             callback->OnReceive(receive);
833         },
834         [callback](int32_t code, const std::string &name, const std::string &message) {
835             callback->OnError(code, name, message);
836         },
837     };
838     OHOS::Ace::ModalUIExtensionConfig config;
839     config.isProhibitBack = true;
840     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
841     if (sessionId == DEFAULT_SESSION_ID) {
842         LOGE("CreateModalUIExtension fail.");
843         errCode = JS_ERR_PARAMETER_INVALID;
844         return;
845     }
846     callback->SetSessionId(sessionId);
847     return;
848 #else
849     LOGE("ace_engine is not support.");
850     errCode = JS_INNER_FAIL;
851     return;
852 #endif
853 }
854 
GetSubWindowUIContent(PhotoSelectOptions & option)855 Ace::UIContent *GetSubWindowUIContent(PhotoSelectOptions &option)
856 {
857     if (option.subWindowName == nullptr) {
858         LOGE("failed to get the value of subWindow name");
859         return nullptr;
860     }
861     string subWindowName(option.subWindowName);
862     if (subWindowName.size() > ARG_BUF_SIZE) {
863         subWindowName = subWindowName.substr(0, ARG_BUF_SIZE);
864     }
865     auto currentWindow = Rosen::Window::Find(string(subWindowName));
866     if (currentWindow == nullptr) {
867         LOGE("GetSubWindowUIContent failed to find context by subWindow name");
868         return nullptr;
869     }
870     return currentWindow->GetUIContent();
871 }
872 
GetUIContent(int64_t id,PhotoSelectOptions & option)873 Ace::UIContent *GetUIContent(int64_t id, PhotoSelectOptions &option)
874 {
875     Ace::UIContent *uiContent = GetSubWindowUIContent(option);
876     if (uiContent != nullptr) {
877         LOGI("GetSubWindowUIContent success");
878         return uiContent;
879     }
880 
881     auto context = FFIData::GetData<AbilityRuntime::CJAbilityContext>(id);
882     if (context == nullptr) {
883         LOGE("get context failed.");
884         return nullptr;
885     }
886     shared_ptr<AbilityRuntime::AbilityContext> abilityContext = context->GetAbilityContext();
887     if (abilityContext == nullptr) {
888         LOGE("Fail to get abilityContext");
889         return nullptr;
890     }
891     return abilityContext->GetUIContent();
892 }
893 
InnerSetWantParamsArrayString(const std::string & key,const std::vector<std::string> & value,AAFwk::WantParams & wantParams)894 static bool InnerSetWantParamsArrayString(
895     const std::string &key, const std::vector<std::string> &value, AAFwk::WantParams &wantParams)
896 {
897     size_t size = value.size();
898     sptr<AAFwk::IArray> ao = new (std::nothrow) AAFwk::Array(size, AAFwk::g_IID_IString);
899     if (ao != nullptr) {
900         for (size_t i = 0; i < size; i++) {
901             ao->Set(i, AAFwk::String::Box(value[i]));
902         }
903         wantParams.SetParam(key, ao);
904         return true;
905     } else {
906         return false;
907     }
908 }
909 
UnwrapWantParams(PhotoSelectOptions & option)910 static AAFwk::WantParams UnwrapWantParams(PhotoSelectOptions &option)
911 {
912     AAFwk::WantParams wantParams;
913     if (option.preselectedUris.size > 0) {
914         vector<string> preselectedUris;
915         for (int64_t i = 0; i < option.preselectedUris.size; i++) {
916             preselectedUris.push_back(string(option.preselectedUris.head[i]));
917         }
918         InnerSetWantParamsArrayString("preselectedUris", preselectedUris, wantParams);
919     }
920     AAFwk::WantParams wp;
921     if (option.recommendationOptions.recommendationType != -1) {
922         wp.SetParam("recommendationType",
923             AAFwk::Integer::Box(option.recommendationOptions.recommendationType));
924     }
925     if (option.recommendationOptions.textContextInfo.text != nullptr) {
926         AAFwk::WantParams wpText;
927         wpText.SetParam("text", AAFwk::String::Box(string(option.recommendationOptions.textContextInfo.text)));
928         sptr<AAFwk::IWantParams> wantParamsText = AAFwk::WantParamWrapper::Box(wpText);
929         if (wantParamsText != nullptr) {
930             wp.SetParam("textContextInfo", wantParamsText);
931         }
932     }
933     sptr<AAFwk::IWantParams> pWantParams = AAFwk::WantParamWrapper::Box(wp);
934     if (pWantParams != nullptr) {
935         wantParams.SetParam("recommendationOptions", pWantParams);
936     }
937     return wantParams;
938 }
939 
SetRequestInfo(PhotoSelectOptions & option,AAFwk::Want & request)940 static void SetRequestInfo(PhotoSelectOptions &option, AAFwk::Want &request)
941 {
942     request.SetParams(UnwrapWantParams(option));
943     std::string targetType = "photoPicker";
944     request.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
945     request.SetAction(OHOS_WANT_ACTION_PHOTOPICKER);
946     string type = (option.maxSelectNumber == 1) ? "singleselect" : "multipleselect";
947     string uri = type;
948     string filterMediaType = "";
949     if (PHOTO_VIEW_MIME_TYPE_MAP.find(option.MIMEType) != PHOTO_VIEW_MIME_TYPE_MAP.end()) {
950         filterMediaType = PHOTO_VIEW_MIME_TYPE_MAP.at(option.MIMEType);
951     }
952     request.SetType(type);
953     request.SetParam("uri", uri);
954     request.SetParam("maxSelectCount", option.maxSelectNumber);
955     request.SetParam("filterMediaType", filterMediaType);
956     request.SetParam("isPhotoTakingSupported", option.isPhotoTakingSupported);
957     request.SetParam("isSearchSupported", option.isSearchSupported);
958     request.SetParam("isPreviewForSingleSelectionSupported", option.isPreviewForSingleSelectionSupported);
959     request.SetParam("singleSelectionMode", static_cast<int32_t>(option.singleSelectionMode));
960     request.SetParam("isEditSupported", option.isEditSupported);
961     request.SetParam("isOriginalSupported", option.isOriginalSupported);
962 }
963 
ParseArgsStartPhotoPicker(int64_t id,PhotoSelectOptions & option,shared_ptr<PickerCallBack> & pickerCallBack)964 static bool ParseArgsStartPhotoPicker(int64_t id, PhotoSelectOptions &option,
965     shared_ptr<PickerCallBack> &pickerCallBack)
966 {
967     Ace::UIContent *uiContent = GetUIContent(id, option);
968     if (uiContent == nullptr) {
969         LOGE("get uiContent failed");
970         return false;
971     }
972     AAFwk::Want request;
973     SetRequestInfo(option, request);
974     auto callback = make_shared<ModalUICallback>(uiContent, pickerCallBack.get());
975     Ace::ModalUIExtensionCallbacks extensionCallback = {
976         ([callback](auto arg) { callback->OnRelease(arg); }),
977         ([callback](auto arg1, auto arg2) { callback->OnResultForModal(arg1, arg2); }),
978         ([callback](auto arg) { callback->OnReceive(arg); }),
979         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
980         std::bind(&ModalUICallback::OnDestroy, callback),
981     };
982     Ace::ModalUIExtensionConfig config;
983     config.isProhibitBack = true;
984     int sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
985     if (sessionId == 0) {
986         LOGE("create modalUIExtension failed");
987         return false;
988     }
989     callback->SetSessionId(sessionId);
990     return true;
991 }
992 
StartPhotoPicker(int64_t id,PhotoSelectOptions & option,int32_t & errCode)993 PhotoSelectResult PhotoAccessHelperImpl::StartPhotoPicker(int64_t id, PhotoSelectOptions &option, int32_t &errCode)
994 {
995     PhotoSelectResult photoSelectResult = {
996         .photoUris = { .head = nullptr, .size = 0 },
997         .isOriginalPhoto = false
998     };
999     shared_ptr<PickerCallBack> pickerCallBack = make_shared<PickerCallBack>();
1000     ParseArgsStartPhotoPicker(id, option, pickerCallBack);
1001     while (!pickerCallBack->ready) {
1002         this_thread::sleep_for(chrono::milliseconds(SLEEP_TIME));
1003     }
1004     errCode = pickerCallBack->resultCode;
1005     size_t uriSize = pickerCallBack->uris.size();
1006     if (uriSize > 0) {
1007         char** head = static_cast<char **>(malloc(sizeof(char *) * uriSize));
1008         if (head == nullptr) {
1009             LOGE("malloc photoUris failed.");
1010             errCode = ERR_MEM_ALLOCATION;
1011             return photoSelectResult;
1012         }
1013         for (size_t i = 0; i < uriSize; i++) {
1014             head[i] = MallocCString(pickerCallBack->uris[i]);
1015         }
1016         photoSelectResult.photoUris.head = head;
1017         photoSelectResult.photoUris.size = static_cast<int64_t>(uriSize);
1018     }
1019     photoSelectResult.isOriginalPhoto = pickerCallBack->isOrigin;
1020     return photoSelectResult;
1021 }
1022 }
1023 }