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 }