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