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 MLOG_TAG "SendablePhotoAccessHelper"
17
18 #include "sendable_photo_access_helper_napi.h"
19
20 #include <fcntl.h>
21 #include <functional>
22 #include <sys/sendfile.h>
23
24 #include "ability_context.h"
25 #include "context.h"
26 #include "directory_ex.h"
27 #include "file_ex.h"
28 #include "hitrace_meter.h"
29 #include "location_column.h"
30 #include "media_device_column.h"
31 #include "media_directory_type_column.h"
32 #include "media_file_asset_columns.h"
33 #include "media_change_request_napi.h"
34 #include "media_column.h"
35 #include "media_app_uri_permission_column.h"
36 #include "media_file_uri.h"
37 #include "media_file_utils.h"
38 #include "media_smart_album_column.h"
39 #include "media_smart_map_column.h"
40 #include "medialibrary_client_errno.h"
41 #include "medialibrary_data_manager.h"
42 #include "medialibrary_db_const.h"
43 #include "medialibrary_errno.h"
44 #include "medialibrary_napi_enum_comm.h"
45 #include "medialibrary_napi_log.h"
46 #include "medialibrary_napi_utils.h"
47 #include "medialibrary_tracer.h"
48 #include "napi_base_context.h"
49 #include "photo_album_column.h"
50 #include "photo_album_napi.h"
51 #include "result_set_utils.h"
52 #include "safe_map.h"
53 #include "search_column.h"
54 #include "sendable_medialibrary_napi_utils.h"
55 #include "sendable_photo_album_napi.h"
56 #include "smart_album_napi.h"
57 #include "story_album_column.h"
58 #include "string_ex.h"
59 #include "string_wrapper.h"
60 #include "userfile_client.h"
61 #include "form_map.h"
62 #include "album_operation_uri.h"
63
64 using namespace std;
65 using namespace OHOS::AppExecFwk;
66 using namespace OHOS::NativeRdb;
67 using namespace OHOS::DataShare;
68
69 namespace OHOS {
70 namespace Media {
71 using ChangeType = AAFwk::ChangeInfo::ChangeType;
72 const string DATE_FUNCTION = "DATE(";
73
74 mutex SendablePhotoAccessHelper::sUserFileClientMutex_;
75 mutex SendablePhotoAccessHelper::sOnOffMutex_;
76
77 const std::string SUBTYPE = "subType";
78 const std::string PAH_SUBTYPE = "subtype";
79 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
80 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
81 { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
82 { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
83 { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
84
85 };
86
87 const std::string TITLE = "title";
88 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
89 { TITLE, MediaColumn::MEDIA_TITLE }
90 };
91
92 using CompleteCallback = napi_async_complete_callback;
93 using Context = SendablePhotoAccessHelperAsyncContext* ;
94
95 thread_local napi_ref SendablePhotoAccessHelper::photoAccessHelperConstructor_ = nullptr;
96 thread_local napi_ref SendablePhotoAccessHelper::sMediaTypeEnumRef_ = nullptr;
97 thread_local napi_ref SendablePhotoAccessHelper::sKeyFrameThumbnailTypeRef_ = nullptr;
98 thread_local napi_ref SendablePhotoAccessHelper::sPhotoSubType_ = nullptr;
99 thread_local napi_ref SendablePhotoAccessHelper::sPositionTypeEnumRef_ = nullptr;
100 thread_local napi_ref SendablePhotoAccessHelper::sAlbumType_ = nullptr;
101 thread_local napi_ref SendablePhotoAccessHelper::sAlbumSubType_ = nullptr;
102 thread_local napi_ref SendablePhotoAccessHelper::sMovingPhotoEffectModeEnumRef_ = nullptr;
103 thread_local napi_ref SendablePhotoAccessHelper::sDynamicRangeTypeEnumRef_ = nullptr;
104
SendablePhotoAccessHelper()105 SendablePhotoAccessHelper::SendablePhotoAccessHelper()
106 : env_(nullptr) {}
107
108 SendablePhotoAccessHelper::~SendablePhotoAccessHelper() = default;
109
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)110 void SendablePhotoAccessHelper::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
111 {
112 SendablePhotoAccessHelper *sendablePhotoAccessHelper = reinterpret_cast<SendablePhotoAccessHelper*>(nativeObject);
113 if (sendablePhotoAccessHelper != nullptr) {
114 delete sendablePhotoAccessHelper;
115 sendablePhotoAccessHelper = nullptr;
116 }
117 }
118
Init(napi_env env,napi_value exports)119 napi_value SendablePhotoAccessHelper::Init(napi_env env, napi_value exports)
120 {
121 napi_value ctorObj;
122
123 napi_property_descriptor props[] = {
124 DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
125 DECLARE_NAPI_FUNCTION("getBurstAssets", PhotoAccessGetBurstAssets),
126 DECLARE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
127 DECLARE_NAPI_FUNCTION("release", JSRelease),
128 DECLARE_NAPI_FUNCTION("getAlbums", PhotoAccessGetPhotoAlbums),
129 DECLARE_NAPI_FUNCTION("getHiddenAlbums", PahGetHiddenAlbums),
130 DECLARE_NAPI_FUNCTION("getSharedPhotoAssets", PhotoAccessGetSharedPhotoAssets),
131 };
132 napi_define_sendable_class(env, SENDABLE_PHOTOACCESSHELPER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
133 MediaLibraryNapiConstructor, nullptr, sizeof(props) / sizeof(props[0]),
134 props, nullptr, &ctorObj);
135 NAPI_CALL(env, napi_create_reference(env, ctorObj, NAPI_INIT_REF_COUNT, &photoAccessHelperConstructor_));
136 NAPI_CALL(env, napi_set_named_property(env, exports, SENDABLE_PHOTOACCESSHELPER_NAPI_CLASS_NAME.c_str(), ctorObj));
137
138 const vector<napi_property_descriptor> staticProps = {
139 DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
140 DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
141 DECLARE_NAPI_PROPERTY("ThumbnailType", CreateKeyFrameThumbnailTypeEnum(env)),
142 DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
143 DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
144 DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
145 DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
146 DECLARE_NAPI_PROPERTY("MovingPhotoEffectMode", CreateMovingPhotoEffectModeEnum(env)),
147 DECLARE_NAPI_PROPERTY("DynamicRangeType", CreateDynamicRangeTypeEnum(env)),
148 };
149 MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
150 return exports;
151 }
152
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)153 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
154 {
155 isAsync = false;
156 size_t argc = ARGS_TWO;
157 napi_value argv[ARGS_TWO] = {0};
158 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
159 if (status != napi_ok) {
160 NAPI_ERR_LOG("Error while obtaining js environment information");
161 return status;
162 }
163
164 if (argc == ARGS_ONE) {
165 return napi_ok;
166 } else if (argc == ARGS_TWO) {
167 napi_valuetype valueType = napi_undefined;
168 status = napi_typeof(env, argv[ARGS_ONE], &valueType);
169 if (status != napi_ok) {
170 NAPI_ERR_LOG("Error while obtaining js environment information");
171 return status;
172 }
173 if (valueType == napi_number) {
174 return napi_ok;
175 }
176 if (valueType == napi_boolean) {
177 isAsync = true;
178 }
179 status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
180 return status;
181 } else {
182 NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
183 return napi_invalid_arg;
184 }
185 }
186
ParseUserIdFormCbInfo(napi_env env,napi_callback_info info)187 static int32_t ParseUserIdFormCbInfo(napi_env env, napi_callback_info info)
188 {
189 size_t argc = ARGS_TWO;
190 napi_value argv[ARGS_TWO] = {0};
191 napi_status status;
192 int userId = -1;
193 status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
194 if (status == napi_ok) {
195 napi_valuetype valueType = napi_undefined;
196 status = napi_typeof(env, argv[ARGS_ONE], &valueType);
197 if (status == napi_ok && valueType == napi_number) {
198 napi_get_value_int32(env, argv[ARGS_ONE], &userId);
199 }
200 }
201 return userId;
202 }
203
204
GetUserIdFromSendableContext(SendablePhotoAccessHelperAsyncContext * context)205 static int32_t GetUserIdFromSendableContext(SendablePhotoAccessHelperAsyncContext *context)
206 {
207 if (context == nullptr || context->objectInfo == nullptr) {
208 return -1;
209 }
210 return context->objectInfo->GetUserId();
211 }
212
213 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)214 napi_value SendablePhotoAccessHelper::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
215 {
216 napi_status status;
217 napi_value result = nullptr;
218 napi_value thisVar = nullptr;
219 MediaLibraryTracer tracer;
220 tracer.Start("MediaLibraryNapiConstructor");
221 int32_t userId = ParseUserIdFormCbInfo(env, info);
222 UserFileClient::SetUserId(userId);
223
224 NAPI_CALL(env, napi_get_undefined(env, &result));
225 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
226 if (status != napi_ok || thisVar == nullptr) {
227 NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
228 return result;
229 }
230
231 unique_ptr<SendablePhotoAccessHelper> obj = make_unique<SendablePhotoAccessHelper>();
232 if (obj == nullptr) {
233 return result;
234 }
235 obj->env_ = env;
236 obj->SetUserId(userId);
237 bool isAsync = false;
238 NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
239 if (!isAsync) {
240 unique_lock<mutex> helperLock(sUserFileClientMutex_);
241 if (!UserFileClient::IsValid(obj->GetUserId())) {
242 UserFileClient::Init(env, info, obj->GetUserId());
243 if (!UserFileClient::IsValid(obj->GetUserId())) {
244 NAPI_ERR_LOG("UserFileClient creation failed");
245 helperLock.unlock();
246 return result;
247 }
248 }
249 helperLock.unlock();
250 }
251 status = napi_wrap_sendable(env, thisVar, reinterpret_cast<void *>(obj.get()),
252 SendablePhotoAccessHelper::MediaLibraryNapiDestructor, nullptr);
253 if (status == napi_ok) {
254 obj.release();
255 return thisVar;
256 } else {
257 NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
258 }
259 return result;
260 }
261
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid,const int32_t userId=-1)262 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid, const int32_t userId = -1)
263 {
264 napi_value propertyNames;
265 uint32_t propertyLength;
266 napi_valuetype valueType = napi_undefined;
267 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
268 if (valueType != napi_object) {
269 return false;
270 }
271
272 NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
273 NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
274 if (propertyLength == 0) {
275 return false;
276 }
277 if (checkIsValid && (!UserFileClient::IsValid(userId))) {
278 NAPI_ERR_LOG("UserFileClient is not valid");
279 return false;
280 }
281 return true;
282 }
283
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)284 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
285 bool isAsync = false)
286 {
287 constexpr size_t argContext = 1;
288 size_t argc = argContext;
289 napi_value argv[ARGS_TWO] = {0};
290
291 napi_value thisVar = nullptr;
292 napi_value ctor = nullptr;
293 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
294 NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
295
296 if (isAsync) {
297 argc = ARGS_TWO;
298 NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
299 argv[ARGS_ONE] = argv[argContext];
300 }
301 int32_t userId = -1;
302 if (argc > 1 && !isAsync) {
303 argc = ARGS_TWO;
304 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
305 NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
306 napi_valuetype valueType = napi_undefined;
307 napi_typeof(env, argv[ARGS_ONE], &valueType);
308 if (valueType == napi_number) {
309 NAPI_CALL(env, napi_get_value_int32(env, argv[ARGS_ONE], &userId));
310 if (userId != -1 && !SendableMediaLibraryNapiUtils::IsSystemApp()) {
311 NAPI_ERR_LOG("CreateNewInstance failed, target is not system app");
312 return nullptr;
313 }
314 UserFileClient::SetUserId(userId);
315 NAPI_INFO_LOG("CreateNewInstance for other user is %{public}d", userId);
316 }
317 }
318
319 napi_value result = nullptr;
320 NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
321 if (!CheckWhetherInitSuccess(env, result, !isAsync, userId)) {
322 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
323 NAPI_CALL(env, napi_get_undefined(env, &result));
324 }
325 return result;
326 }
327
GetPhotoAccessHelper(napi_env env,napi_callback_info info)328 napi_value SendablePhotoAccessHelper::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
329 {
330 MediaLibraryTracer tracer;
331 tracer.Start("GetPhotoAccessHelper");
332 if (photoAccessHelperConstructor_ == nullptr) {
333 napi_value exports = nullptr;
334 napi_create_object(env, &exports);
335 SendablePhotoAccessHelper::Init(env, exports);
336 }
337
338 return CreateNewInstance(env, info, photoAccessHelperConstructor_);
339 }
340
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)341 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
342 const string &name, int32_t enumValue)
343 {
344 napi_value enumNapiValue;
345 napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
346 if (status == napi_ok) {
347 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
348 }
349 return status;
350 }
351
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)352 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
353 {
354 napi_value result = nullptr;
355 NAPI_CALL(env, napi_create_object(env, &result));
356 for (size_t i = 0; i < properties.size(); i++) {
357 NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], i + offset));
358 }
359 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
360 return result;
361 }
362
GetNapiFileResult(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)363 static void GetNapiFileResult(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
364 unique_ptr<SendableJSAsyncContextOutput> &jsContext)
365 {
366 // Create FetchResult object using the contents of resultSet
367 if (context->fetchFileResult == nullptr) {
368 NAPI_ERR_LOG("No fetch file result found!");
369 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
370 "Failed to obtain Fetch File Result");
371 return;
372 }
373 napi_value fileResult = SendableFetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
374 if (fileResult == nullptr) {
375 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
376 "Failed to create js object for Fetch File Result");
377 } else {
378 jsContext->data = fileResult;
379 jsContext->status = true;
380 napi_get_undefined(env, &jsContext->error);
381 }
382 }
383
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)384 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
385 {
386 MediaLibraryTracer tracer;
387 tracer.Start("GetFileAssetsAsyncCallbackComplete");
388
389 SendablePhotoAccessHelperAsyncContext *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
390 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
391
392 unique_ptr<SendableJSAsyncContextOutput> jsContext = make_unique<SendableJSAsyncContextOutput>();
393 jsContext->status = false;
394 napi_get_undefined(env, &jsContext->data);
395
396 if (context->error != ERR_DEFAULT) {
397 context->HandleError(env, jsContext->error);
398 } else {
399 GetNapiFileResult(env, context, jsContext);
400 }
401
402 tracer.Finish();
403 if (context->work != nullptr) {
404 SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
405 context->work, *jsContext);
406 }
407 delete context;
408 }
409
410 #ifdef MEDIALIBRARY_COMPATIBILITY
SetCompatAlbumName(AlbumAsset * albumData)411 static void SetCompatAlbumName(AlbumAsset *albumData)
412 {
413 string albumName;
414 switch (albumData->GetAlbumSubType()) {
415 case PhotoAlbumSubType::CAMERA:
416 albumName = CAMERA_ALBUM_NAME;
417 break;
418 case PhotoAlbumSubType::SCREENSHOT:
419 albumName = SCREEN_SHOT_ALBUM_NAME;
420 break;
421 default:
422 NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
423 }
424 albumData->SetAlbumName(albumName);
425 }
426 #else
SetAlbumCoverUri(SendablePhotoAccessHelperAsyncContext * context,unique_ptr<AlbumAsset> & album)427 static void SetAlbumCoverUri(SendablePhotoAccessHelperAsyncContext *context, unique_ptr<AlbumAsset> &album)
428 {
429 MediaLibraryTracer tracer;
430 tracer.Start("SetAlbumCoverUri");
431 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
432 DataShare::DataSharePredicates predicates;
433 predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
434 predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
435 predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
436 vector<string> columns;
437 string queryUri = MEDIALIBRARY_DATA_URI;
438 if (!context->networkId.empty()) {
439 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
440 NAPI_DEBUG_LOG("querycoverUri is = %{private}s", queryUri.c_str());
441 }
442 Uri uri(queryUri);
443 int errCode = 0;
444 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
445 uri, predicates, columns, errCode, GetUserIdFromSendableContext(context));
446 if (resultSet == nullptr) {
447 NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
448 return;
449 }
450 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
451 fetchFileResult->SetNetworkId(context->networkId);
452 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
453 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
454 string coverUri = fileAsset->GetUri();
455 album->SetCoverUri(coverUri);
456 NAPI_DEBUG_LOG("coverUri is = %{private}s", album->GetCoverUri().c_str());
457 }
458 #endif
459
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)460 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
461 const string &networkId)
462 {
463 #ifdef MEDIALIBRARY_COMPATIBILITY
464 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
465 TYPE_INT32)));
466 albumData->SetAlbumType(static_cast<PhotoAlbumType>(
467 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
468 albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
469 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
470 SetCompatAlbumName(albumData);
471 #else
472 // Get album id index and value
473 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
474 TYPE_INT32)));
475
476 // Get album title index and value
477 albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
478 TYPE_STRING)));
479 #endif
480
481 // Get album asset count index and value
482 albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
483 MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
484 MEDIA_API_VERSION_DEFAULT);
485 albumData->SetAlbumUri(fileUri.ToString());
486 // Get album relativePath index and value
487 albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
488 resultSet, TYPE_STRING)));
489 albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
490 resultSet, TYPE_INT64)));
491 }
492
493 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)494 static void ReplaceAlbumName(const string &arg, string &argInstead)
495 {
496 if (arg == CAMERA_ALBUM_NAME) {
497 argInstead = to_string(PhotoAlbumSubType::CAMERA);
498 } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
499 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
500 } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
501 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
502 } else {
503 argInstead = arg;
504 }
505 }
506
DoReplaceRelativePath(const string & arg,string & argInstead)507 static bool DoReplaceRelativePath(const string &arg, string &argInstead)
508 {
509 if (arg == CAMERA_PATH) {
510 argInstead = to_string(PhotoAlbumSubType::CAMERA);
511 } else if (arg == SCREEN_SHOT_PATH) {
512 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
513 } else if (arg == SCREEN_RECORD_PATH) {
514 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
515 } else if (arg.empty()) {
516 argInstead = arg;
517 return false;
518 } else {
519 argInstead = arg;
520 }
521 return true;
522 }
523
ReplaceRelativePath(string & selection,size_t pos,const string & keyInstead,const string & arg,string & argInstead)524 static inline void ReplaceRelativePath(string &selection, size_t pos, const string &keyInstead, const string &arg,
525 string &argInstead)
526 {
527 bool shouldReplace = DoReplaceRelativePath(arg, argInstead);
528 if (shouldReplace) {
529 selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), keyInstead);
530 }
531 }
532
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead,const int32_t mode)533 void SendablePhotoAccessHelper::ReplaceSelection(string &selection, vector<string> &selectionArgs,
534 const string &key, const string &keyInstead, const int32_t mode)
535 {
536 for (size_t pos = 0; pos != string::npos;) {
537 pos = selection.find(key, pos);
538 if (pos == string::npos) {
539 break;
540 }
541
542 size_t argPos = selection.find('?', pos);
543 if (argPos == string::npos) {
544 break;
545 }
546 size_t argIndex = 0;
547 for (size_t i = 0; i < argPos; i++) {
548 if (selection[i] == '?') {
549 argIndex++;
550 }
551 }
552 if (argIndex > selectionArgs.size() - 1) {
553 NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
554 selection.c_str());
555 break;
556 }
557 const string &arg = selectionArgs[argIndex];
558 string argInstead = arg;
559 if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
560 if (mode == SendableReplaceSelectionMode::SENDABLE_ADD_DOCS_TO_RELATIVE_PATH) {
561 argInstead = MediaFileUtils::AddDocsToRelativePath(arg);
562 } else {
563 ReplaceRelativePath(selection, pos, keyInstead, arg, argInstead);
564 }
565 } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
566 ReplaceAlbumName(arg, argInstead);
567 selection.replace(pos, key.length(), keyInstead);
568 } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
569 selection.replace(pos, key.length(), keyInstead);
570 }
571 selectionArgs[argIndex] = argInstead;
572 argPos = selection.find('?', pos);
573 if (argPos == string::npos) {
574 break;
575 }
576 pos = argPos + 1;
577 }
578 }
579 #endif
580
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],SendablePhotoAccessHelperAsyncContext & asyncContext)581 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
582 SendablePhotoAccessHelperAsyncContext &asyncContext)
583 {
584 const int32_t refCount = 1;
585 napi_value result = nullptr;
586 auto context = &asyncContext;
587 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
588 int32_t fileMediaType = 0;
589 size_t res = 0;
590 char relativePathBuffer[PATH_MAX];
591 char titleBuffer[PATH_MAX];
592 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
593
594 for (size_t i = PARAM0; i < argc; i++) {
595 napi_valuetype valueType = napi_undefined;
596 napi_typeof(env, argv[i], &valueType);
597 if (i == PARAM0 && valueType == napi_number) {
598 napi_get_value_int32(env, argv[i], &fileMediaType);
599 } else if (i == PARAM1 && valueType == napi_string) {
600 napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
601 NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
602 } else if (i == PARAM2 && valueType == napi_string) {
603 napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
604 NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
605 } else if (i == PARAM3 && valueType == napi_function) {
606 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
607 } else {
608 NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
609 return result;
610 }
611 }
612
613 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
614 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
615 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
616
617 context->assetType = TYPE_DEFAULT;
618 if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
619 context->assetType = TYPE_PHOTO;
620 } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
621 context->assetType = TYPE_AUDIO;
622 }
623
624 NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
625 // Return true napi_value if params are successfully obtained
626 napi_get_boolean(env, true, &result);
627 return result;
628 }
629
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],SendablePhotoAccessHelperAsyncContext & asyncContext)630 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
631 SendablePhotoAccessHelperAsyncContext &asyncContext)
632 {
633 const int32_t refCount = 1;
634 napi_value result = nullptr;
635 auto context = &asyncContext;
636 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
637 size_t res = 0;
638 char buffer[PATH_MAX];
639
640 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
641
642 for (size_t i = PARAM0; i < argc; i++) {
643 napi_valuetype valueType = napi_undefined;
644 napi_typeof(env, argv[i], &valueType);
645
646 if (i == PARAM0 && valueType == napi_string) {
647 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
648 } else if (i == PARAM1 && valueType == napi_function) {
649 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
650 break;
651 } else {
652 NAPI_ASSERT(env, false, "type mismatch");
653 }
654 }
655
656 context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
657
658 // Return true napi_value if params are successfully obtained
659 napi_get_boolean(env, true, &result);
660 return result;
661 }
662
JSReleaseCompleteCallback(napi_env env,napi_status status,SendablePhotoAccessHelperAsyncContext * context)663 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
664 SendablePhotoAccessHelperAsyncContext *context)
665 {
666 MediaLibraryTracer tracer;
667 tracer.Start("JSReleaseCompleteCallback");
668
669 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
670
671 unique_ptr<SendableJSAsyncContextOutput> jsContext = make_unique<SendableJSAsyncContextOutput>();
672 jsContext->status = false;
673 if (context->objectInfo != nullptr) {
674 napi_create_int32(env, E_SUCCESS, &jsContext->data);
675 jsContext->status = true;
676 napi_get_undefined(env, &jsContext->error);
677 } else {
678 NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
679 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
680 "UserFileClient is invalid");
681 napi_get_undefined(env, &jsContext->data);
682 }
683
684 tracer.Finish();
685 SendableMediaLibraryNapiUtils::InvokeJSAsyncMethodWithoutWork(env, context->deferred, context->callbackRef,
686 *jsContext);
687
688 delete context;
689 }
690
JSRelease(napi_env env,napi_callback_info info)691 napi_value SendablePhotoAccessHelper::JSRelease(napi_env env, napi_callback_info info)
692 {
693 napi_status status;
694 napi_value result = nullptr;
695 size_t argc = ARGS_ONE;
696 napi_value argv[ARGS_ONE] = {0};
697 napi_value thisVar = nullptr;
698 int32_t refCount = 1;
699
700 MediaLibraryTracer tracer;
701 tracer.Start("JSRelease");
702
703 GET_JS_ARGS(env, info, argc, argv, thisVar);
704 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
705 napi_get_undefined(env, &result);
706
707 unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
708 make_unique<SendablePhotoAccessHelperAsyncContext>();
709 status = napi_unwrap_sendable(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
710 NAPI_ASSERT(env, status == napi_ok && asyncContext->objectInfo != nullptr, "Failed to get object info");
711
712 if (argc == PARAM1) {
713 napi_valuetype valueType = napi_undefined;
714 napi_typeof(env, argv[PARAM0], &valueType);
715 if (valueType == napi_function) {
716 napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
717 }
718 }
719 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
720
721 NAPI_CALL(env, napi_remove_wrap_sendable(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
722 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
723 SendablePhotoAccessHelperAsyncContext *context = asyncContext.get();
724 std::function<void()> task = [env, status, context]() {
725 JSReleaseCompleteCallback(env, status, context);
726 };
727 status = napi_send_event(env, task, napi_eprio_immediate);
728 if (status != napi_ok) {
729 napi_get_undefined(env, &result);
730 } else {
731 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
732 asyncContext.release();
733 }
734
735 return result;
736 }
737
AddDefaultPhotoAlbumColumns(napi_env env,vector<string> & fetchColumn)738 static napi_value AddDefaultPhotoAlbumColumns(napi_env env, vector<string> &fetchColumn)
739 {
740 auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
741 for (const auto &column : fetchColumn) {
742 if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
743 validFetchColumns.insert(column);
744 } else if (column.compare(MEDIA_DATA_DB_URI) == 0) {
745 // uri is default property of album
746 continue;
747 } else {
748 NAPI_ERR_LOG("unknown columns:%{public}s", column.c_str());
749 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
750 return nullptr;
751 }
752 }
753 fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
754
755 napi_value result = nullptr;
756 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
757 return result;
758 }
759
AddDefaultColumnsForNonAnalysisAlbums(SendablePhotoAccessHelperAsyncContext & context)760 static void AddDefaultColumnsForNonAnalysisAlbums(SendablePhotoAccessHelperAsyncContext& context)
761 {
762 if (!context.isAnalysisAlbum) {
763 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
764 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
765 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_LPATH);
766 }
767 }
768
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],SendablePhotoAccessHelperAsyncContext & asyncContext)769 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
770 SendablePhotoAccessHelperAsyncContext &asyncContext)
771 {
772 const int32_t refCount = 1;
773 napi_value result = nullptr;
774 auto context = &asyncContext;
775 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
776 size_t res = 0;
777 char buffer[PATH_MAX];
778 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
779 for (size_t i = 0; i < argc; i++) {
780 napi_valuetype valueType = napi_undefined;
781 napi_typeof(env, argv[i], &valueType);
782 if (i == 0 && valueType == napi_number) {
783 napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
784 } else if (i == PARAM1 && valueType == napi_string) {
785 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
786 } else if (i == PARAM2 && valueType == napi_function) {
787 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
788 break;
789 } else {
790 NAPI_ASSERT(env, false, "type mismatch");
791 }
792 }
793 if (context->parentSmartAlbumId < 0) {
794 NAPI_ASSERT(env, false, "type mismatch");
795 }
796 string smartName = string(buffer);
797 if (smartName.empty()) {
798 NAPI_ASSERT(env, false, "type mismatch");
799 }
800 context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
801 napi_get_boolean(env, true, &result);
802 return result;
803 }
804
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,bool needExtraOption=false)805 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
806 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context, bool needExtraOption = false)
807 {
808 constexpr size_t minArgs = ARGS_ONE;
809 constexpr size_t maxArgs = ARGS_TWO;
810 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
811 JS_ERR_PARAMETER_INVALID);
812
813 /* Parse the first argument */
814 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(
815 env, context->argv[PARAM0], ASSET_FETCH_OPT, context), JS_INNER_FAIL);
816
817 switch (context->assetType) {
818 case TYPE_AUDIO: {
819 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
820 AudioColumn::IsAudioColumn, TYPE_AUDIO));
821 break;
822 }
823 case TYPE_PHOTO: {
824 if (needExtraOption) {
825 bool isAddDefaultColumn =
826 std::find(context->fetchColumn.begin(), context->fetchColumn.end(), MEDIA_DATA_DB_URI) !=
827 context->fetchColumn.end();
828 if (isAddDefaultColumn) {
829 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
830 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
831 } else {
832 std::set<std::string> fetchColumns;
833 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddAssetColumns(env, context->fetchColumn,
834 PhotoColumn::IsPhotoColumn, fetchColumns));
835 }
836 } else {
837 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
838 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
839 }
840 break;
841 }
842 default: {
843 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
844 return nullptr;
845 }
846 }
847 auto &predicates = context->predicates;
848 predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
849 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
850 if (context->assetType == TYPE_PHOTO) {
851 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
852 predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
853 predicates.EqualTo(
854 PhotoColumn::PHOTO_BURST_COVER_LEVEL, to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
855 }
856 napi_value result = nullptr;
857 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
858 return result;
859 }
860
861 // Easter egg operation: query duplicate assets
EasterEgg(SendablePhotoAccessHelperAsyncContext * context)862 static bool EasterEgg(SendablePhotoAccessHelperAsyncContext* context)
863 {
864 string queryUri;
865 if (context->uri == URI_FIND_ALL_DUPLICATE_ASSETS) {
866 queryUri = PAH_FIND_ALL_DUPLICATE_ASSETS;
867 } else if (context->uri == URI_FIND_ALL_DUPLICATE_ASSETS_TO_DELETE) {
868 queryUri = PAH_FIND_DUPLICATE_ASSETS_TO_DELETE;
869 } else {
870 return false;
871 }
872 if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
873 NAPI_ERR_LOG("Easter egg operation failed, target is not system app");
874 return false;
875 };
876 bool isQueryCount = find(context->fetchColumn.begin(), context->fetchColumn.end(), MEDIA_COLUMN_COUNT)
877 != context->fetchColumn.end();
878 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
879 NAPI_INFO_LOG(
880 "Easter egg operation start: %{public}s, is query count: %{public}d",
881 queryUri == PAH_FIND_ALL_DUPLICATE_ASSETS ?
882 "find all duplicate assets" : "find all duplicate assets to delete", isQueryCount);
883 int errCode = 0;
884 Uri uri(queryUri);
885 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
886 context->predicates, context->fetchColumn, errCode, GetUserIdFromSendableContext(context));
887 if (resultSet == nullptr) {
888 context->SaveError(errCode);
889 NAPI_ERR_LOG("Easter egg operation failed, errCode: %{public}d", errCode);
890 return true;
891 }
892 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
893 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
894 context->fetchFileResult->SetUserId(GetUserIdFromSendableContext(context));
895 NAPI_INFO_LOG(
896 "Easter egg operation end: %{public}s, is query count: %{public}d, cost time: %{public}" PRId64 "ms",
897 queryUri == PAH_FIND_ALL_DUPLICATE_ASSETS ?
898 "find all duplicate assets" : "find all duplicate assets to delete", isQueryCount,
899 MediaFileUtils::UTCTimeMilliSeconds() - startTime);
900 return true;
901 }
902
PhotoAccessGetAssetsExecute(napi_env env,void * data)903 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
904 {
905 MediaLibraryTracer tracer;
906 tracer.Start("PhotoAccessGetAssetsExecute");
907
908 auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
909 if (EasterEgg(context)) {
910 return;
911 }
912 string queryUri;
913 switch (context->assetType) {
914 case TYPE_PHOTO: {
915 queryUri = PAH_QUERY_PHOTO;
916 SendableMediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
917 break;
918 }
919 default: {
920 context->SaveError(-EINVAL);
921 return;
922 }
923 }
924
925 Uri uri(queryUri);
926 int errCode = 0;
927 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
928 context->predicates, context->fetchColumn, errCode, GetUserIdFromSendableContext(context));
929 if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
930 Uri queryWithUri(context->uri);
931 resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode,
932 GetUserIdFromSendableContext(context));
933 }
934 if (resultSet == nullptr) {
935 context->SaveError(errCode);
936 return;
937 }
938 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
939 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
940 context->fetchFileResult->SetUserId(GetUserIdFromSendableContext(context));
941 }
942
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)943 napi_value SendablePhotoAccessHelper::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
944 {
945 unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
946 make_unique<SendablePhotoAccessHelperAsyncContext>();
947 asyncContext->assetType = TYPE_PHOTO;
948 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
949
950 return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
951 PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
952 }
953
GetPhotoAlbumQueryResult(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)954 static void GetPhotoAlbumQueryResult(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
955 unique_ptr<SendableJSAsyncContextOutput> &jsContext)
956 {
957 napi_value fileResult = SendableFetchFileResultNapi::CreateFetchFileResult(env,
958 move(context->fetchPhotoAlbumResult));
959 if (fileResult == nullptr) {
960 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
961 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
962 "Failed to create js object for Fetch Album Result");
963 return;
964 }
965 jsContext->data = fileResult;
966 jsContext->status = true;
967 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
968 }
969
JSGetPhotoAlbumsExecute(napi_env env,void * data)970 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
971 {
972 MediaLibraryTracer tracer;
973 tracer.Start("JSGetPhotoAlbumsExecute");
974
975 auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
976 string queryUri;
977 if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
978 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
979 UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
980 } else if (context->isAnalysisAlbum) {
981 queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
982 PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
983 } else {
984 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
985 UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
986 }
987 Uri uri(queryUri);
988 int errCode = 0;
989 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode,
990 GetUserIdFromSendableContext(context));
991 if (resultSet == nullptr) {
992 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
993 if (errCode == E_PERMISSION_DENIED) {
994 if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
995 context->error = OHOS_PERMISSION_DENIED_CODE;
996 } else {
997 context->SaveError(E_HAS_DB_ERROR);
998 }
999 } else {
1000 context->SaveError(E_HAS_DB_ERROR);
1001 }
1002 return;
1003 }
1004
1005 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
1006 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
1007 context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
1008 context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
1009 PhotoAlbumSubType::GEOGRAPHY_LOCATION);
1010 context->fetchPhotoAlbumResult->SetUserId(GetUserIdFromSendableContext(context));
1011 }
1012
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)1013 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
1014 {
1015 MediaLibraryTracer tracer;
1016 tracer.Start("JSGetPhotoAlbumsCompleteCallback");
1017
1018 auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
1019 unique_ptr<SendableJSAsyncContextOutput> jsContext = make_unique<SendableJSAsyncContextOutput>();
1020 jsContext->status = false;
1021 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1022 if (context->error != ERR_DEFAULT || context->fetchPhotoAlbumResult == nullptr) {
1023 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1024 context->HandleError(env, jsContext->error);
1025 } else {
1026 GetPhotoAlbumQueryResult(env, context, jsContext);
1027 }
1028
1029 tracer.Finish();
1030 if (context->work != nullptr) {
1031 SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1032 context->work, *jsContext);
1033 }
1034 delete context;
1035 }
1036
CreateMediaTypeUserFileEnum(napi_env env)1037 napi_value SendablePhotoAccessHelper::CreateMediaTypeUserFileEnum(napi_env env)
1038 {
1039 const int32_t startIdx = 1;
1040 return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
1041 }
1042
CreateKeyFrameThumbnailTypeEnum(napi_env env)1043 napi_value SendablePhotoAccessHelper::CreateKeyFrameThumbnailTypeEnum(napi_env env)
1044 {
1045 const int32_t startIdx = 1;
1046 return CreateNumberEnumProperty(env, keyFrameThumbnailTypeEnum, sKeyFrameThumbnailTypeRef_, startIdx);
1047 }
1048
CreateAlbumTypeEnum(napi_env env)1049 napi_value SendablePhotoAccessHelper::CreateAlbumTypeEnum(napi_env env)
1050 {
1051 napi_value result = nullptr;
1052 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
1053
1054 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
1055 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
1056 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SMART", PhotoAlbumType::SMART), JS_INNER_FAIL);
1057 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE", PhotoAlbumType::SOURCE), JS_INNER_FAIL);
1058
1059 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
1060 return result;
1061 }
1062
CreateAlbumSubTypeEnum(napi_env env)1063 napi_value SendablePhotoAccessHelper::CreateAlbumSubTypeEnum(napi_env env)
1064 {
1065 napi_value result = nullptr;
1066 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
1067
1068 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
1069 JS_INNER_FAIL);
1070 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE_GENERIC", PhotoAlbumSubType::SOURCE_GENERIC),
1071 JS_INNER_FAIL);
1072 for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
1073 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
1074 PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
1075 }
1076 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "CLASSIFY", PhotoAlbumSubType::CLASSIFY),
1077 JS_INNER_FAIL);
1078 for (size_t i = 0; i < analysisAlbumSubType.size(); i++) {
1079 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, analysisAlbumSubType[i],
1080 PhotoAlbumSubType::GEOGRAPHY_LOCATION + i), JS_INNER_FAIL);
1081 }
1082 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
1083
1084 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
1085 return result;
1086 }
1087
CreateMovingPhotoEffectModeEnum(napi_env env)1088 napi_value SendablePhotoAccessHelper::CreateMovingPhotoEffectModeEnum(napi_env env)
1089 {
1090 return CreateNumberEnumProperty(env, movingPhotoEffectModeEnum, sMovingPhotoEffectModeEnumRef_);
1091 }
1092
CreateDynamicRangeTypeEnum(napi_env env)1093 napi_value SendablePhotoAccessHelper::CreateDynamicRangeTypeEnum(napi_env env)
1094 {
1095 return CreateNumberEnumProperty(env, dynamicRangeTypeEnum, sDynamicRangeTypeEnumRef_);
1096 }
1097
GetAlbumFetchOption(napi_env env,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,bool hasCallback)1098 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<SendablePhotoAccessHelperAsyncContext> &context,
1099 bool hasCallback)
1100 {
1101 if (context->argc < (ARGS_ONE + hasCallback)) {
1102 NAPI_ERR_LOG("No arguments to parse");
1103 return nullptr;
1104 }
1105
1106 // The index of fetchOption should always be the last arg besides callback
1107 napi_value fetchOption = context->argv[context->argc - 1 - hasCallback];
1108 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT,
1109 context), JS_INNER_FAIL);
1110 if (!context->uri.empty()) {
1111 if (context->uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != std::string::npos) {
1112 context->isAnalysisAlbum = 1; // 1:is an analysis album
1113 }
1114 }
1115 napi_value result = nullptr;
1116 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1117 return result;
1118 }
1119
ParseLocationAlbumTypes(unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,const int32_t albumSubType)1120 static bool ParseLocationAlbumTypes(unique_ptr<SendablePhotoAccessHelperAsyncContext> &context,
1121 const int32_t albumSubType)
1122 {
1123 if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
1124 context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
1125 context->fetchColumn.insert(context->fetchColumn.end(),
1126 PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
1127 PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
1128 SendableMediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
1129 return false;
1130 } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
1131 context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
1132 context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
1133 string onClause = PhotoAlbumColumns::ALBUM_NAME + " = " + CITY_ID;
1134 context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
1135 context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
1136 }
1137 return true;
1138 }
1139
ApplyTablePrefixToAlbumIdPredicates(DataSharePredicates & predicates)1140 static void ApplyTablePrefixToAlbumIdPredicates(DataSharePredicates& predicates)
1141 {
1142 constexpr int32_t fieldIdx = 0;
1143 auto& items = predicates.GetOperationList();
1144 string targetColumn = "AnalysisAlbum.album_id";
1145 std::vector<DataShare::OperationItem> tmpOperations = {};
1146 for (const DataShare::OperationItem& item : items) {
1147 if (item.singleParams.empty()) {
1148 tmpOperations.push_back(item);
1149 continue;
1150 }
1151 if (static_cast<string>(item.GetSingle(fieldIdx)) == PhotoAlbumColumns::ALBUM_ID) {
1152 DataShare::OperationItem tmpItem = item;
1153 tmpItem.singleParams[fieldIdx] = targetColumn;
1154 tmpOperations.push_back(tmpItem);
1155 continue;
1156 }
1157 tmpOperations.push_back(item);
1158 }
1159 predicates = DataSharePredicates(move(tmpOperations));
1160 }
1161
AddHighlightAlbumPredicates(DataSharePredicates & predicates)1162 static void AddHighlightAlbumPredicates(DataSharePredicates& predicates)
1163 {
1164 vector<string> onClause = {
1165 ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
1166 HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
1167 };
1168 predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
1169 predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
1170 ApplyTablePrefixToAlbumIdPredicates(predicates);
1171 }
1172
ParseAlbumTypes(napi_env env,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1173 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1174 {
1175 if (context->argc < ARGS_TWO) {
1176 NAPI_ERR_LOG("No arguments to parse");
1177 return nullptr;
1178 }
1179
1180 /* Parse the first argument to photo album type */
1181 int32_t albumType;
1182 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
1183 if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
1184 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
1185 return nullptr;
1186 }
1187 context->isAnalysisAlbum = (albumType == PhotoAlbumType::SMART) ? 1 : 0;
1188
1189 /* Parse the second argument to photo album subType */
1190 int32_t albumSubType;
1191 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
1192 if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
1193 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
1194 return nullptr;
1195 }
1196
1197 if (!ParseLocationAlbumTypes(context, albumSubType)) {
1198 napi_value result = nullptr;
1199 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1200 return result;
1201 }
1202
1203 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
1204 if (albumSubType != ANY) {
1205 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
1206 }
1207 if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
1208 context->predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
1209 }
1210 if (albumSubType == PhotoAlbumSubType::HIGHLIGHT || albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
1211 context->isHighlightAlbum = albumSubType;
1212 AddHighlightAlbumPredicates(context->predicates);
1213 }
1214
1215 napi_value result = nullptr;
1216 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1217 return result;
1218 }
1219
RestrictAlbumSubtypeOptions(unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1220 static void RestrictAlbumSubtypeOptions(unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1221 {
1222 if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
1223 context->predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
1224 to_string(PhotoAlbumSubType::USER_GENERIC),
1225 to_string(PhotoAlbumSubType::FAVORITE),
1226 to_string(PhotoAlbumSubType::VIDEO),
1227 to_string(PhotoAlbumSubType::IMAGE),
1228 }));
1229 } else {
1230 context->predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
1231 }
1232 }
1233
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1234 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
1235 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1236 {
1237 constexpr size_t minArgs = ARGS_ZERO;
1238 constexpr size_t maxArgs = ARGS_FOUR;
1239 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1240 JS_ERR_PARAMETER_INVALID);
1241
1242 bool hasCallback = false;
1243 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
1244 JS_ERR_PARAMETER_INVALID);
1245 if (context->argc == ARGS_THREE) {
1246 napi_valuetype valueType = napi_undefined;
1247 if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
1248 (valueType == napi_undefined || valueType == napi_null)) {
1249 context->argc -= 1;
1250 }
1251 }
1252 switch (context->argc - hasCallback) {
1253 case ARGS_ZERO:
1254 break;
1255 case ARGS_ONE:
1256 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
1257 break;
1258 case ARGS_TWO:
1259 CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
1260 break;
1261 case ARGS_THREE:
1262 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
1263 CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
1264 break;
1265 default:
1266 return nullptr;
1267 }
1268 RestrictAlbumSubtypeOptions(context);
1269 if (context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
1270 context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
1271 CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
1272 AddDefaultColumnsForNonAnalysisAlbums(*context);
1273 if (context->isHighlightAlbum) {
1274 context->fetchColumn.erase(std::remove(context->fetchColumn.begin(), context->fetchColumn.end(),
1275 PhotoAlbumColumns::ALBUM_ID), context->fetchColumn.end());
1276 context->fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
1277 PhotoAlbumColumns::ALBUM_ID);
1278 }
1279 }
1280 napi_value result = nullptr;
1281 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1282 return result;
1283 }
1284
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)1285 napi_value SendablePhotoAccessHelper::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
1286 {
1287 unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1288 make_unique<SendablePhotoAccessHelperAsyncContext>();
1289 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1290 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
1291
1292 return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums",
1293 JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
1294 }
1295
CreatePositionTypeEnum(napi_env env)1296 napi_value SendablePhotoAccessHelper::CreatePositionTypeEnum(napi_env env)
1297 {
1298 const int32_t startIdx = 1;
1299 return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
1300 }
1301
CreatePhotoSubTypeEnum(napi_env env)1302 napi_value SendablePhotoAccessHelper::CreatePhotoSubTypeEnum(napi_env env)
1303 {
1304 return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
1305 }
1306
ParseHiddenPhotosDisplayMode(napi_env env,const unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,const int32_t fetchMode)1307 napi_value ParseHiddenPhotosDisplayMode(napi_env env,
1308 const unique_ptr<SendablePhotoAccessHelperAsyncContext> &context, const int32_t fetchMode)
1309 {
1310 switch (fetchMode) {
1311 case ASSETS_MODE:
1312 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::HIDDEN);
1313 break;
1314 case ALBUMS_MODE:
1315 context->predicates.EqualTo(PhotoAlbumColumns::CONTAINS_HIDDEN, to_string(1));
1316 break;
1317 default:
1318 NapiError::ThrowError(
1319 env, OHOS_INVALID_PARAM_CODE, "Invalid fetch mode: " + to_string(fetchMode));
1320 return nullptr;
1321 }
1322 napi_value result = nullptr;
1323 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1324 return result;
1325 }
1326
ParseArgsGetHiddenAlbums(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1327 napi_value ParseArgsGetHiddenAlbums(napi_env env, napi_callback_info info,
1328 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1329 {
1330 if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
1331 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1332 return nullptr;
1333 }
1334 napi_value result = nullptr;
1335 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1336 constexpr size_t minArgs = ARGS_ONE;
1337 constexpr size_t maxArgs = ARGS_THREE;
1338 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1339 OHOS_INVALID_PARAM_CODE);
1340 bool hasCallback = false;
1341 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
1342 OHOS_INVALID_PARAM_CODE);
1343 if (context->argc == ARGS_THREE) {
1344 napi_valuetype valueType = napi_undefined;
1345 if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
1346 (valueType == napi_undefined || valueType == napi_null)) {
1347 context->argc -= 1;
1348 }
1349 }
1350 int32_t fetchMode = 0;
1351 switch (context->argc - hasCallback) {
1352 case ARGS_ONE:
1353 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode),
1354 OHOS_INVALID_PARAM_CODE);
1355 break;
1356 case ARGS_TWO:
1357 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode),
1358 OHOS_INVALID_PARAM_CODE);
1359 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(
1360 env, context->argv[PARAM1], ALBUM_FETCH_OPT, context), OHOS_INVALID_PARAM_CODE);
1361 break;
1362 default:
1363 NapiError::ThrowError(
1364 env, OHOS_INVALID_PARAM_CODE, "Invalid parameter count: " + to_string(context->argc));
1365 return nullptr;
1366 }
1367 CHECK_NULLPTR_RET(ParseHiddenPhotosDisplayMode(env, context, fetchMode));
1368 CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
1369 context->hiddenAlbumFetchMode = fetchMode;
1370 if (fetchMode == HiddenPhotosDisplayMode::ASSETS_MODE) {
1371 return result;
1372 }
1373 context->hiddenOnly = true;
1374 context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COUNT);
1375 context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COVER);
1376 return result;
1377 }
1378
PahGetHiddenAlbums(napi_env env,napi_callback_info info)1379 napi_value SendablePhotoAccessHelper::PahGetHiddenAlbums(napi_env env, napi_callback_info info)
1380 {
1381 auto asyncContext = make_unique<SendablePhotoAccessHelperAsyncContext>();
1382 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1383 CHECK_NULLPTR_RET(ParseArgsGetHiddenAlbums(env, info, asyncContext));
1384 return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetHiddenAlbums",
1385 JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
1386 }
1387
1388 template <class AsyncContext>
AsyncContextSetStaticObjectInfo(napi_env env,napi_callback_info info,AsyncContext & asyncContext,const size_t minArgs,const size_t maxArgs)1389 static napi_status AsyncContextSetStaticObjectInfo(napi_env env, napi_callback_info info,
1390 AsyncContext &asyncContext, const size_t minArgs, const size_t maxArgs)
1391 {
1392 NAPI_INFO_LOG("AsyncContextSetStaticObjectInfo start");
1393 napi_value thisVar = nullptr;
1394 asyncContext->argc = maxArgs;
1395 CHECK_STATUS_RET(napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]), &thisVar,
1396 nullptr), "Failed to get cb info");
1397 CHECK_COND_RET(((asyncContext->argc >= minArgs) && (asyncContext->argc <= maxArgs)), napi_invalid_arg,
1398 "Number of args is invalid");
1399 if (minArgs > 0) {
1400 CHECK_COND_RET(asyncContext->argv[ARGS_ZERO] != nullptr, napi_invalid_arg, "Argument list is empty");
1401 }
1402 CHECK_STATUS_RET(SendableMediaLibraryNapiUtils::GetParamCallback(env, asyncContext),
1403 "Failed to get callback param!");
1404 return napi_ok;
1405 }
1406
CheckDisplayNameParams(SendablePhotoAccessHelperAsyncContext * context)1407 static bool CheckDisplayNameParams(SendablePhotoAccessHelperAsyncContext *context)
1408 {
1409 if (context == nullptr) {
1410 NAPI_ERR_LOG("Async context is null");
1411 return false;
1412 }
1413 if (!context->isCreateByComponent) {
1414 bool isValid = false;
1415 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1416 if (!isValid) {
1417 NAPI_ERR_LOG("getting displayName is invalid");
1418 return false;
1419 }
1420 if (displayName.empty()) {
1421 return false;
1422 }
1423 }
1424
1425 return true;
1426 }
1427
CheckCreateOption(SendablePhotoAccessHelperAsyncContext & context)1428 static napi_status CheckCreateOption(SendablePhotoAccessHelperAsyncContext &context)
1429 {
1430 bool isValid = false;
1431 int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
1432 string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
1433 if (isValid) {
1434 if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
1435 NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
1436 return napi_invalid_arg;
1437 }
1438 if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
1439 NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
1440 return napi_invalid_arg;
1441 } else {
1442 context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
1443 }
1444 }
1445
1446 return napi_ok;
1447 }
1448
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,SendablePhotoAccessHelperAsyncContext & context)1449 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg,
1450 SendablePhotoAccessHelperAsyncContext &context)
1451 {
1452 for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
1453 string param = iter.first;
1454 bool present = false;
1455 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
1456 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
1457 if (!present) {
1458 continue;
1459 }
1460 napi_value value;
1461 result = napi_get_named_property(env, arg, param.c_str(), &value);
1462 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
1463 napi_valuetype valueType = napi_undefined;
1464 result = napi_typeof(env, value, &valueType);
1465 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
1466 if (valueType == napi_number) {
1467 int32_t number = 0;
1468 result = napi_get_value_int32(env, value, &number);
1469 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
1470 context.valuesBucket.Put(iter.second, number);
1471 } else if (valueType == napi_boolean) {
1472 bool isTrue = false;
1473 result = napi_get_value_bool(env, value, &isTrue);
1474 CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
1475 context.valuesBucket.Put(iter.second, isTrue);
1476 } else if (valueType == napi_string) {
1477 char buffer[ARG_BUF_SIZE];
1478 size_t res = 0;
1479 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
1480 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
1481 context.valuesBucket.Put(iter.second, string(buffer));
1482 } else if (valueType == napi_undefined || valueType == napi_null) {
1483 continue;
1484 } else {
1485 NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
1486 return napi_invalid_arg;
1487 }
1488 }
1489
1490 return CheckCreateOption(context);
1491 }
1492
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1493 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
1494 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1495 {
1496 /* Parse the first argument into displayName */
1497 napi_valuetype valueType;
1498 MediaType mediaType;
1499 string displayName;
1500 NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
1501 napi_ok, "Failed to get displayName");
1502 mediaType = MediaFileUtils::GetMediaType(displayName);
1503 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
1504 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
1505
1506 /* Parse the second argument into albumUri if exists */
1507 string albumUri;
1508 if ((context->argc >= ARGS_TWO)) {
1509 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
1510 if (valueType == napi_string) {
1511 if (SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
1512 albumUri) == napi_ok) {
1513 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
1514 }
1515 } else if (valueType == napi_object) {
1516 NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
1517 "Parse asset create option failed");
1518 }
1519 }
1520
1521 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
1522 NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok,
1523 "Failed to get callback");
1524
1525 napi_value result = nullptr;
1526 NAPI_CALL(env, napi_get_boolean(env, true, &result));
1527 return result;
1528 }
1529
ParseCreateOptions(napi_env env,napi_value arg,SendablePhotoAccessHelperAsyncContext & context)1530 static napi_status ParseCreateOptions(napi_env env, napi_value arg, SendablePhotoAccessHelperAsyncContext &context)
1531 {
1532 for (const auto &iter : CREATE_OPTIONS_PARAM) {
1533 string param = iter.first;
1534 bool present = false;
1535 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
1536 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
1537 if (!present) {
1538 continue;
1539 }
1540 napi_value value;
1541 result = napi_get_named_property(env, arg, param.c_str(), &value);
1542 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
1543 napi_valuetype valueType = napi_undefined;
1544 result = napi_typeof(env, value, &valueType);
1545 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
1546 if (valueType == napi_number) {
1547 int32_t number = 0;
1548 result = napi_get_value_int32(env, value, &number);
1549 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
1550 context.valuesBucket.Put(iter.second, number);
1551 } else if (valueType == napi_boolean) {
1552 bool isTrue = false;
1553 result = napi_get_value_bool(env, value, &isTrue);
1554 CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
1555 context.valuesBucket.Put(iter.second, isTrue);
1556 } else if (valueType == napi_string) {
1557 char buffer[ARG_BUF_SIZE];
1558 size_t res = 0;
1559 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
1560 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
1561 context.valuesBucket.Put(iter.second, string(buffer));
1562 } else if (valueType == napi_undefined || valueType == napi_null) {
1563 continue;
1564 } else {
1565 NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
1566 static_cast<int>(valueType));
1567 return napi_invalid_arg;
1568 }
1569 }
1570
1571 return napi_ok;
1572 }
1573
1574
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1575 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
1576 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1577 {
1578 /* Parse the first argument into displayName */
1579 napi_valuetype valueType;
1580 MediaType mediaType;
1581 int32_t type = 0;
1582 NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
1583 "Failed to get type value");
1584 mediaType = static_cast<MediaType>(type);
1585 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
1586
1587 /* Parse the second argument into albumUri if exists */
1588 string extention;
1589 NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
1590 napi_ok, "Failed to get extention");
1591 context->valuesBucket.Put(ASSET_EXTENTION, extention);
1592
1593 /* Parse the third argument into albumUri if exists */
1594 if (context->argc >= ARGS_THREE) {
1595 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
1596 if (valueType == napi_object) {
1597 NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
1598 "Parse asset create option failed");
1599 } else if (valueType != napi_function) {
1600 NAPI_ERR_LOG("Napi type is wrong in create options");
1601 return nullptr;
1602 }
1603 }
1604
1605 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
1606
1607 napi_value result = nullptr;
1608 NAPI_CALL(env, napi_get_boolean(env, true, &result));
1609 return result;
1610 }
1611
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,SendablePhotoAccessHelperAsyncContext * context)1612 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1613 SendablePhotoAccessHelperAsyncContext *context)
1614 {
1615 bool isValid = false;
1616 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1617 if (!isValid) {
1618 NAPI_ERR_LOG("getting title is invalid");
1619 return;
1620 }
1621 auto fileAsset = make_unique<FileAsset>();
1622 fileAsset->SetId(id);
1623 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1624 fileAsset->SetUri(uri);
1625 fileAsset->SetMediaType(mediaType);
1626 fileAsset->SetDisplayName(displayName);
1627 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1628 fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1629 fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1630 fileAsset->SetUserId(GetUserIdFromSendableContext(context));
1631 context->fileAsset = move(fileAsset);
1632 }
1633
GetCreateUri(SendablePhotoAccessHelperAsyncContext * context,string & uri)1634 static void GetCreateUri(SendablePhotoAccessHelperAsyncContext *context, string &uri)
1635 {
1636 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1637 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1638 switch (context->assetType) {
1639 case TYPE_PHOTO:
1640 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1641 uri = (context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO;
1642 } else {
1643 uri = (context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT :
1644 (context->needSystemApp ? PAH_SYS_CREATE_PHOTO : PAH_CREATE_PHOTO);
1645 }
1646 break;
1647 case TYPE_AUDIO:
1648 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
1649 break;
1650 default:
1651 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
1652 return;
1653 }
1654 SendableMediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1655 } else {
1656 #ifdef MEDIALIBRARY_COMPATIBILITY
1657 bool isValid = false;
1658 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1659 if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
1660 MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1661 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1662 SendableMediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1663 return;
1664 }
1665 switch (context->assetType) {
1666 case TYPE_PHOTO:
1667 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1668 break;
1669 case TYPE_AUDIO:
1670 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1671 break;
1672 case TYPE_DEFAULT:
1673 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1674 break;
1675 default:
1676 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
1677 return;
1678 }
1679 SendableMediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1680 #else
1681 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1682 #endif
1683 }
1684 }
1685
PhotoAccessCreateAssetExecute(napi_env env,void * data)1686 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
1687 {
1688 MediaLibraryTracer tracer;
1689 tracer.Start("JSCreateAssetExecute");
1690
1691 auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
1692 if (!CheckDisplayNameParams(context)) {
1693 context->error = JS_E_DISPLAYNAME;
1694 return;
1695 }
1696
1697 string uri;
1698 GetCreateUri(context, uri);
1699 Uri createFileUri(uri);
1700 string outUri;
1701 int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
1702 if (index < 0) {
1703 context->SaveError(index);
1704 NAPI_ERR_LOG("InsertExt fail, index: %{public}d.", index);
1705 } else {
1706 if (context->isCreateByComponent) {
1707 context->uri = outUri;
1708 } else {
1709 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
1710 }
1711 }
1712 }
1713
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1714 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
1715 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1716 {
1717 constexpr size_t minArgs = ARGS_ONE;
1718 constexpr size_t maxArgs = ARGS_FOUR;
1719 NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
1720 napi_ok, "Failed to get object info");
1721
1722 napi_valuetype valueType;
1723 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
1724 if (valueType == napi_string) {
1725 context->isCreateByComponent = false;
1726 context->needSystemApp = true;
1727 if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
1728 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1729 return nullptr;
1730 }
1731 return ParseArgsCreatePhotoAssetSystem(env, info, context);
1732 } else if (valueType == napi_number) {
1733 context->isCreateByComponent = true;
1734 return ParseArgsCreatePhotoAssetComponent(env, info, context);
1735 } else {
1736 NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
1737 return nullptr;
1738 }
1739 }
1740
JSCreateUriInCallback(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)1741 static void JSCreateUriInCallback(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
1742 unique_ptr<SendableJSAsyncContextOutput> &jsContext)
1743 {
1744 napi_value jsObject = nullptr;
1745 if (context->uri.empty()) {
1746 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1747 "Obtain file asset uri failed");
1748 napi_get_undefined(env, &jsContext->data);
1749 } else {
1750 napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1751 if (status != napi_ok || jsObject == nullptr) {
1752 NAPI_ERR_LOG("Failed to get file asset uri napi object");
1753 napi_get_undefined(env, &jsContext->data);
1754 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1755 "System inner fail");
1756 } else {
1757 jsContext->data = jsObject;
1758 napi_get_undefined(env, &jsContext->error);
1759 jsContext->status = true;
1760 }
1761 }
1762 }
1763
JSCreateAssetInCallback(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)1764 static void JSCreateAssetInCallback(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
1765 unique_ptr<SendableJSAsyncContextOutput> &jsContext)
1766 {
1767 napi_value jsFileAsset = nullptr;
1768 if (context->fileAsset == nullptr) {
1769 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1770 "Obtain file asset failed");
1771 napi_get_undefined(env, &jsContext->data);
1772 } else {
1773 context->fileAsset->SetUserId(GetUserIdFromSendableContext(context));
1774 jsFileAsset = SendableFileAssetNapi::CreateFileAsset(env, context->fileAsset);
1775 if (jsFileAsset == nullptr) {
1776 NAPI_ERR_LOG("Failed to get file asset napi object");
1777 napi_get_undefined(env, &jsContext->data);
1778 SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1779 "System inner fail");
1780 } else {
1781 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1782 jsContext->data = jsFileAsset;
1783 napi_get_undefined(env, &jsContext->error);
1784 jsContext->status = true;
1785 }
1786 }
1787 }
1788
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1789 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1790 {
1791 MediaLibraryTracer tracer;
1792 tracer.Start("JSCreateAssetCompleteCallback");
1793
1794 auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
1795 auto jsContext = make_unique<SendableJSAsyncContextOutput>();
1796 jsContext->status = false;
1797
1798 if (context->error == ERR_DEFAULT) {
1799 if (context->isCreateByComponent) {
1800 JSCreateUriInCallback(env, context, jsContext);
1801 } else {
1802 JSCreateAssetInCallback(env, context, jsContext);
1803 }
1804 } else {
1805 context->HandleError(env, jsContext->error);
1806 napi_get_undefined(env, &jsContext->data);
1807 }
1808
1809 tracer.Finish();
1810 if (context->work != nullptr) {
1811 SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1812 context->work, *jsContext);
1813 }
1814 delete context;
1815 }
1816
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)1817 napi_value SendablePhotoAccessHelper::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
1818 {
1819 MediaLibraryTracer tracer;
1820 tracer.Start("PhotoAccessHelperCreatePhotoAsset");
1821
1822 NAPI_INFO_LOG("enter");
1823
1824 unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1825 make_unique<SendablePhotoAccessHelperAsyncContext>();
1826 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1827 asyncContext->assetType = TYPE_PHOTO;
1828 NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
1829
1830 return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
1831 PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
1832 }
1833
ParseArgsGetBurstAssets(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1834 static napi_value ParseArgsGetBurstAssets(napi_env env, napi_callback_info info,
1835 unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1836 {
1837 constexpr size_t minArgs = ARGS_ONE;
1838 constexpr size_t maxArgs = ARGS_TWO;
1839 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1840 OHOS_INVALID_PARAM_CODE);
1841
1842 /* Parse the first argument */
1843 std::string burstKey;
1844 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], burstKey),
1845 OHOS_INVALID_PARAM_CODE);
1846 if (burstKey.empty()) {
1847 NAPI_ERR_LOG("The input burstkey cannot be empty");
1848 return nullptr;
1849 }
1850 /* Parse the second argument */
1851 CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ASSET_FETCH_OPT,
1852 context), JS_INNER_FAIL);
1853
1854 auto &predicates = context->predicates;
1855 if (context->assetType != TYPE_PHOTO) {
1856 return nullptr;
1857 }
1858 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
1859 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
1860 predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_KEY, burstKey);
1861 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
1862 predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
1863 predicates.OrderByAsc(MediaColumn::MEDIA_NAME);
1864
1865 napi_value result = nullptr;
1866 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1867 return result;
1868 }
1869
PhotoAccessGetBurstAssets(napi_env env,napi_callback_info info)1870 napi_value SendablePhotoAccessHelper::PhotoAccessGetBurstAssets(napi_env env, napi_callback_info info)
1871 {
1872 NAPI_INFO_LOG("PhotoAccessHelper::PhotoAccessGetBurstAssets start");
1873 unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1874 make_unique<SendablePhotoAccessHelperAsyncContext>();
1875 asyncContext->assetType = TYPE_PHOTO;
1876 CHECK_NULLPTR_RET(ParseArgsGetBurstAssets(env, info, asyncContext));
1877
1878 return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
1879 PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
1880 }
1881
PhotoAccessGetSharedPhotoAssets(napi_env env,napi_callback_info info)1882 napi_value SendablePhotoAccessHelper::PhotoAccessGetSharedPhotoAssets(napi_env env, napi_callback_info info)
1883 {
1884 MediaLibraryTracer tracer;
1885 tracer.Start("PhotoAccessGetSharedPhotoAssets");
1886 unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1887 make_unique<SendablePhotoAccessHelperAsyncContext>();
1888 asyncContext->assetType = TYPE_PHOTO;
1889 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext, true));
1890
1891 SendablePhotoAccessHelperAsyncContext* context =
1892 static_cast<SendablePhotoAccessHelperAsyncContext*>((asyncContext.get()));
1893 string queryUri = PAH_QUERY_PHOTO;
1894 SendableMediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1895
1896 Uri uri(queryUri);
1897 shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
1898 context->predicates, context->fetchColumn);
1899 CHECK_NULLPTR_RET(resultSet);
1900
1901 napi_value jsFileArray = 0;
1902 napi_create_array(env, &jsFileArray);
1903
1904 int count = 0;
1905 int err = resultSet->GoToFirstRow();
1906 if (err != napi_ok) {
1907 NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
1908 return jsFileArray;
1909 }
1910 do {
1911 napi_value item = SendableMediaLibraryNapiUtils::GetNextRowObject(env, resultSet);
1912 napi_set_element(env, jsFileArray, count++, item);
1913 } while (!resultSet->GoToNextRow());
1914 resultSet->Close();
1915 return jsFileArray;
1916 }
1917
GetUserId()1918 int32_t SendablePhotoAccessHelper::GetUserId()
1919 {
1920 return userId_;
1921 }
1922
SetUserId(const int32_t & userId)1923 void SendablePhotoAccessHelper::SetUserId(const int32_t &userId)
1924 {
1925 userId_ = userId;
1926 }
1927 } // namespace Media
1928 } // namespace OHOS