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