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 }