1 /*
2 * Copyright (C) 2024-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 "HighlightAlbumNapi"
17
18 #include <unordered_map>
19 #include <unordered_set>
20
21 #include "highlight_album_napi.h"
22 #include "file_asset_napi.h"
23 #include "media_file_utils.h"
24 #include "medialibrary_client_errno.h"
25 #include "medialibrary_napi_log.h"
26 #include "medialibrary_tracer.h"
27 #include "photo_album.h"
28 #include "photo_album_napi.h"
29 #include "photo_map_column.h"
30 #include "result_set_utils.h"
31 #include "userfile_client.h"
32 #include "vision_column.h"
33 #include "story_album_column.h"
34 #include "story_cover_info_column.h"
35 #include "story_play_info_column.h"
36 #include "user_photography_info_column.h"
37
38 using namespace std;
39
40 namespace OHOS::Media {
41 static const string HIGHLIGHT_ALBUM_CLASS = "HighlightAlbum";
42 thread_local napi_ref HighlightAlbumNapi::constructor_ = nullptr;
43
44 using CompleteCallback = napi_async_complete_callback;
45
HighlightAlbumNapi()46 HighlightAlbumNapi::HighlightAlbumNapi() : highlightmEnv_(nullptr) {}
47
48 HighlightAlbumNapi::~HighlightAlbumNapi() = default;
49
Init(napi_env env, napi_value exports)50 napi_value HighlightAlbumNapi::Init(napi_env env, napi_value exports)
51 {
52 NapiClassInfo info = {
53 .name = HIGHLIGHT_ALBUM_CLASS,
54 .ref = &constructor_,
55 .constructor = Constructor,
56 .props = {
57 DECLARE_NAPI_FUNCTION("getHighlightAlbumInfo", JSGetHighlightAlbumInfo),
58 DECLARE_NAPI_FUNCTION("setHighlightUserActionData", JSSetHighlightUserActionData),
59 DECLARE_NAPI_FUNCTION("getHighlightResource", JSGetHighlightResource),
60 } };
61 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
62 return exports;
63 }
64
ParseHighlightAlbum(napi_env env, napi_value arg, shared_ptr<PhotoAlbum>& photoAlbum)65 static napi_value ParseHighlightAlbum(napi_env env, napi_value arg, shared_ptr<PhotoAlbum>& photoAlbum)
66 {
67 napi_valuetype valueType;
68 PhotoAlbumNapi* photoAlbumNapi;
69 CHECK_ARGS(env, napi_typeof(env, arg, &valueType), JS_INNER_FAIL);
70 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
71 CHECK_ARGS(env, napi_unwrap(env, arg, reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
72 CHECK_COND_WITH_MESSAGE(env, photoAlbumNapi != nullptr, "Failed to get PhotoAlbumNapi object");
73
74 auto photoAlbumPtr = photoAlbumNapi->GetPhotoAlbumInstance();
75 CHECK_COND_WITH_MESSAGE(env, photoAlbumPtr != nullptr, "photoAlbum is null");
76 CHECK_COND_WITH_MESSAGE(env,
77 photoAlbumPtr->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER &&
78 PhotoAlbum::CheckPhotoAlbumType(photoAlbumPtr->GetPhotoAlbumType()) &&
79 PhotoAlbum::CheckPhotoAlbumSubType(photoAlbumPtr->GetPhotoAlbumSubType()),
80 "Unsupported type of photoAlbum");
81 photoAlbum = photoAlbumPtr;
82 RETURN_NAPI_TRUE(env);
83 }
84
Constructor(napi_env env, napi_callback_info info)85 napi_value HighlightAlbumNapi::Constructor(napi_env env, napi_callback_info info)
86 {
87 napi_value newTarget = nullptr;
88 CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
89 CHECK_COND_RET(newTarget != nullptr, nullptr, "Failed to check new.target");
90
91 size_t argc = ARGS_ONE;
92 napi_value argv[ARGS_ONE] = { 0 };
93 napi_value thisVar = nullptr;
94 shared_ptr<PhotoAlbum> photoAlbum = nullptr;
95 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
96 CHECK_COND_WITH_MESSAGE(env, argc == ARGS_ONE, "Number of args is invalid");
97 CHECK_COND_WITH_MESSAGE(env, ParseHighlightAlbum(env, argv[PARAM0], photoAlbum), "Failed to parse album");
98
99 unique_ptr<HighlightAlbumNapi> obj = make_unique<HighlightAlbumNapi>();
100 CHECK_COND(env, obj != nullptr, JS_INNER_FAIL);
101 obj->highlightAlbumPtr = photoAlbum;
102 obj->highlightmEnv_ = env;
103 CHECK_ARGS(env,
104 napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), HighlightAlbumNapi::Destructor, nullptr,
105 nullptr),
106 JS_INNER_FAIL);
107 obj.release();
108 return thisVar;
109 }
110
Destructor(napi_env env, void* nativeObject, void* finalizeHint)111 void HighlightAlbumNapi::Destructor(napi_env env, void* nativeObject, void* finalizeHint)
112 {
113 auto* hightlihgtAlbum = reinterpret_cast<HighlightAlbumNapi*>(nativeObject);
114 if (hightlihgtAlbum != nullptr) {
115 delete hightlihgtAlbum;
116 hightlihgtAlbum = nullptr;
117 }
118 }
119
120 static const map<int32_t, struct HighlightAlbumInfo> HIGHLIGHT_ALBUM_INFO_MAP = {
121 { COVER_INFO, { PAH_QUERY_HIGHLIGHT_COVER, { ID, HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
122 AI_ALBUM_ID, SUB_TITLE, CLUSTER_TYPE, CLUSTER_SUB_TYPE,
123 CLUSTER_CONDITION, MIN_DATE_ADDED, MAX_DATE_ADDED, GENERATE_TIME, HIGHLIGHT_VERSION,
124 REMARKS, HIGHLIGHT_STATUS, RATIO, BACKGROUND, FOREGROUND, WORDART, IS_COVERED, COLOR,
125 RADIUS, SATURATION, BRIGHTNESS, BACKGROUND_COLOR_TYPE, SHADOW_LEVEL, TITLE_SCALE_X,
126 TITLE_SCALE_Y, TITLE_RECT_WIDTH, TITLE_RECT_HEIGHT, BACKGROUND_SCALE_X, BACKGROUND_SCALE_Y,
127 BACKGROUND_RECT_WIDTH, BACKGROUND_RECT_HEIGHT, LAYOUT_INDEX, COVER_ALGO_VERSION, COVER_KEY,
128 HIGHLIGHT_IS_MUTED, HIGHLIGHT_IS_FAVORITE, HIGHLIGHT_THEME } } },
129 { PLAY_INFO, { PAH_QUERY_HIGHLIGHT_PLAY, { ID, HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
130 MUSIC, FILTER, HIGHLIGHT_PLAY_INFO, IS_CHOSEN, PLAY_INFO_VERSION, PLAY_INFO_ID } } },
131 };
132
133 static const map<int32_t, std::string> HIGHLIGHT_USER_ACTION_MAP = {
134 { INSERTED_PIC_COUNT, HIGHLIGHT_INSERT_PIC_COUNT },
135 { REMOVED_PIC_COUNT, HIGHLIGHT_REMOVE_PIC_COUNT },
136 { SHARED_SCREENSHOT_COUNT, HIGHLIGHT_SHARE_SCREENSHOT_COUNT },
137 { SHARED_COVER_COUNT, HIGHLIGHT_SHARE_COVER_COUNT },
138 { RENAMED_COUNT, HIGHLIGHT_RENAME_COUNT },
139 { CHANGED_COVER_COUNT, HIGHLIGHT_CHANGE_COVER_COUNT },
140 { RENDER_VIEWED_TIMES, HIGHLIGHT_RENDER_VIEWED_TIMES },
141 { RENDER_VIEWED_DURATION, HIGHLIGHT_RENDER_VIEWED_DURATION },
142 { ART_LAYOUT_VIEWED_TIMES, HIGHLIGHT_ART_LAYOUT_VIEWED_TIMES },
143 { ART_LAYOUT_VIEWED_DURATION, HIGHLIGHT_ART_LAYOUT_VIEWED_DURATION },
144 };
145
JSGetHighlightAlbumInfoExecute(napi_env env, void *data)146 static void JSGetHighlightAlbumInfoExecute(napi_env env, void *data)
147 {
148 MediaLibraryTracer tracer;
149 tracer.Start("JSGetHighlightAlbumInfoExecute");
150
151 auto *context = static_cast<HighlightAlbumNapiAsyncContext*>(data);
152 string uriStr;
153 std::vector<std::string> fetchColumn;
154 DataShare::DataSharePredicates predicates;
155 if (HIGHLIGHT_ALBUM_INFO_MAP.find(context->highlightAlbumInfoType) != HIGHLIGHT_ALBUM_INFO_MAP.end()) {
156 uriStr = HIGHLIGHT_ALBUM_INFO_MAP.at(context->highlightAlbumInfoType).uriStr;
157 fetchColumn = HIGHLIGHT_ALBUM_INFO_MAP.at(context->highlightAlbumInfoType).fetchColumn;
158 string tabStr;
159 if (context->highlightAlbumInfoType == COVER_INFO) {
160 tabStr = HIGHLIGHT_COVER_INFO_TABLE;
161 } else {
162 tabStr = HIGHLIGHT_PLAY_INFO_TABLE;
163 }
164 vector<string> onClause = {
165 tabStr + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
166 HIGHLIGHT_ALBUM_TABLE + "." + ID
167 };
168 predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
169 } else {
170 NAPI_ERR_LOG("Invalid highlightAlbumInfoType");
171 return;
172 }
173 auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
174 CHECK_NULL_PTR_RETURN_VOID(photoAlbum, "photoAlbum is null");
175 int albumId = photoAlbum->GetAlbumId();
176 int subType = photoAlbum->GetPhotoAlbumSubType();
177 Uri uri (uriStr);
178 if (subType == PhotoAlbumSubType::HIGHLIGHT) {
179 predicates.EqualTo(HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID, to_string(albumId));
180 } else if (subType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
181 predicates.EqualTo(HIGHLIGHT_ALBUM_TABLE + "." + AI_ALBUM_ID, to_string(albumId));
182 } else {
183 NAPI_ERR_LOG("Invalid highlight album subType");
184 return;
185 }
186 int errCode = 0;
187 auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
188 if (resultSet != nullptr) {
189 context->highlightAlbumInfo = MediaLibraryNapiUtils::ParseResultSet2JsonStr(resultSet, fetchColumn);
190 }
191 }
192
JSGetHighlightAlbumInfoCompleteCallback(napi_env env, napi_status status, void *data)193 static void JSGetHighlightAlbumInfoCompleteCallback(napi_env env, napi_status status, void *data)
194 {
195 MediaLibraryTracer tracer;
196 tracer.Start("JSGetHighlightAlbumInfoCompleteCallback");
197
198 auto *context = static_cast<HighlightAlbumNapiAsyncContext *>(data);
199 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
200
201 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
202 jsContext->status = false;
203
204 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
205 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
206 if (context->error == ERR_DEFAULT) {
207 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, context->highlightAlbumInfo.c_str(),
208 NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
209 jsContext->status = true;
210 } else {
211 context->HandleError(env, jsContext->error);
212 }
213
214 tracer.Finish();
215 if (context->work != nullptr) {
216 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
217 context->work, *jsContext);
218 }
219 delete context;
220 }
221
JSSetHighlightUserActionDataExecute(napi_env env, void *data)222 static void JSSetHighlightUserActionDataExecute(napi_env env, void *data)
223 {
224 MediaLibraryTracer tracer;
225 tracer.Start("JSSetHighlightUserActionDataExecute");
226
227 auto *context = static_cast<HighlightAlbumNapiAsyncContext*>(data);
228 string userActionType;
229 if (HIGHLIGHT_USER_ACTION_MAP.find(context->highlightUserActionType) != HIGHLIGHT_USER_ACTION_MAP.end()) {
230 userActionType = HIGHLIGHT_USER_ACTION_MAP.at(context->highlightUserActionType);
231 context->fetchColumn.push_back(userActionType);
232 } else {
233 NAPI_ERR_LOG("Invalid highlightUserActionType");
234 return;
235 }
236 int albumId = context->objectInfo->GetPhotoAlbumInstance()->GetAlbumId();
237 Uri uri(URI_HIGHLIGHT_ALBUM);
238 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(albumId));
239 int errCode = 0;
240 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
241 if (resultSet != nullptr) {
242 auto count = 0;
243 auto ret = resultSet->GetRowCount(count);
244 if (ret != NativeRdb::E_OK || count == 0 || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
245 NAPI_ERR_LOG("highlight user action data get rdbstore failed");
246 context->error = JS_INNER_FAIL;
247 return;
248 }
249 int64_t userActionDataCount = get<int64_t>(ResultSetUtils::GetValFromColumn(userActionType,
250 resultSet, TYPE_INT64));
251 context->valuesBucket.Put(userActionType, to_string(userActionDataCount + context->actionData));
252 int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
253 context->SaveError(changedRows);
254 context->changedRows = changedRows;
255 } else {
256 NAPI_ERR_LOG("highlight user action data resultSet is null");
257 context->error = JS_INNER_FAIL;
258 return;
259 }
260 }
261
JSSetHighlightUserActionDataCompleteCallback(napi_env env, napi_status status, void *data)262 static void JSSetHighlightUserActionDataCompleteCallback(napi_env env, napi_status status, void *data)
263 {
264 MediaLibraryTracer tracer;
265 tracer.Start("JSSetHighlightUserActionDataCompleteCallback");
266
267 auto *context = static_cast<HighlightAlbumNapiAsyncContext*>(data);
268 auto jsContext = make_unique<JSAsyncContextOutput>();
269 jsContext->status = false;
270 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
271 if (context->error == ERR_DEFAULT) {
272 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
273 jsContext->status = true;
274 } else {
275 context->HandleError(env, jsContext->error);
276 }
277
278 tracer.Finish();
279 if (context->work != nullptr) {
280 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
281 context->work, *jsContext);
282 }
283 delete context;
284 }
285
GetFdForArrayBuffer(std::string uriStr)286 static int32_t GetFdForArrayBuffer(std::string uriStr)
287 {
288 int32_t fd = 0;
289 Uri uri(uriStr);
290 fd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
291 if (fd == E_ERR) {
292 NAPI_ERR_LOG("Open highlight cover file failed, error: %{public}d", errno);
293 return E_HAS_FS_ERROR;
294 } else if (fd < 0) {
295 NAPI_ERR_LOG("Open highlight cover file failed due to OpenFile failure");
296 return fd;
297 }
298 return fd;
299 }
300
JSGetHighlightResourceExecute(napi_env env, void *data)301 static void JSGetHighlightResourceExecute(napi_env env, void *data)
302 {
303 MediaLibraryTracer tracer;
304 tracer.Start("JSGetHighlightResourceExecute");
305
306 auto *context = static_cast<HighlightAlbumNapiAsyncContext*>(data);
307 if (context->resourceUri.find(MEDIA_DATA_DB_HIGHLIGHT) == string::npos) {
308 NAPI_ERR_LOG("Invalid highlight resource uri");
309 return;
310 }
311
312 int32_t fd = GetFdForArrayBuffer(context->resourceUri);
313 if (fd < 0) {
314 return;
315 }
316 UniqueFd uniqueFd(fd);
317 off_t fileLen = lseek(uniqueFd.Get(), 0, SEEK_END);
318 if (fileLen < 0) {
319 NAPI_ERR_LOG("Failed to get highlight cover file length, error: %{public}d", errno);
320 return;
321 }
322 off_t ret = lseek(uniqueFd.Get(), 0, SEEK_SET);
323 if (ret < 0) {
324 NAPI_ERR_LOG("Failed to reset highlight cover file offset, error: %{public}d", errno);
325 return;
326 }
327 void* arrayBufferData = nullptr;
328 napi_value arrayBuffer;
329 if (napi_create_arraybuffer(env, fileLen, &arrayBufferData, &arrayBuffer) != napi_ok) {
330 NAPI_ERR_LOG("failed to create napi arraybuffer");
331 return;
332 }
333
334 ssize_t readBytes = read(uniqueFd.Get(), arrayBufferData, fileLen);
335 if (readBytes != fileLen) {
336 NAPI_ERR_LOG("read file failed, read bytes is %{public}zu,""actual length is %{public}" PRId64
337 ",error: %{public}d", readBytes, fileLen, errno);
338 return;
339 }
340 context->napiArrayBuffer = arrayBuffer;
341 }
342
JSGetHighlightResourceCompleteCallback(napi_env env, napi_status status, void *data)343 static void JSGetHighlightResourceCompleteCallback(napi_env env, napi_status status, void *data)
344 {
345 MediaLibraryTracer tracer;
346 tracer.Start("JSGetHighlightResourceCompleteCallback");
347
348 auto *context = static_cast<HighlightAlbumNapiAsyncContext *>(data);
349 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
350
351 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
352 jsContext->status = false;
353
354 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
355 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
356 if (context->error == ERR_DEFAULT) {
357 jsContext->data = context->napiArrayBuffer;
358 jsContext->status = true;
359 } else {
360 context->HandleError(env, jsContext->error);
361 }
362
363 tracer.Finish();
364 if (context->work != nullptr) {
365 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
366 context->work, *jsContext);
367 }
368 delete context;
369 }
370
JSGetHighlightAlbumInfo(napi_env env, napi_callback_info info)371 napi_value HighlightAlbumNapi::JSGetHighlightAlbumInfo(napi_env env, napi_callback_info info)
372 {
373 MediaLibraryTracer tracer;
374 tracer.Start("JSGetHighlightAlbumInfo");
375
376 napi_value result = nullptr;
377 NAPI_CALL(env, napi_get_undefined(env, &result));
378 unique_ptr<HighlightAlbumNapiAsyncContext> asyncContext = make_unique<HighlightAlbumNapiAsyncContext>();
379 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
380 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext,
381 asyncContext->highlightAlbumInfoType), JS_ERR_PARAMETER_INVALID);
382
383 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
384 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
385 CHECK_COND_WITH_MESSAGE(env,
386 PhotoAlbum::IsHighlightAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
387 "Only and smart highlight album can get highlight album info");
388
389 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
390 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetHighlightAlbumInfo",
391 JSGetHighlightAlbumInfoExecute, JSGetHighlightAlbumInfoCompleteCallback);
392 }
393
JSSetHighlightUserActionData(napi_env env, napi_callback_info info)394 napi_value HighlightAlbumNapi::JSSetHighlightUserActionData(napi_env env, napi_callback_info info)
395 {
396 MediaLibraryTracer tracer;
397 tracer.Start("JSSetHighlightUserActionData");
398
399 napi_value result = nullptr;
400 NAPI_CALL(env, napi_get_undefined(env, &result));
401 unique_ptr<HighlightAlbumNapiAsyncContext> asyncContext = make_unique<HighlightAlbumNapiAsyncContext>();
402 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
403
404 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext,
405 asyncContext->highlightUserActionType), JS_ERR_PARAMETER_INVALID);
406 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[1], asyncContext->actionData));
407
408 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
409 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
410 CHECK_COND_WITH_MESSAGE(env,
411 PhotoAlbum::IsHighlightAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
412 "Only and smart highlight album can set user action info");
413
414 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
415 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSSetHighlightUserActionData",
416 JSSetHighlightUserActionDataExecute, JSSetHighlightUserActionDataCompleteCallback);
417 }
418
JSGetHighlightResource(napi_env env, napi_callback_info info)419 napi_value HighlightAlbumNapi::JSGetHighlightResource(napi_env env, napi_callback_info info)
420 {
421 MediaLibraryTracer tracer;
422 tracer.Start("JSGetHighlightResource");
423
424 napi_value result = nullptr;
425 NAPI_CALL(env, napi_get_undefined(env, &result));
426 unique_ptr<HighlightAlbumNapiAsyncContext> asyncContext = make_unique<HighlightAlbumNapiAsyncContext>();
427 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
428
429 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->resourceUri),
430 JS_ERR_PARAMETER_INVALID);
431
432 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
433 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
434 CHECK_COND_WITH_MESSAGE(env,
435 PhotoAlbum::IsHighlightAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
436 "Only and smart highlight album can set user action info");
437
438 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
439 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetHighlightResource",
440 JSGetHighlightResourceExecute, JSGetHighlightResourceCompleteCallback);
441 }
442
GetPhotoAlbumInstance() const443 shared_ptr<PhotoAlbum> HighlightAlbumNapi::GetPhotoAlbumInstance() const
444 {
445 return highlightAlbumPtr;
446 }
447 } // namespace OHOS::Media