1 /*
2 * Copyright (C) 2023 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 "MediaAssetManagerNapi"
17
18 #include "media_asset_manager_napi.h"
19
20 #include <fcntl.h>
21 #include <string>
22 #include <sys/sendfile.h>
23 #include <unordered_map>
24 #include <uuid/uuid.h>
25
26 #include "access_token.h"
27 #include "accesstoken_kit.h"
28 #include "dataobs_mgr_client.h"
29 #include "directory_ex.h"
30 #include "file_asset_napi.h"
31 #include "file_uri.h"
32 #include "image_source.h"
33 #include "image_source_napi.h"
34 #include "ipc_skeleton.h"
35 #include "media_column.h"
36 #include "media_file_utils.h"
37 #include "media_file_uri.h"
38 #include "medialibrary_client_errno.h"
39 #include "media_library_napi.h"
40 #include "medialibrary_errno.h"
41 #include "medialibrary_napi_log.h"
42 #include "medialibrary_napi_utils.h"
43 #include "medialibrary_napi_utils_ext.h"
44 #include "medialibrary_tracer.h"
45 #include "moving_photo_napi.h"
46 #include "permission_utils.h"
47 #include "picture_handle_client.h"
48 #include "ui_extension_context.h"
49 #include "userfile_client.h"
50 #include "media_call_transcode.h"
51
52 using namespace OHOS::Security::AccessToken;
53
54 namespace OHOS {
55 namespace Media {
56 static const std::string MEDIA_ASSET_MANAGER_CLASS = "MediaAssetManager";
57 static std::mutex multiStagesCaptureLock;
58 static std::mutex registerTaskLock;
59
60 const int32_t LOW_QUALITY_IMAGE = 1;
61 const int32_t HIGH_QUALITY_IMAGE = 0;
62
63 const int32_t UUID_STR_LENGTH = 37;
64 const int32_t MAX_URI_SIZE = 384; // 256 for display name and 128 for relative path
65 const int32_t REQUEST_ID_MAX_LEN = 64;
66
67 thread_local unique_ptr<ChangeListenerNapi> g_multiStagesRequestListObj = nullptr;
68 thread_local napi_ref constructor_ = nullptr;
69
70 static std::map<std::string, std::shared_ptr<MultiStagesTaskObserver>> multiStagesObserverMap;
71 static std::map<std::string, std::map<std::string, AssetHandler*>> inProcessUriMap;
72 static SafeMap<std::string, AssetHandler*> inProcessFastRequests;
73 static SafeMap<std::string, AssetHandler*> onPreparedResult_;
74 static SafeMap<std::string, napi_value> onPreparedResultValue_;
75 static SafeMap<std::string, bool> isTranscoderMap_;
76
Init(napi_env env, napi_value exports)77 napi_value MediaAssetManagerNapi::Init(napi_env env, napi_value exports)
78 {
79 NapiClassInfo info = {.name = MEDIA_ASSET_MANAGER_CLASS,
80 .ref = &constructor_,
81 .constructor = Constructor,
82 .props = {
83 DECLARE_NAPI_STATIC_FUNCTION("requestImage", JSRequestImage),
84 DECLARE_NAPI_STATIC_FUNCTION("requestImageData", JSRequestImageData),
85 DECLARE_NAPI_STATIC_FUNCTION("requestMovingPhoto", JSRequestMovingPhoto),
86 DECLARE_NAPI_STATIC_FUNCTION("requestVideoFile", JSRequestVideoFile),
87 DECLARE_NAPI_STATIC_FUNCTION("cancelRequest", JSCancelRequest),
88 DECLARE_NAPI_STATIC_FUNCTION("loadMovingPhoto", JSLoadMovingPhoto),
89 DECLARE_NAPI_STATIC_FUNCTION("quickRequestImage", JSRequestEfficientIImage)
90 }};
91 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
92 return exports;
93 }
94
Constructor(napi_env env, napi_callback_info info)95 napi_value MediaAssetManagerNapi::Constructor(napi_env env, napi_callback_info info)
96 {
97 napi_value newTarget = nullptr;
98 CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
99 bool isConstructor = newTarget != nullptr;
100 if (isConstructor) {
101 napi_value thisVar = nullptr;
102 unique_ptr<MediaAssetManagerNapi> obj = make_unique<MediaAssetManagerNapi>();
103 CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "Create MediaAssetManagerNapi failed");
104 CHECK_ARGS(env,
105 napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), MediaAssetManagerNapi::Destructor,
106 nullptr, nullptr),
107 JS_INNER_FAIL);
108 obj.release();
109 return thisVar;
110 }
111 napi_value constructor = nullptr;
112 napi_value result = nullptr;
113 NAPI_CALL(env, napi_get_reference_value(env, constructor_, &constructor));
114 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
115 return result;
116 }
117
Destructor(napi_env env, void *nativeObject, void *finalizeHint)118 void MediaAssetManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
119 {
120 auto* mediaAssetManager = reinterpret_cast<MediaAssetManagerNapi*>(nativeObject);
121 if (mediaAssetManager != nullptr) {
122 delete mediaAssetManager;
123 mediaAssetManager = nullptr;
124 }
125 }
126
HasReadPermission()127 static bool HasReadPermission()
128 {
129 AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
130 int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_READ_IMAGEVIDEO);
131 return result == PermissionState::PERMISSION_GRANTED;
132 }
133
CreateAssetHandler(const std::string &photoId, const std::string &requestId, const std::string &uri, const MediaAssetDataHandlerPtr &handler, napi_threadsafe_function func)134 static AssetHandler* CreateAssetHandler(const std::string &photoId, const std::string &requestId,
135 const std::string &uri, const MediaAssetDataHandlerPtr &handler, napi_threadsafe_function func)
136 {
137 AssetHandler *assetHandler = new AssetHandler(photoId, requestId, uri, handler, func);
138 NAPI_DEBUG_LOG("[AssetHandler create] photoId: %{public}s, requestId: %{public}s, uri: %{public}s, %{public}p.",
139 photoId.c_str(), requestId.c_str(), uri.c_str(), assetHandler);
140 return assetHandler;
141 }
142
DeleteAssetHandlerSafe(AssetHandler *handler, napi_env env)143 static void DeleteAssetHandlerSafe(AssetHandler *handler, napi_env env)
144 {
145 if (handler != nullptr) {
146 NAPI_DEBUG_LOG("[AssetHandler delete] %{public}p.", handler);
147 if (handler->dataHandler != nullptr) {
148 handler->dataHandler->DeleteNapiReference(env);
149 }
150 delete handler;
151 handler = nullptr;
152 }
153 }
154
DeleteProcessHandlerSafe(ProgressHandler *handler, napi_env env)155 static void DeleteProcessHandlerSafe(ProgressHandler *handler, napi_env env)
156 {
157 if (handler == nullptr) {
158 return;
159 }
160 NAPI_DEBUG_LOG("[ProgressHandler delete] %{public}p.", handler);
161 if (handler->progressRef != nullptr && env != nullptr) {
162 napi_delete_reference(env, handler->progressRef);
163 handler->progressRef = nullptr;
164 }
165 delete handler;
166 handler = nullptr;
167 }
168
InsertInProcessMapRecord(const std::string &requestUri, const std::string &requestId, AssetHandler *handler)169 static void InsertInProcessMapRecord(const std::string &requestUri, const std::string &requestId,
170 AssetHandler *handler)
171 {
172 std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
173 std::map<std::string, AssetHandler*> assetHandler;
174 auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
175 if (inProcessUriMap.find(uriLocal) != inProcessUriMap.end()) {
176 assetHandler = inProcessUriMap[uriLocal];
177 assetHandler[requestId] = handler;
178 inProcessUriMap[uriLocal] = assetHandler;
179 } else {
180 assetHandler[requestId] = handler;
181 inProcessUriMap[uriLocal] = assetHandler;
182 }
183 }
184
DeleteInProcessMapRecord(const std::string &requestUri, const std::string &requestId)185 static void DeleteInProcessMapRecord(const std::string &requestUri, const std::string &requestId)
186 {
187 std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
188 auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
189 if (inProcessUriMap.find(uriLocal) == inProcessUriMap.end()) {
190 return;
191 }
192
193 std::map<std::string, AssetHandler*> assetHandlers = inProcessUriMap[uriLocal];
194 if (assetHandlers.find(requestId) == assetHandlers.end()) {
195 return;
196 }
197
198 assetHandlers.erase(requestId);
199 if (!assetHandlers.empty()) {
200 inProcessUriMap[uriLocal] = assetHandlers;
201 return;
202 }
203
204 inProcessUriMap.erase(uriLocal);
205
206 if (multiStagesObserverMap.find(uriLocal) != multiStagesObserverMap.end()) {
207 UserFileClient::UnregisterObserverExt(Uri(uriLocal),
208 static_cast<std::shared_ptr<DataShare::DataShareObserver>>(multiStagesObserverMap[uriLocal]));
209 }
210 multiStagesObserverMap.erase(uriLocal);
211 }
212
IsInProcessInMapRecord(const std::string &requestId, AssetHandler* &handler)213 static int32_t IsInProcessInMapRecord(const std::string &requestId, AssetHandler* &handler)
214 {
215 std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
216 for (auto record : inProcessUriMap) {
217 if (record.second.find(requestId) != record.second.end()) {
218 handler = record.second[requestId];
219 return true;
220 }
221 }
222
223 return false;
224 }
225
InsertDataHandler(NotifyMode notifyMode, napi_env env, MediaAssetManagerAsyncContext *asyncContext)226 static AssetHandler* InsertDataHandler(NotifyMode notifyMode, napi_env env,
227 MediaAssetManagerAsyncContext *asyncContext)
228 {
229 napi_ref dataHandlerRef;
230 napi_threadsafe_function threadSafeFunc;
231 if (notifyMode == NotifyMode::FAST_NOTIFY) {
232 dataHandlerRef = asyncContext->dataHandlerRef;
233 asyncContext->dataHandlerRef = nullptr;
234 threadSafeFunc = asyncContext->onDataPreparedPtr;
235 } else {
236 dataHandlerRef = asyncContext->dataHandlerRef2;
237 asyncContext->dataHandlerRef2 = nullptr;
238 threadSafeFunc = asyncContext->onDataPreparedPtr2;
239 }
240 std::shared_ptr<NapiMediaAssetDataHandler> mediaAssetDataHandler = make_shared<NapiMediaAssetDataHandler>(
241 env, dataHandlerRef, asyncContext->returnDataType, asyncContext->photoUri, asyncContext->destUri,
242 asyncContext->sourceMode);
243 mediaAssetDataHandler->SetCompatibleMode(asyncContext->compatibleMode);
244 mediaAssetDataHandler->SetNotifyMode(notifyMode);
245 mediaAssetDataHandler->SetRequestId(asyncContext->requestId);
246
247 AssetHandler *assetHandler = CreateAssetHandler(asyncContext->photoId, asyncContext->requestId,
248 asyncContext->photoUri, mediaAssetDataHandler, threadSafeFunc);
249 assetHandler->photoQuality = asyncContext->photoQuality;
250 assetHandler->needsExtraInfo = asyncContext->needsExtraInfo;
251 NAPI_INFO_LOG("Add %{public}d, %{public}s, %{public}s, %{public}p", notifyMode, asyncContext->photoUri.c_str(),
252 asyncContext->requestId.c_str(), assetHandler);
253
254 switch (notifyMode) {
255 case NotifyMode::FAST_NOTIFY: {
256 inProcessFastRequests.EnsureInsert(asyncContext->requestId, assetHandler);
257 break;
258 }
259 case NotifyMode::WAIT_FOR_HIGH_QUALITY: {
260 InsertInProcessMapRecord(asyncContext->photoUri, asyncContext->requestId, assetHandler);
261 break;
262 }
263 default:
264 break;
265 }
266
267 return assetHandler;
268 }
269
InsertProgressHandler(napi_env env, MediaAssetManagerAsyncContext *asyncContext)270 static ProgressHandler* InsertProgressHandler(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
271 {
272 napi_ref dataHandlerRef;
273 napi_threadsafe_function threadSafeFunc;
274 dataHandlerRef = asyncContext->progressHandlerRef;
275 threadSafeFunc = asyncContext->onProgressPtr;
276 RetProgressValue retProgressValue;
277 ProgressHandler *progressHandler = new ProgressHandler(env, threadSafeFunc, asyncContext->requestId,
278 retProgressValue, dataHandlerRef);
279 MediaAssetManagerNapi::progressHandlerMap_.EnsureInsert(asyncContext->requestId, progressHandler);
280 NAPI_INFO_LOG("InsertProgressHandler %{public}p", progressHandler);
281 return progressHandler;
282 }
283
DeleteDataHandler(NotifyMode notifyMode, const std::string &requestUri, const std::string &requestId)284 static void DeleteDataHandler(NotifyMode notifyMode, const std::string &requestUri, const std::string &requestId)
285 {
286 auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
287 NAPI_INFO_LOG("Rmv %{public}d, %{public}s, %{public}s", notifyMode, requestUri.c_str(), requestId.c_str());
288 if (notifyMode == NotifyMode::WAIT_FOR_HIGH_QUALITY) {
289 DeleteInProcessMapRecord(uriLocal, requestId);
290 }
291 inProcessFastRequests.Erase(requestId);
292 }
293
QueryPhotoStatus(int fileId, const string& photoUri, std::string &photoId, bool hasReadPermission)294 MultiStagesCapturePhotoStatus MediaAssetManagerNapi::QueryPhotoStatus(int fileId,
295 const string& photoUri, std::string &photoId, bool hasReadPermission)
296 {
297 photoId = "";
298 DataShare::DataSharePredicates predicates;
299 predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
300 std::vector<std::string> fetchColumn { PhotoColumn::PHOTO_QUALITY, PhotoColumn::PHOTO_ID};
301 string queryUri;
302 if (hasReadPermission) {
303 queryUri = PAH_QUERY_PHOTO;
304 } else {
305 queryUri = photoUri;
306 MediaFileUri::RemoveAllFragment(queryUri);
307 }
308 Uri uri(queryUri);
309 int errCode = 0;
310 auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
311 if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
312 NAPI_ERR_LOG("query resultSet is nullptr");
313 return MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
314 }
315 int indexOfPhotoId = -1;
316 resultSet->GetColumnIndex(PhotoColumn::PHOTO_ID, indexOfPhotoId);
317 resultSet->GetString(indexOfPhotoId, photoId);
318
319 int columnIndexQuality = -1;
320 resultSet->GetColumnIndex(PhotoColumn::PHOTO_QUALITY, columnIndexQuality);
321 int currentPhotoQuality = HIGH_QUALITY_IMAGE;
322 resultSet->GetInt(columnIndexQuality, currentPhotoQuality);
323 if (currentPhotoQuality == LOW_QUALITY_IMAGE) {
324 NAPI_DEBUG_LOG("query photo status : lowQuality");
325 return MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS;
326 }
327 NAPI_DEBUG_LOG("query photo status quality: %{public}d", currentPhotoQuality);
328 return MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
329 }
330
ProcessImage(const int fileId, const int deliveryMode)331 void MediaAssetManagerNapi::ProcessImage(const int fileId, const int deliveryMode)
332 {
333 std::string uriStr = PAH_PROCESS_IMAGE;
334 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
335 Uri uri(uriStr);
336 DataShare::DataSharePredicates predicates;
337 int errCode = 0;
338 std::vector<std::string> columns { std::to_string(fileId), std::to_string(deliveryMode) };
339 UserFileClient::Query(uri, predicates, columns, errCode);
340 }
341
CancelProcessImage(const std::string &photoId)342 void MediaAssetManagerNapi::CancelProcessImage(const std::string &photoId)
343 {
344 std::string uriStr = PAH_CANCEL_PROCESS_IMAGE;
345 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
346 Uri uri(uriStr);
347 DataShare::DataSharePredicates predicates;
348 int errCode = 0;
349 std::vector<std::string> columns { photoId };
350 UserFileClient::Query(uri, predicates, columns, errCode);
351 }
352
AddImage(const int fileId, DeliveryMode deliveryMode)353 void MediaAssetManagerNapi::AddImage(const int fileId, DeliveryMode deliveryMode)
354 {
355 Uri updateAssetUri(PAH_ADD_IMAGE);
356 DataShare::DataSharePredicates predicates;
357 DataShare::DataShareValuesBucket valuesBucket;
358 valuesBucket.Put(MediaColumn::MEDIA_ID, fileId);
359 valuesBucket.Put("deliveryMode", static_cast<int>(deliveryMode));
360 UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
361 }
362
GetDeliveryMode(napi_env env, const napi_value arg, const string &propName, DeliveryMode& deliveryMode)363 napi_status GetDeliveryMode(napi_env env, const napi_value arg, const string &propName,
364 DeliveryMode& deliveryMode)
365 {
366 bool present = false;
367 napi_value property = nullptr;
368 int mode = -1;
369 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present),
370 "Failed to check property name");
371 if (!present) {
372 NAPI_ERR_LOG("No delivery mode specified");
373 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "No delivery mode specified");
374 return napi_invalid_arg;
375 }
376 CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
377 CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse deliveryMode argument value");
378
379 // delivery mode's valid range is 0 - 2
380 if (mode < 0 || mode > 2) {
381 NAPI_ERR_LOG("delivery mode invalid argument ");
382 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid delivery mode value");
383 return napi_invalid_arg;
384 }
385 deliveryMode = static_cast<DeliveryMode>(mode);
386 return napi_ok;
387 }
388
GetSourceMode(napi_env env, const napi_value arg, const string &propName, SourceMode& sourceMode)389 napi_status GetSourceMode(napi_env env, const napi_value arg, const string &propName,
390 SourceMode& sourceMode)
391 {
392 bool present = false;
393 napi_value property = nullptr;
394 int mode = -1;
395 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
396 if (!present) {
397 // use default source mode
398 sourceMode = SourceMode::EDITED_MODE;
399 return napi_ok;
400 } else if (!MediaLibraryNapiUtils::IsSystemApp()) {
401 NAPI_ERR_LOG("Source mode is only available to system apps");
402 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Source mode is only available to system apps");
403 return napi_invalid_arg;
404 }
405 CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
406 CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse sourceMode argument value");
407
408 // source mode's valid range is 0 - 1
409 if (mode < 0 || mode > 1) {
410 NAPI_ERR_LOG("source mode invalid");
411 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid source mode value");
412 return napi_invalid_arg;
413 }
414 sourceMode = static_cast<SourceMode>(mode);
415 return napi_ok;
416 }
417
ParseArgGetRequestOption(napi_env env, napi_value arg, DeliveryMode &deliveryMode, SourceMode &sourceMode)418 napi_status ParseArgGetRequestOption(napi_env env, napi_value arg, DeliveryMode &deliveryMode, SourceMode &sourceMode)
419 {
420 CHECK_STATUS_RET(GetDeliveryMode(env, arg, "deliveryMode", deliveryMode), "Failed to parse deliveryMode");
421 CHECK_STATUS_RET(GetSourceMode(env, arg, "sourceMode", sourceMode), "Failed to parse sourceMode");
422 return napi_ok;
423 }
424
GetCompatibleMode(napi_env env, const napi_value arg, const string &propName, CompatibleMode& compatibleMode)425 napi_status GetCompatibleMode(napi_env env, const napi_value arg, const string &propName,
426 CompatibleMode& compatibleMode)
427 {
428 bool present = false;
429 napi_value property = nullptr;
430 int mode = static_cast<int>(CompatibleMode::ORIGINAL_FORMAT_MODE);
431 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
432 if (!present) {
433 NAPI_INFO_LOG("compatible mode is null");
434 compatibleMode = CompatibleMode::ORIGINAL_FORMAT_MODE;
435 return napi_ok;
436 }
437 CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
438 CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse compatiblemode argument value");
439
440 if (static_cast<CompatibleMode>(mode) < CompatibleMode::ORIGINAL_FORMAT_MODE ||
441 static_cast<CompatibleMode>(mode) > CompatibleMode::COMPATIBLE_FORMAT_MODE) {
442 NAPI_ERR_LOG("delivery mode invalid argument ");
443 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid compatible mode value");
444 return napi_invalid_arg;
445 }
446 compatibleMode = static_cast<CompatibleMode>(mode);
447 return napi_ok;
448 }
449
GetMediaAssetProgressHandler(napi_env env, const napi_value arg, napi_value& mediaAssetProgressHandler, const string &propName)450 napi_status GetMediaAssetProgressHandler(napi_env env, const napi_value arg, napi_value& mediaAssetProgressHandler,
451 const string &propName)
452 {
453 CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE,
454 "MediaAssetProgressHandler invalid argument", napi_invalid_arg, "MediaAssetProgressHandler is nullptr");
455 bool present = false;
456 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
457 if (!present) {
458 NAPI_INFO_LOG("MediaAssetProgressHandler is null");
459 mediaAssetProgressHandler = nullptr;
460 return napi_ok;
461 }
462 napi_value progressHandler;
463 napi_status status = napi_get_named_property(env, arg, "mediaAssetProgressHandler", &progressHandler);
464 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
465 "failed to get mediaAssetProgressHandler ", napi_invalid_arg,
466 "failed to get mediaAssetProgressHandler, napi status: %{public}d", static_cast<int>(status));
467 napi_valuetype valueType;
468 status = napi_typeof(env, progressHandler, &valueType);
469 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid progress handler",
470 napi_invalid_arg, "failed to get type of progress handler, napi status: %{public}d", static_cast<int>(status));
471 CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
472 "progress handler not an object", napi_invalid_arg, "progress handler not an object");
473
474 napi_value onProgress;
475 status = napi_get_named_property(env, progressHandler, ON_PROGRESS_FUNC, &onProgress);
476 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
477 "unable to get onProgress function", napi_invalid_arg,
478 "failed to get onProgress function, napi status: %{public}d", static_cast<int>(status));
479
480 status = napi_typeof(env, onProgress, &valueType);
481 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onProgress",
482 napi_invalid_arg, "failed to get type of onProgress, napi status: %{public}d", static_cast<int>(status));
483 CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
484 "onProgress not a function", napi_invalid_arg, "onProgress not a function");
485 mediaAssetProgressHandler = progressHandler;
486 return napi_ok;
487 }
488
ParseArgGetRequestOptionMore(napi_env env, napi_value arg, CompatibleMode &compatibleMode, napi_value &mediaAssetProgressHandler)489 napi_status ParseArgGetRequestOptionMore(napi_env env, napi_value arg, CompatibleMode &compatibleMode,
490 napi_value &mediaAssetProgressHandler)
491 {
492 NAPI_INFO_LOG("ParseArgGetRequestOptionMore start");
493 CHECK_STATUS_RET(GetCompatibleMode(env, arg, "compatibleMode", compatibleMode), "Failed to parse compatibleMode");
494 if (GetMediaAssetProgressHandler(env, arg, mediaAssetProgressHandler, "mediaAssetProgressHandler") != napi_ok) {
495 NAPI_ERR_LOG("requestMedia GetMediaAssetProgressHandler error");
496 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia GetMediaAssetProgressHandler error");
497 return napi_invalid_arg;
498 }
499 return napi_ok;
500 }
501
ParseArgGetPhotoAsset(napi_env env, napi_value arg, int &fileId, std::string &uri, std::string &displayName)502 napi_status ParseArgGetPhotoAsset(napi_env env, napi_value arg, int &fileId, std::string &uri,
503 std::string &displayName)
504 {
505 if (arg == nullptr) {
506 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "ParseArgGetPhotoAsset failed to get photoAsset");
507 return napi_invalid_arg;
508 }
509 FileAssetNapi *obj = nullptr;
510 napi_unwrap(env, arg, reinterpret_cast<void**>(&obj));
511 if (obj == nullptr) {
512 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get asset napi object");
513 return napi_invalid_arg;
514 }
515 fileId = obj->GetFileId();
516 uri = obj->GetFileUri();
517 displayName = obj->GetFileDisplayName();
518 return napi_ok;
519 }
520
ParseArgGetDestPath(napi_env env, napi_value arg, std::string &destPath)521 napi_status ParseArgGetDestPath(napi_env env, napi_value arg, std::string &destPath)
522 {
523 if (arg == nullptr) {
524 NAPI_ERR_LOG("destPath arg is invalid");
525 return napi_invalid_arg;
526 }
527 napi_get_print_string(env, arg, destPath);
528 if (destPath.empty()) {
529 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get destPath napi object");
530 return napi_invalid_arg;
531 }
532 return napi_ok;
533 }
534
ParseArgGetEfficientImageDataHandler(napi_env env, napi_value arg, napi_value& dataHandler, bool& needsExtraInfo)535 napi_status ParseArgGetEfficientImageDataHandler(napi_env env, napi_value arg, napi_value& dataHandler,
536 bool& needsExtraInfo)
537 {
538 CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE, "efficient handler invalid argument",
539 napi_invalid_arg, "efficient data handler is nullptr");
540
541 napi_valuetype valueType;
542 napi_status status = napi_typeof(env, arg, &valueType);
543 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid efficient data handler",
544 napi_invalid_arg, "failed to get type of efficient data handler, napi status: %{public}d",
545 static_cast<int>(status));
546 CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
547 "efficient data handler not a object", napi_invalid_arg, "efficient data handler not a object");
548
549 dataHandler = arg;
550
551 napi_value onDataPrepared;
552 status = napi_get_named_property(env, arg, ON_DATA_PREPARED_FUNC, &onDataPrepared);
553 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
554 "unable to get onDataPrepared function", napi_invalid_arg,
555 "failed to get type of efficient data handler, napi status: %{public}d", static_cast<int>(status));
556 status = napi_typeof(env, onDataPrepared, &valueType);
557 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
558 napi_invalid_arg, "failed to get type of onDataPrepared, napi status: %{public}d", static_cast<int>(status));
559 CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
560 "onDataPrepared not a function", napi_invalid_arg, "onDataPrepared not a function");
561
562 napi_value paramCountNapi;
563 status = napi_get_named_property(env, onDataPrepared, "length", ¶mCountNapi);
564 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
565 napi_invalid_arg, "get onDataPrepared arg count fail, napi status: %{public}d", static_cast<int>(status));
566 int32_t paramCount = -1;
567 constexpr int paramCountMin = 2;
568 constexpr int paramCountMax = 3;
569 status = napi_get_value_int32(env, paramCountNapi, ¶mCount);
570 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
571 napi_invalid_arg, "get onDataPrepared arg count value fail, napi status: %{public}d", static_cast<int>(status));
572 CHECK_COND_LOG_THROW_RETURN_RET(env, (paramCount >= paramCountMin && paramCount <= paramCountMax),
573 OHOS_INVALID_PARAM_CODE, "onDataPrepared has wrong number of parameters",
574 napi_invalid_arg, "onDataPrepared has wrong number of parameters");
575
576 if (paramCount == ARGS_THREE) {
577 needsExtraInfo = true;
578 }
579 return napi_ok;
580 }
581
ParseArgGetDataHandler(napi_env env, napi_value arg, napi_value& dataHandler, bool& needsExtraInfo)582 napi_status ParseArgGetDataHandler(napi_env env, napi_value arg, napi_value& dataHandler, bool& needsExtraInfo)
583 {
584 CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE, "data handler invalid argument",
585 napi_invalid_arg, "data handler is nullptr");
586
587 napi_valuetype valueType;
588 napi_status status = napi_typeof(env, arg, &valueType);
589 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid data handler",
590 napi_invalid_arg, "failed to get type of data handler, napi status: %{public}d", static_cast<int>(status));
591 CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
592 "data handler not a object", napi_invalid_arg, "data handler not a object");
593
594 dataHandler = arg;
595
596 napi_value onDataPrepared;
597 status = napi_get_named_property(env, arg, ON_DATA_PREPARED_FUNC, &onDataPrepared);
598 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
599 "unable to get onDataPrepared function", napi_invalid_arg,
600 "failed to get type of data handler, napi status: %{public}d", static_cast<int>(status));
601 status = napi_typeof(env, onDataPrepared, &valueType);
602 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
603 napi_invalid_arg, "failed to get type of onDataPrepared, napi status: %{public}d", static_cast<int>(status));
604 CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
605 "onDataPrepared not a function", napi_invalid_arg, "onDataPrepared not a function");
606
607 napi_value paramCountNapi;
608 status = napi_get_named_property(env, onDataPrepared, "length", ¶mCountNapi);
609 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
610 napi_invalid_arg, "get onDataPrepared arg count fail, napi status: %{public}d", static_cast<int>(status));
611 int32_t paramCount = -1;
612 constexpr int paramCountMin = 1;
613 constexpr int paramCountMax = 2;
614 status = napi_get_value_int32(env, paramCountNapi, ¶mCount);
615 CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
616 napi_invalid_arg, "get onDataPrepared arg count value fail, napi status: %{public}d", static_cast<int>(status));
617 CHECK_COND_LOG_THROW_RETURN_RET(env, (paramCount >= paramCountMin && paramCount <= paramCountMax),
618 OHOS_INVALID_PARAM_CODE, "onDataPrepared has wrong number of parameters",
619 napi_invalid_arg, "onDataPrepared has wrong number of parameters");
620
621 if (paramCount == ARGS_TWO) {
622 needsExtraInfo = true;
623 }
624 return napi_ok;
625 }
626
GenerateRequestId()627 static std::string GenerateRequestId()
628 {
629 uuid_t uuid;
630 uuid_generate(uuid);
631 char str[UUID_STR_LENGTH] = {};
632 uuid_unparse(uuid, str);
633 return str;
634 }
635
RegisterTaskObserver(napi_env env, MediaAssetManagerAsyncContext *asyncContext)636 void MediaAssetManagerNapi::RegisterTaskObserver(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
637 {
638 auto dataObserver = std::make_shared<MultiStagesTaskObserver>(asyncContext->fileId);
639 auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(asyncContext->photoUri);
640 NAPI_INFO_LOG("uri: %{public}s, %{public}s", asyncContext->photoUri.c_str(), uriLocal.c_str());
641 Uri uri(asyncContext->photoUri);
642 std::unique_lock<std::mutex> registerLock(registerTaskLock);
643 if (multiStagesObserverMap.find(uriLocal) == multiStagesObserverMap.end()) {
644 UserFileClient::RegisterObserverExt(Uri(uriLocal),
645 static_cast<std::shared_ptr<DataShare::DataShareObserver>>(dataObserver), false);
646 multiStagesObserverMap.insert(std::make_pair(uriLocal, dataObserver));
647 }
648 registerLock.unlock();
649
650 InsertDataHandler(NotifyMode::WAIT_FOR_HIGH_QUALITY, env, asyncContext);
651
652 MediaAssetManagerNapi::ProcessImage(asyncContext->fileId, static_cast<int32_t>(asyncContext->deliveryMode));
653 }
654
ParseRequestMediaArgs(napi_env env, napi_callback_info info, unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)655 napi_status MediaAssetManagerNapi::ParseRequestMediaArgs(napi_env env, napi_callback_info info,
656 unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
657 {
658 napi_value thisVar = nullptr;
659 GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
660 if (asyncContext->argc != ARGS_FOUR && asyncContext->argc != ARGS_FIVE) {
661 NAPI_ERR_LOG("requestMedia argc error");
662 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
663 return napi_invalid_arg;
664 }
665 if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext->fileId, asyncContext->photoUri,
666 asyncContext->displayName) != napi_ok) {
667 NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
668 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
669 return napi_invalid_arg;
670 }
671 if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
672 asyncContext->sourceMode) != napi_ok) {
673 NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
674 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
675 return napi_invalid_arg;
676 }
677 if (ParseArgGetRequestOptionMore(env, asyncContext->argv[PARAM2], asyncContext->compatibleMode,
678 asyncContext->mediaAssetProgressHandler) != napi_ok) {
679 NAPI_ERR_LOG("requestMedia ParseArgGetRequestOptionMore error");
680 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOptionMore error");
681 return napi_invalid_arg;
682 }
683 if (asyncContext->argc == ARGS_FOUR) {
684 if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
685 asyncContext->needsExtraInfo) != napi_ok) {
686 NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
687 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
688 return napi_invalid_arg;
689 }
690 } else if (asyncContext->argc == ARGS_FIVE) {
691 if (ParseArgGetDestPath(env, asyncContext->argv[PARAM3], asyncContext->destUri) != napi_ok) {
692 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDestPath error");
693 return napi_invalid_arg;
694 }
695 if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM4], asyncContext->dataHandler,
696 asyncContext->needsExtraInfo) != napi_ok) {
697 NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
698 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
699 return napi_invalid_arg;
700 }
701 }
702 asyncContext->hasReadPermission = HasReadPermission();
703 return napi_ok;
704 }
705
ParseEfficentRequestMediaArgs(napi_env env, napi_callback_info info, unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)706 napi_status MediaAssetManagerNapi::ParseEfficentRequestMediaArgs(napi_env env, napi_callback_info info,
707 unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
708 {
709 napi_value thisVar = nullptr;
710 GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
711 if (asyncContext->argc != ARGS_FOUR && asyncContext->argc != ARGS_FIVE) {
712 NAPI_ERR_LOG("requestMedia argc error");
713 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
714 return napi_invalid_arg;
715 }
716
717 if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext->fileId, asyncContext->photoUri,
718 asyncContext->displayName) != napi_ok) {
719 NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
720 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
721 return napi_invalid_arg;
722 }
723 if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
724 asyncContext->sourceMode) != napi_ok) {
725 NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
726 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
727 return napi_invalid_arg;
728 }
729 if (asyncContext->argc == ARGS_FOUR) {
730 if (ParseArgGetEfficientImageDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
731 asyncContext->needsExtraInfo) != napi_ok) {
732 NAPI_ERR_LOG("requestMedia ParseArgGetEfficientImageDataHandler error");
733 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE,
734 "requestMedia ParseArgGetEfficientImageDataHandler error");
735 return napi_invalid_arg;
736 }
737 } else if (asyncContext->argc == ARGS_FIVE) {
738 if (ParseArgGetDestPath(env, asyncContext->argv[PARAM3], asyncContext->destUri) != napi_ok) {
739 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDestPath error");
740 return napi_invalid_arg;
741 }
742 if (ParseArgGetEfficientImageDataHandler(env, asyncContext->argv[PARAM4], asyncContext->dataHandler,
743 asyncContext->needsExtraInfo) != napi_ok) {
744 NAPI_ERR_LOG("requestMedia ParseArgGetEfficientImageDataHandler error");
745 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE,
746 "requestMedia ParseArgGetEfficientImageDataHandler error");
747 return napi_invalid_arg;
748 }
749 }
750 asyncContext->hasReadPermission = HasReadPermission();
751 return napi_ok;
752 }
753
InitUserFileClient(napi_env env, napi_callback_info info)754 bool MediaAssetManagerNapi::InitUserFileClient(napi_env env, napi_callback_info info)
755 {
756 if (UserFileClient::IsValid()) {
757 return true;
758 }
759
760 std::unique_lock<std::mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
761 if (!UserFileClient::IsValid()) {
762 UserFileClient::Init(env, info);
763 }
764 helperLock.unlock();
765 return UserFileClient::IsValid();
766 }
767
GetPhotoSubtype(napi_env env, napi_value photoAssetArg)768 static int32_t GetPhotoSubtype(napi_env env, napi_value photoAssetArg)
769 {
770 if (photoAssetArg == nullptr) {
771 NAPI_ERR_LOG(
772 "Dfx adaptation to moving photo collector error: failed to get photo subtype, photo asset is null");
773 return -1;
774 }
775 FileAssetNapi *obj = nullptr;
776 napi_unwrap(env, photoAssetArg, reinterpret_cast<void**>(&obj));
777 if (obj == nullptr) {
778 NAPI_ERR_LOG("Dfx adaptation to moving photo collector error: failed to unwrap file asset");
779 return -1;
780 }
781 return obj->GetFileAssetInstance()->GetPhotoSubType();
782 }
783
JSRequestImageData(napi_env env, napi_callback_info info)784 napi_value MediaAssetManagerNapi::JSRequestImageData(napi_env env, napi_callback_info info)
785 {
786 if (env == nullptr || info == nullptr) {
787 NAPI_ERR_LOG("JSRequestImageData js arg invalid");
788 NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestImageData js arg invalid");
789 return nullptr;
790 }
791 if (!InitUserFileClient(env, info)) {
792 NAPI_ERR_LOG("JSRequestImageData init user file client failed");
793 NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
794 return nullptr;
795 }
796
797 MediaLibraryTracer tracer;
798 tracer.Start("JSRequestImageData");
799 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
800 asyncContext->returnDataType = ReturnDataType::TYPE_ARRAY_BUFFER;
801 if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
802 NAPI_ERR_LOG("failed to parse requestImagedata args");
803 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestImagedata args");
804 return nullptr;
805 }
806 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
807 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
808 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
809 return nullptr;
810 }
811 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
812 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
813 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
814 return nullptr;
815 }
816
817 asyncContext->requestId = GenerateRequestId();
818 asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
819
820 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestImageData", JSRequestExecute,
821 JSRequestComplete);
822 }
823
JSRequestImage(napi_env env, napi_callback_info info)824 napi_value MediaAssetManagerNapi::JSRequestImage(napi_env env, napi_callback_info info)
825 {
826 NAPI_DEBUG_LOG("JSRequestImage");
827 if (env == nullptr || info == nullptr) {
828 NAPI_ERR_LOG("JSRequestImage js arg invalid");
829 NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestImage js arg invalid");
830 return nullptr;
831 }
832 if (!InitUserFileClient(env, info)) {
833 NAPI_ERR_LOG("JSRequestImage init user file client failed");
834 NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
835 return nullptr;
836 }
837
838 MediaLibraryTracer tracer;
839 tracer.Start("JSRequestImage");
840
841 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
842 asyncContext->returnDataType = ReturnDataType::TYPE_IMAGE_SOURCE;
843 if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
844 NAPI_ERR_LOG("failed to parse requestImage args");
845 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestImage args");
846 return nullptr;
847 }
848 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
849 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
850 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
851 return nullptr;
852 }
853 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
854 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
855 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
856 return nullptr;
857 }
858
859 asyncContext->requestId = GenerateRequestId();
860 asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
861
862 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestImage", JSRequestExecute,
863 JSRequestComplete);
864 }
865
JSRequestEfficientIImage(napi_env env, napi_callback_info info)866 napi_value MediaAssetManagerNapi::JSRequestEfficientIImage(napi_env env, napi_callback_info info)
867 {
868 NAPI_DEBUG_LOG("JSRequestEfficientIImage");
869 if (env == nullptr || info == nullptr) {
870 NAPI_ERR_LOG("JSRequestEfficientIImage js arg invalid");
871 NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestEfficientIImage js arg invalid");
872 return nullptr;
873 }
874 if (!InitUserFileClient(env, info)) {
875 NAPI_ERR_LOG("JSRequestEfficientIImage init user file client failed");
876 NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
877 return nullptr;
878 }
879
880 MediaLibraryTracer tracer;
881 tracer.Start("JSRequestEfficientIImage");
882
883 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
884 asyncContext->returnDataType = ReturnDataType::TYPE_PICTURE;
885 if (ParseEfficentRequestMediaArgs(env, info, asyncContext) != napi_ok) {
886 NAPI_ERR_LOG("failed to parse JSRequestEfficientIImage args");
887 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse JSRequestEfficientIImage args");
888 return nullptr;
889 }
890 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
891 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
892 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
893 return nullptr;
894 }
895 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
896 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
897 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
898 return nullptr;
899 }
900
901 asyncContext->requestId = GenerateRequestId();
902 asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
903
904 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestEfficientIImage", JSRequestExecute,
905 JSRequestComplete);
906 }
907
CreateOnProgressHandlerInfo(napi_env env, unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)908 bool MediaAssetManagerNapi::CreateOnProgressHandlerInfo(napi_env env,
909 unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
910 {
911 if (asyncContext->compatibleMode != CompatibleMode::COMPATIBLE_FORMAT_MODE) {
912 return true;
913 }
914 if (asyncContext->mediaAssetProgressHandler == nullptr) {
915 if (CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
916 NAPI_ERR_LOG("CreateOnProgressThreadSafeFunc failed");
917 return false;
918 }
919 return true;
920 }
921 if (CreateProgressHandlerRef(env, asyncContext, asyncContext->progressHandlerRef) != napi_ok ||
922 CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
923 NAPI_ERR_LOG("CreateProgressHandlerRef or CreateOnProgressThreadSafeFunc failed");
924 return false;
925 }
926 return true;
927 }
928
JSRequestVideoFile(napi_env env, napi_callback_info info)929 napi_value MediaAssetManagerNapi::JSRequestVideoFile(napi_env env, napi_callback_info info)
930 {
931 if (env == nullptr || info == nullptr) {
932 NAPI_ERR_LOG("JSRequestVideoFile js arg invalid");
933 NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestVideoFile js arg invalid");
934 return nullptr;
935 }
936 if (!InitUserFileClient(env, info)) {
937 NAPI_ERR_LOG("JSRequestVideoFile init user file client failed");
938 NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
939 return nullptr;
940 }
941
942 MediaLibraryTracer tracer;
943 tracer.Start("JSRequestVideoFile");
944
945 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
946 asyncContext->returnDataType = ReturnDataType::TYPE_TARGET_PATH;
947 if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
948 NAPI_ERR_LOG("failed to parse requestVideo args");
949 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestVideo args");
950 return nullptr;
951 }
952 if (asyncContext->photoUri.length() > MAX_URI_SIZE || asyncContext->destUri.length() > MAX_URI_SIZE) {
953 NAPI_ERR_LOG("request video file uri lens out of limit photoUri lens: %{public}zu, destUri lens: %{public}zu",
954 asyncContext->photoUri.length(), asyncContext->destUri.length());
955 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file uri lens out of limit");
956 return nullptr;
957 }
958 if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_VIDEO ||
959 MediaFileUtils::GetMediaType(MediaFileUtils::GetFileName(asyncContext->destUri)) != MEDIA_TYPE_VIDEO) {
960 NAPI_ERR_LOG("request video file type invalid");
961 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file type invalid");
962 return nullptr;
963 }
964 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
965 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
966 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
967 return nullptr;
968 }
969 if (!CreateOnProgressHandlerInfo(env, asyncContext)) {
970 NAPI_ERR_LOG("CreateOnProgressHandlerInfo failed");
971 return nullptr;
972 }
973
974 asyncContext->requestId = GenerateRequestId();
975 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestVideoFile",
976 JSRequestVideoFileExecute, JSRequestComplete);
977 }
978
OnHandleRequestImage(napi_env env, MediaAssetManagerAsyncContext *asyncContext)979 void MediaAssetManagerNapi::OnHandleRequestImage(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
980 {
981 MultiStagesCapturePhotoStatus status = MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
982 switch (asyncContext->deliveryMode) {
983 case DeliveryMode::FAST:
984 if (asyncContext->needsExtraInfo) {
985 asyncContext->photoQuality = MediaAssetManagerNapi::QueryPhotoStatus(asyncContext->fileId,
986 asyncContext->photoUri, asyncContext->photoId, asyncContext->hasReadPermission);
987 }
988 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
989 break;
990 case DeliveryMode::HIGH_QUALITY:
991 status = MediaAssetManagerNapi::QueryPhotoStatus(asyncContext->fileId,
992 asyncContext->photoUri, asyncContext->photoId, asyncContext->hasReadPermission);
993 asyncContext->photoQuality = status;
994 if (status == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
995 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
996 } else {
997 RegisterTaskObserver(env, asyncContext);
998 }
999 break;
1000 case DeliveryMode::BALANCED_MODE:
1001 status = MediaAssetManagerNapi::QueryPhotoStatus(asyncContext->fileId,
1002 asyncContext->photoUri, asyncContext->photoId, asyncContext->hasReadPermission);
1003 asyncContext->photoQuality = status;
1004 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1005 if (status == MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
1006 RegisterTaskObserver(env, asyncContext);
1007 }
1008 break;
1009 default: {
1010 NAPI_ERR_LOG("invalid delivery mode");
1011 return;
1012 }
1013 }
1014 }
1015
OnHandleRequestVideo(napi_env env, MediaAssetManagerAsyncContext *asyncContext)1016 void MediaAssetManagerNapi::OnHandleRequestVideo(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
1017 {
1018 switch (asyncContext->deliveryMode) {
1019 case DeliveryMode::FAST:
1020 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1021 break;
1022 case DeliveryMode::HIGH_QUALITY:
1023 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1024 break;
1025 case DeliveryMode::BALANCED_MODE:
1026 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1027 break;
1028 default: {
1029 NAPI_ERR_LOG("invalid delivery mode");
1030 return;
1031 }
1032 }
1033 }
1034
NotifyDataPreparedWithoutRegister(napi_env env, MediaAssetManagerAsyncContext *asyncContext)1035 void MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(napi_env env,
1036 MediaAssetManagerAsyncContext *asyncContext)
1037 {
1038 AssetHandler *assetHandler = InsertDataHandler(NotifyMode::FAST_NOTIFY, env, asyncContext);
1039 if (assetHandler == nullptr) {
1040 NAPI_ERR_LOG("assetHandler is nullptr");
1041 return;
1042 }
1043 asyncContext->assetHandler = assetHandler;
1044 }
1045
OnHandleProgress(napi_env env, MediaAssetManagerAsyncContext *asyncContext)1046 void MediaAssetManagerNapi::OnHandleProgress(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
1047 {
1048 ProgressHandler *progressHandler = InsertProgressHandler(env, asyncContext);
1049 if (progressHandler == nullptr) {
1050 NAPI_ERR_LOG("progressHandler is nullptr");
1051 return;
1052 }
1053 asyncContext->progressHandler = progressHandler;
1054 }
1055
PhotoQualityToString(MultiStagesCapturePhotoStatus photoQuality)1056 static string PhotoQualityToString(MultiStagesCapturePhotoStatus photoQuality)
1057 {
1058 static const string HIGH_QUALITY_STRING = "high";
1059 static const string LOW_QUALITY_STRING = "low";
1060 if (photoQuality != MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS &&
1061 photoQuality != MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
1062 NAPI_ERR_LOG("Invalid photo quality: %{public}d", static_cast<int>(photoQuality));
1063 return HIGH_QUALITY_STRING;
1064 }
1065
1066 return (photoQuality == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) ? HIGH_QUALITY_STRING :
1067 LOW_QUALITY_STRING;
1068 }
1069
GetInfoMapNapiValue(napi_env env, AssetHandler* assetHandler)1070 static napi_value GetInfoMapNapiValue(napi_env env, AssetHandler* assetHandler)
1071 {
1072 napi_status status;
1073 napi_value mapNapiValue {nullptr};
1074 status = napi_create_map(env, &mapNapiValue);
1075 CHECK_COND_RET(status == napi_ok && mapNapiValue != nullptr, nullptr,
1076 "Failed to create map napi value, napi status: %{public}d", static_cast<int>(status));
1077
1078 napi_value qualityInfo {nullptr};
1079 status = napi_create_string_utf8(env, PhotoQualityToString(assetHandler->photoQuality).c_str(),
1080 NAPI_AUTO_LENGTH, &qualityInfo);
1081 CHECK_COND_RET(status == napi_ok && qualityInfo != nullptr, nullptr,
1082 "Failed to create quality string, napi status: %{public}d", static_cast<int>(status));
1083
1084 status = napi_set_named_property(env, mapNapiValue, "quality", qualityInfo);
1085 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set quality property, napi status: %{public}d",
1086 static_cast<int>(status));
1087
1088 status = napi_map_set_named_property(env, mapNapiValue, "quality", qualityInfo);
1089 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set quality map key-value, napi status: %{public}d",
1090 static_cast<int>(status));
1091
1092 return mapNapiValue;
1093 }
1094
GetNapiValueOfMedia(napi_env env, const std::shared_ptr<NapiMediaAssetDataHandler>& dataHandler, bool& isPicture)1095 static napi_value GetNapiValueOfMedia(napi_env env, const std::shared_ptr<NapiMediaAssetDataHandler>& dataHandler,
1096 bool& isPicture)
1097 {
1098 NAPI_DEBUG_LOG("GetNapiValueOfMedia");
1099 napi_value napiValueOfMedia = nullptr;
1100 if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_ARRAY_BUFFER) {
1101 MediaAssetManagerNapi::GetByteArrayNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
1102 dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env);
1103 } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_IMAGE_SOURCE) {
1104 MediaAssetManagerNapi::GetImageSourceNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
1105 dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env);
1106 } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_TARGET_PATH) {
1107 WriteData param;
1108 param.compatibleMode = dataHandler->GetCompatibleMode();
1109 param.destUri = dataHandler->GetDestUri();
1110 param.requestUri = dataHandler->GetRequestUri();
1111 param.env = env;
1112 param.isSource = dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE;
1113 MediaAssetManagerNapi::WriteDataToDestPath(param, napiValueOfMedia, dataHandler->GetRequestId());
1114 } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_MOVING_PHOTO) {
1115 napiValueOfMedia = MovingPhotoNapi::NewMovingPhotoNapi(
1116 env, dataHandler->GetRequestUri(), dataHandler->GetSourceMode());
1117 } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_PICTURE) {
1118 MediaAssetManagerNapi::GetPictureNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
1119 dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env, isPicture);
1120 } else {
1121 NAPI_ERR_LOG("source mode type invalid");
1122 }
1123 return napiValueOfMedia;
1124 }
1125
IsSaveCallbackInfoByTranscoder(napi_value napiValueOfMedia, napi_env env, AssetHandler *assetHandler, napi_value napiValueOfInfoMap)1126 bool IsSaveCallbackInfoByTranscoder(napi_value napiValueOfMedia, napi_env env, AssetHandler *assetHandler,
1127 napi_value napiValueOfInfoMap)
1128 {
1129 auto dataHandler = assetHandler->dataHandler;
1130 if (dataHandler == nullptr) {
1131 NAPI_ERR_LOG("data handler is nullptr");
1132 DeleteAssetHandlerSafe(assetHandler, env);
1133 return false;
1134 }
1135 if (napiValueOfMedia == nullptr) {
1136 napi_get_undefined(env, &napiValueOfMedia);
1137 }
1138 bool isTranscoder;
1139 if (!isTranscoderMap_.Find(assetHandler->requestId, isTranscoder)) {
1140 NAPI_INFO_LOG("not find key from map");
1141 isTranscoder = false;
1142 }
1143 NAPI_INFO_LOG("IsSaveCallbackInfoByTranscoder isTranscoder_ %{public}d", isTranscoder);
1144 if (isTranscoder) {
1145 onPreparedResult_.EnsureInsert(assetHandler->requestId, assetHandler);
1146 onPreparedResultValue_.EnsureInsert(assetHandler->requestId, napiValueOfMedia);
1147 return true;
1148 }
1149 dataHandler->JsOnDataPrepared(env, napiValueOfMedia, napiValueOfInfoMap);
1150 return false;
1151 }
1152
SavePicture(std::string &fileUri)1153 static void SavePicture(std::string &fileUri)
1154 {
1155 std::string uriStr = PATH_SAVE_PICTURE;
1156 std::string tempStr = fileUri.substr(PhotoColumn::PHOTO_URI_PREFIX.length());
1157 std::size_t index = tempStr.find("/");
1158 std::string fileId = tempStr.substr(0, index);
1159 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1160 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, fileId);
1161 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, IMAGE_FILE_TYPE, "1");
1162 MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, "uri", fileUri);
1163 Uri uri(uriStr);
1164 DataShare::DataShareValuesBucket valuesBucket;
1165 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
1166 DataShare::DataSharePredicates predicate;
1167 UserFileClient::Update(uri, predicate, valuesBucket);
1168 }
1169
OnDataPrepared(napi_env env, napi_value cb, void *context, void *data)1170 void MediaAssetManagerNapi::OnDataPrepared(napi_env env, napi_value cb, void *context, void *data)
1171 {
1172 NAPI_DEBUG_LOG("OnDataPrepared");
1173 AssetHandler *assetHandler = reinterpret_cast<AssetHandler *>(data);
1174 CHECK_NULL_PTR_RETURN_VOID(assetHandler, "assetHandler is nullptr");
1175 auto dataHandler = assetHandler->dataHandler;
1176 if (dataHandler == nullptr) {
1177 NAPI_ERR_LOG("data handler is nullptr");
1178 DeleteAssetHandlerSafe(assetHandler, env);
1179 return;
1180 }
1181
1182 NotifyMode notifyMode = dataHandler->GetNotifyMode();
1183 if (notifyMode == NotifyMode::FAST_NOTIFY) {
1184 AssetHandler *tmp;
1185 if (!inProcessFastRequests.Find(assetHandler->requestId, tmp)) {
1186 NAPI_ERR_LOG("The request has been canceled");
1187 DeleteAssetHandlerSafe(assetHandler, env);
1188 return;
1189 }
1190 }
1191
1192 napi_value napiValueOfInfoMap = nullptr;
1193 if (assetHandler->needsExtraInfo) {
1194 napiValueOfInfoMap = GetInfoMapNapiValue(env, assetHandler);
1195 if (napiValueOfInfoMap == nullptr) {
1196 NAPI_ERR_LOG("Failed to get info map");
1197 napi_get_undefined(env, &napiValueOfInfoMap);
1198 }
1199 }
1200 bool isPicture = true;
1201 if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_ARRAY_BUFFER ||
1202 dataHandler->GetReturnDataType() == ReturnDataType::TYPE_IMAGE_SOURCE) {
1203 string uri = dataHandler->GetRequestUri();
1204 SavePicture(uri);
1205 }
1206 napi_value napiValueOfMedia = GetNapiValueOfMedia(env, dataHandler, isPicture);
1207 if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_PICTURE) {
1208 if (isPicture) {
1209 dataHandler->JsOnDataPrepared(env, napiValueOfMedia, nullptr, napiValueOfInfoMap);
1210 } else {
1211 if (napiValueOfMedia == nullptr) {
1212 napi_get_undefined(env, &napiValueOfMedia);
1213 }
1214 dataHandler->JsOnDataPrepared(env, nullptr, napiValueOfMedia, napiValueOfInfoMap);
1215 }
1216 } else {
1217 if (IsSaveCallbackInfoByTranscoder(napiValueOfMedia, env, assetHandler, napiValueOfInfoMap)) {
1218 return;
1219 }
1220 }
1221 DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
1222 NAPI_INFO_LOG("delete assetHandler: %{public}p", assetHandler);
1223 DeleteAssetHandlerSafe(assetHandler, env);
1224 }
1225
CallPreparedCallbackAfterProgress(napi_env env, ProgressHandler *progressHandler, napi_value napiValueOfMedia)1226 void CallPreparedCallbackAfterProgress(napi_env env, ProgressHandler *progressHandler, napi_value napiValueOfMedia)
1227 {
1228 MediaCallTranscode::CallTranscodeRelease(progressHandler->requestId);
1229 MediaAssetManagerNapi::progressHandlerMap_.Erase(progressHandler->requestId);
1230 AssetHandler *assetHandler = nullptr;
1231 if (!onPreparedResult_.Find(progressHandler->requestId, assetHandler)) {
1232 NAPI_ERR_LOG("not find key from map");
1233 return;
1234 }
1235 onPreparedResult_.Erase(progressHandler->requestId);
1236 auto dataHandler = assetHandler->dataHandler;
1237 if (dataHandler == nullptr) {
1238 NAPI_ERR_LOG("data handler is nullptr");
1239 DeleteAssetHandlerSafe(assetHandler, env);
1240 return;
1241 }
1242
1243 NotifyMode notifyMode = dataHandler->GetNotifyMode();
1244 napi_value napiValueOfInfoMap = nullptr;
1245 if (assetHandler->needsExtraInfo) {
1246 napiValueOfInfoMap = GetInfoMapNapiValue(env, assetHandler);
1247 if (napiValueOfInfoMap == nullptr) {
1248 NAPI_ERR_LOG("Failed to get info map");
1249 napi_get_undefined(env, &napiValueOfInfoMap);
1250 }
1251 }
1252 dataHandler->JsOnDataPrepared(env, napiValueOfMedia, napiValueOfInfoMap);
1253 NAPI_INFO_LOG("delete assetHandler: %{public}p", assetHandler);
1254 DeleteProcessHandlerSafe(progressHandler, env);
1255 DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
1256 DeleteAssetHandlerSafe(assetHandler, env);
1257 }
1258
CallProgressCallback(napi_env env, ProgressHandler &progressHandler, int32_t process)1259 void CallProgressCallback(napi_env env, ProgressHandler &progressHandler, int32_t process)
1260 {
1261 napi_value result;
1262 napi_status status = napi_create_int32(env, process, &result);
1263 if (status != napi_ok) {
1264 NAPI_ERR_LOG("OnProgress napi_create_int32 fail");
1265 }
1266 napi_value callback;
1267 status = napi_get_reference_value(env, progressHandler.progressRef, &callback);
1268 if (status != napi_ok) {
1269 NAPI_ERR_LOG("OnProgress napi_get_reference_value fail, napi status: %{public}d",
1270 static_cast<int>(status));
1271 DeleteProcessHandlerSafe(&progressHandler, env);
1272 return;
1273 }
1274 napi_value jsOnProgress;
1275 status = napi_get_named_property(env, callback, ON_PROGRESS_FUNC, &jsOnProgress);
1276 if (status != napi_ok) {
1277 NAPI_ERR_LOG("jsOnProgress napi_get_named_property fail, napi status: %{public}d",
1278 static_cast<int>(status));
1279 DeleteProcessHandlerSafe(&progressHandler, env);
1280 return;
1281 }
1282 constexpr size_t maxArgs = 1;
1283 napi_value argv[maxArgs];
1284 size_t argc = ARGS_ONE;
1285 argv[PARAM0] = result;
1286 argc = ARGS_ONE;
1287 napi_value promise;
1288 status = napi_call_function(env, nullptr, jsOnProgress, argc, argv, &promise);
1289 if (status != napi_ok) {
1290 NAPI_ERR_LOG("call js function failed %{public}d", static_cast<int32_t>(status));
1291 NapiError::ThrowError(env, JS_INNER_FAIL, "calling onDataPrepared failed");
1292 }
1293 NAPI_INFO_LOG("CallProgressCallback process %{public}d", process);
1294 }
1295
OnProgress(napi_env env, napi_value cb, void *context, void *data)1296 void MediaAssetManagerNapi::OnProgress(napi_env env, napi_value cb, void *context, void *data)
1297 {
1298 ProgressHandler *progressHandler = reinterpret_cast<ProgressHandler *>(data);
1299 if (progressHandler == nullptr) {
1300 NAPI_ERR_LOG("progressHandler handler is nullptr");
1301 DeleteProcessHandlerSafe(progressHandler, env);
1302 return;
1303 }
1304 int32_t process = progressHandler->retProgressValue.progress;
1305 int32_t type = progressHandler->retProgressValue.type;
1306
1307 if (type == INFO_TYPE_TRANSCODER_COMPLETED || type == INFO_TYPE_ERROR) {
1308 bool isTranscoder;
1309 if (isTranscoderMap_.Find(progressHandler->requestId, isTranscoder)) {
1310 isTranscoderMap_.Erase(progressHandler->requestId);
1311 }
1312
1313 napi_value napiValueOfMedia;
1314 if (onPreparedResultValue_.Find(progressHandler->requestId, napiValueOfMedia)) {
1315 onPreparedResultValue_.Erase(progressHandler->requestId);
1316 }
1317 if (type == INFO_TYPE_ERROR) {
1318 napi_get_boolean(env, false, &napiValueOfMedia);
1319 }
1320 NAPI_INFO_LOG("CallPreparedCallbackAfterProgress type %{public}d", type);
1321 CallPreparedCallbackAfterProgress(env, progressHandler, napiValueOfMedia);
1322 return;
1323 }
1324 if (progressHandler->progressRef == nullptr) {
1325 NAPI_INFO_LOG("progressHandler->progressRef == nullptr");
1326 return;
1327 }
1328 CallProgressCallback(env, *progressHandler, process);
1329 }
1330
NotifyMediaDataPrepared(AssetHandler *assetHandler)1331 void MediaAssetManagerNapi::NotifyMediaDataPrepared(AssetHandler *assetHandler)
1332 {
1333 napi_status status = napi_call_threadsafe_function(assetHandler->threadSafeFunc, (void *)assetHandler,
1334 napi_tsfn_blocking);
1335 if (status != napi_ok) {
1336 NAPI_ERR_LOG("napi_call_threadsafe_function fail, %{public}d", static_cast<int32_t>(status));
1337 napi_release_threadsafe_function(assetHandler->threadSafeFunc, napi_tsfn_release);
1338 DeleteAssetHandlerSafe(assetHandler, nullptr);
1339 }
1340 }
1341
OnChange(const ChangeInfo &changeInfo)1342 void MultiStagesTaskObserver::OnChange(const ChangeInfo &changeInfo)
1343 {
1344 if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_UPDATE)) {
1345 NAPI_DEBUG_LOG("ignore notify change, type: %{public}d", changeInfo.changeType_);
1346 return;
1347 }
1348 for (auto &uri : changeInfo.uris_) {
1349 string uriString = uri.ToString();
1350 NAPI_DEBUG_LOG("%{public}s", uriString.c_str());
1351 std::string photoId = "";
1352 if (MediaAssetManagerNapi::QueryPhotoStatus(fileId_, uriString, photoId, true) !=
1353 MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
1354 NAPI_ERR_LOG("requested data not prepared");
1355 continue;
1356 }
1357
1358 std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
1359 if (inProcessUriMap.find(uriString) == inProcessUriMap.end()) {
1360 NAPI_INFO_LOG("current uri does not in process, uri: %{public}s", uriString.c_str());
1361 return;
1362 }
1363 std::map<std::string, AssetHandler *> assetHandlers = inProcessUriMap[uriString];
1364 for (auto handler : assetHandlers) {
1365 auto assetHandler = handler.second;
1366 assetHandler->photoQuality = MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
1367 MediaAssetManagerNapi::NotifyMediaDataPrepared(assetHandler);
1368 }
1369 }
1370 }
1371
NotifyOnProgress(int32_t type, int32_t progress, std::string requestId)1372 void MediaAssetManagerNapi::NotifyOnProgress(int32_t type, int32_t progress, std::string requestId)
1373 {
1374 NAPI_DEBUG_LOG("NotifyOnProgress start %{public}d,type %{public}d", progress, type);
1375 ProgressHandler *progressHandler = nullptr;
1376 if (!MediaAssetManagerNapi::progressHandlerMap_.Find(requestId, progressHandler)) {
1377 NAPI_ERR_LOG("not find key from map");
1378 return;
1379 }
1380 if (progressHandler == nullptr) {
1381 NAPI_ERR_LOG("ProgressHandler is nullptr.");
1382 return;
1383 }
1384 progressHandler->retProgressValue.progress = progress;
1385 progressHandler->retProgressValue.type = type;
1386
1387 napi_status status = napi_acquire_threadsafe_function(progressHandler->progressFunc);
1388 if (status != napi_ok) {
1389 NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
1390 return;
1391 }
1392 status = napi_call_threadsafe_function(progressHandler->progressFunc, (void *)progressHandler, napi_tsfn_blocking);
1393 if (status != napi_ok) {
1394 NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
1395 DeleteProcessHandlerSafe(progressHandler, progressHandler->env);
1396 return;
1397 }
1398 }
1399
GetImageSourceNapiObject(const std::string &fileUri, napi_value &imageSourceNapiObj, bool isSource, napi_env env)1400 void MediaAssetManagerNapi::GetImageSourceNapiObject(const std::string &fileUri, napi_value &imageSourceNapiObj,
1401 bool isSource, napi_env env)
1402 {
1403 if (env == nullptr) {
1404 NAPI_ERR_LOG(" create image source object failed, need to initialize js env");
1405 return;
1406 }
1407 napi_value tempImageSourceNapi;
1408 ImageSourceNapi::CreateImageSourceNapi(env, &tempImageSourceNapi);
1409 ImageSourceNapi* imageSourceNapi = nullptr;
1410 napi_unwrap(env, tempImageSourceNapi, reinterpret_cast<void**>(&imageSourceNapi));
1411 if (imageSourceNapi == nullptr) {
1412 NAPI_ERR_LOG("unwrap image napi object failed");
1413 return;
1414 }
1415 std::string tmpUri = fileUri;
1416 if (isSource) {
1417 MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
1418 NAPI_INFO_LOG("request source image's imageSource");
1419 }
1420 Uri uri(tmpUri);
1421 int fd = UserFileClient::OpenFile(uri, "r");
1422 if (fd < 0) {
1423 NAPI_ERR_LOG("get image fd failed, errno: %{public}d", errno);
1424 return;
1425 }
1426
1427 SourceOptions opts;
1428 uint32_t errCode = 0;
1429 auto nativeImageSourcePtr = ImageSource::CreateImageSource(fd, opts, errCode);
1430 close(fd);
1431 if (nativeImageSourcePtr == nullptr) {
1432 NAPI_ERR_LOG("get ImageSource::CreateImageSource failed nullptr");
1433 return;
1434 }
1435 imageSourceNapi->SetNativeImageSource(std::move(nativeImageSourcePtr));
1436 imageSourceNapiObj = tempImageSourceNapi;
1437 }
1438
GetPictureNapiObject(const std::string &fileUri, napi_value &pictureNapiObj, bool isSource, napi_env env, bool& isPicture)1439 void MediaAssetManagerNapi::GetPictureNapiObject(const std::string &fileUri, napi_value &pictureNapiObj,
1440 bool isSource, napi_env env, bool& isPicture)
1441 {
1442 if (env == nullptr) {
1443 NAPI_ERR_LOG(" create image source object failed, need to initialize js env");
1444 return;
1445 }
1446 NAPI_DEBUG_LOG("GetPictureNapiObject");
1447
1448 std::string tempStr = fileUri.substr(PhotoColumn::PHOTO_URI_PREFIX.length());
1449 std::size_t index = tempStr.find("/");
1450 std::string fileId = tempStr.substr(0, index);
1451 auto pic = PictureHandlerClient::RequestPicture(std::atoi(fileId.c_str()));
1452 if (pic == nullptr) {
1453 NAPI_ERR_LOG("picture is null");
1454 isPicture = false;
1455 GetImageSourceNapiObject(fileUri, pictureNapiObj, isSource, env);
1456 return;
1457 }
1458 NAPI_ERR_LOG("picture is not null");
1459 napi_value tempPictureNapi;
1460 PictureNapi::CreatePictureNapi(env, &tempPictureNapi);
1461 PictureNapi* pictureNapi = nullptr;
1462 napi_unwrap(env, tempPictureNapi, reinterpret_cast<void**>(&pictureNapi));
1463 if (pictureNapi == nullptr) {
1464 NAPI_ERR_LOG("GetPictureNapiObject unwrap image napi object failed");
1465 return;
1466 }
1467 pictureNapi->SetNativePicture(pic);
1468 pictureNapiObj = tempPictureNapi;
1469 }
1470
1471
GetByteArrayNapiObject(const std::string &requestUri, napi_value &arrayBuffer, bool isSource, napi_env env)1472 void MediaAssetManagerNapi::GetByteArrayNapiObject(const std::string &requestUri, napi_value &arrayBuffer,
1473 bool isSource, napi_env env)
1474 {
1475 if (env == nullptr) {
1476 NAPI_ERR_LOG("create byte array object failed, need to initialize js env");
1477 return;
1478 }
1479
1480 std::string tmpUri = requestUri;
1481 if (isSource) {
1482 MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
1483 }
1484 Uri uri(tmpUri);
1485 int imageFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
1486 if (imageFd < 0) {
1487 NAPI_ERR_LOG("get image fd failed, %{public}d", errno);
1488 return;
1489 }
1490 ssize_t imgLen = lseek(imageFd, 0, SEEK_END);
1491 void* buffer = nullptr;
1492 napi_create_arraybuffer(env, imgLen, &buffer, &arrayBuffer);
1493 lseek(imageFd, 0, SEEK_SET);
1494 ssize_t readRet = read(imageFd, buffer, imgLen);
1495 close(imageFd);
1496 if (readRet != imgLen) {
1497 NAPI_ERR_LOG("read image failed");
1498 return;
1499 }
1500 }
1501
IsMovingPhoto(int32_t photoSubType, int32_t effectMode, int32_t sourceMode)1502 bool IsMovingPhoto(int32_t photoSubType, int32_t effectMode, int32_t sourceMode)
1503 {
1504 return photoSubType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
1505 (MediaLibraryNapiUtils::IsSystemApp() && sourceMode == static_cast<int32_t>(SourceMode::ORIGINAL_MODE) &&
1506 effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY));
1507 }
1508
ParseArgsForRequestMovingPhoto(napi_env env, size_t argc, const napi_value argv[], unique_ptr<MediaAssetManagerAsyncContext> &context)1509 static napi_value ParseArgsForRequestMovingPhoto(napi_env env, size_t argc, const napi_value argv[],
1510 unique_ptr<MediaAssetManagerAsyncContext> &context)
1511 {
1512 CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_FOUR), "Invalid number of arguments");
1513
1514 FileAssetNapi *fileAssetNapi = nullptr;
1515 CHECK_COND_WITH_MESSAGE(env,
1516 (napi_unwrap(env, argv[PARAM1], reinterpret_cast<void**>(&fileAssetNapi)) == napi_ok),
1517 "Failed to parse photo asset");
1518 CHECK_COND_WITH_MESSAGE(env, fileAssetNapi != nullptr, "Failed to parse photo asset");
1519 auto fileAssetPtr = fileAssetNapi->GetFileAssetInstance();
1520 CHECK_COND_WITH_MESSAGE(env, fileAssetPtr != nullptr, "fileAsset is null");
1521 context->photoUri = fileAssetPtr->GetUri();
1522 context->fileId = fileAssetPtr->GetId();
1523 context->returnDataType = ReturnDataType::TYPE_MOVING_PHOTO;
1524 context->hasReadPermission = HasReadPermission();
1525 context->subType = PhotoSubType::MOVING_PHOTO;
1526
1527 CHECK_COND_WITH_MESSAGE(env,
1528 ParseArgGetRequestOption(env, argv[PARAM2], context->deliveryMode, context->sourceMode) == napi_ok,
1529 "Failed to parse request option");
1530 CHECK_COND_WITH_MESSAGE(env, IsMovingPhoto(fileAssetPtr->GetPhotoSubType(),
1531 fileAssetPtr->GetMovingPhotoEffectMode(), static_cast<int32_t>(context->sourceMode)),
1532 "Asset is not a moving photo");
1533 if (ParseArgGetDataHandler(env, argv[PARAM3], context->dataHandler, context->needsExtraInfo) != napi_ok) {
1534 NAPI_ERR_LOG("requestMovingPhoto ParseArgGetDataHandler error");
1535 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMovingPhoto ParseArgGetDataHandler error");
1536 return nullptr;
1537 }
1538
1539 RETURN_NAPI_TRUE(env);
1540 }
1541
JSRequestMovingPhoto(napi_env env, napi_callback_info info)1542 napi_value MediaAssetManagerNapi::JSRequestMovingPhoto(napi_env env, napi_callback_info info)
1543 {
1544 MediaLibraryTracer tracer;
1545 tracer.Start("JSRequestMovingPhoto");
1546
1547 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
1548 CHECK_ARGS(env, napi_get_cb_info(env, info, &(asyncContext->argc), asyncContext->argv, nullptr, nullptr),
1549 JS_INNER_FAIL);
1550 CHECK_NULLPTR_RET(ParseArgsForRequestMovingPhoto(env, asyncContext->argc, asyncContext->argv, asyncContext));
1551 CHECK_COND(env, InitUserFileClient(env, info), JS_INNER_FAIL);
1552 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
1553 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
1554 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
1555 return nullptr;
1556 }
1557 if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
1558 || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
1559 NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
1560 return nullptr;
1561 }
1562 asyncContext->requestId = GenerateRequestId();
1563
1564 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestMovingPhoto", JSRequestExecute,
1565 JSRequestComplete);
1566 }
1567
WriteDataToDestPath(WriteData &writeData, napi_value &resultNapiValue, std::string requestId)1568 void MediaAssetManagerNapi::WriteDataToDestPath(WriteData &writeData, napi_value &resultNapiValue,
1569 std::string requestId)
1570 {
1571 if (writeData.env == nullptr) {
1572 NAPI_ERR_LOG("create byte array object failed, need to initialize js env");
1573 return;
1574 }
1575 if (writeData.requestUri.empty() || writeData.destUri.empty()) {
1576 napi_get_boolean(writeData.env, false, &resultNapiValue);
1577 NAPI_ERR_LOG("requestUri or responseUri is nullptr");
1578 return;
1579 }
1580 std::string tmpUri = writeData.requestUri;
1581 if (writeData.isSource) {
1582 MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
1583 }
1584 Uri srcUri(tmpUri);
1585 int srcFd = UserFileClient::OpenFile(srcUri, MEDIA_FILEMODE_READONLY);
1586 if (srcFd < 0) {
1587 napi_get_boolean(writeData.env, false, &resultNapiValue);
1588 NAPI_ERR_LOG("get source file fd failed %{public}d", srcFd);
1589 return;
1590 }
1591 struct stat statSrc;
1592 if (fstat(srcFd, &statSrc) == -1) {
1593 close(srcFd);
1594 napi_get_boolean(writeData.env, false, &resultNapiValue);
1595 NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
1596 return;
1597 }
1598 int destFd = GetFdFromSandBoxUri(writeData.destUri);
1599 if (destFd < 0) {
1600 close(srcFd);
1601 napi_get_boolean(writeData.env, false, &resultNapiValue);
1602 NAPI_ERR_LOG("get dest fd failed %{public}d", destFd);
1603 return;
1604 }
1605 NAPI_INFO_LOG("WriteDataToDestPath compatibleMode %{public}d", writeData.compatibleMode);
1606 if (writeData.compatibleMode == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
1607 isTranscoderMap_.Insert(requestId, true);
1608 MediaCallTranscode::RegisterCallback(NotifyOnProgress);
1609 MediaCallTranscode::CallTranscodeHandle(writeData.env, srcFd, destFd, resultNapiValue,
1610 statSrc.st_size, requestId);
1611 } else {
1612 SendFile(writeData.env, srcFd, destFd, resultNapiValue, statSrc.st_size);
1613 }
1614 close(srcFd);
1615 close(destFd);
1616 return;
1617 }
1618
SendFile(napi_env env, int srcFd, int destFd, napi_value &result, off_t fileSize)1619 void MediaAssetManagerNapi::SendFile(napi_env env, int srcFd, int destFd, napi_value &result, off_t fileSize)
1620 {
1621 if (srcFd < 0 || destFd < 0) {
1622 NAPI_ERR_LOG("srcFd or destFd is invalid");
1623 napi_get_boolean(env, false, &result);
1624 return;
1625 }
1626 if (sendfile(destFd, srcFd, nullptr, fileSize) == -1) {
1627 close(srcFd);
1628 close(destFd);
1629 napi_get_boolean(env, false, &result);
1630 NAPI_ERR_LOG("send file failed, %{public}d", errno);
1631 return;
1632 }
1633 napi_get_boolean(env, true, &result);
1634 }
1635
IsFastRequestCanceled(const std::string &requestId, std::string &photoId)1636 static bool IsFastRequestCanceled(const std::string &requestId, std::string &photoId)
1637 {
1638 AssetHandler *assetHandler = nullptr;
1639 if (!inProcessFastRequests.Find(requestId, assetHandler)) {
1640 NAPI_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
1641 return false;
1642 }
1643
1644 if (assetHandler == nullptr) {
1645 NAPI_ERR_LOG("assetHandler is nullptr.");
1646 return false;
1647 }
1648 photoId = assetHandler->photoId;
1649 inProcessFastRequests.Erase(requestId);
1650 return true;
1651 }
1652
IsMapRecordCanceled(const std::string &requestId, std::string &photoId, napi_env env)1653 static bool IsMapRecordCanceled(const std::string &requestId, std::string &photoId, napi_env env)
1654 {
1655 AssetHandler *assetHandler = nullptr;
1656 if (!IsInProcessInMapRecord(requestId, assetHandler)) {
1657 NAPI_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
1658 return false;
1659 }
1660
1661 if (assetHandler == nullptr) {
1662 NAPI_ERR_LOG("assetHandler is nullptr.");
1663 return false;
1664 }
1665 photoId = assetHandler->photoId;
1666 DeleteInProcessMapRecord(assetHandler->requestUri, assetHandler->requestId);
1667 DeleteAssetHandlerSafe(assetHandler, env);
1668 return true;
1669 }
1670
JSCancelRequest(napi_env env, napi_callback_info info)1671 napi_value MediaAssetManagerNapi::JSCancelRequest(napi_env env, napi_callback_info info)
1672 {
1673 size_t argc = ARGS_TWO;
1674 napi_value argv[ARGS_TWO];
1675 napi_value thisVar = nullptr;
1676
1677 GET_JS_ARGS(env, info, argc, argv, thisVar);
1678 NAPI_ASSERT(env, (argc == ARGS_TWO), "requires 2 paramters");
1679
1680 string requestId;
1681 CHECK_ARGS_THROW_INVALID_PARAM(env,
1682 MediaLibraryNapiUtils::GetParamStringWithLength(env, argv[ARGS_ONE], REQUEST_ID_MAX_LEN, requestId));
1683 std::string photoId = "";
1684 bool hasFastRequestInProcess = IsFastRequestCanceled(requestId, photoId);
1685 bool hasMapRecordInProcess = IsMapRecordCanceled(requestId, photoId, env);
1686 if (hasFastRequestInProcess || hasMapRecordInProcess) {
1687 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
1688 asyncContext->photoId = photoId;
1689 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCancelRequest", JSCancelRequestExecute,
1690 JSCancelRequestComplete);
1691 }
1692 RETURN_NAPI_UNDEFINED(env);
1693 }
1694
ParseArgsForLoadMovingPhoto(napi_env env, size_t argc, const napi_value argv[], unique_ptr<MediaAssetManagerAsyncContext> &context)1695 static napi_value ParseArgsForLoadMovingPhoto(napi_env env, size_t argc, const napi_value argv[],
1696 unique_ptr<MediaAssetManagerAsyncContext> &context)
1697 {
1698 CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_THREE), "Invalid number of arguments");
1699
1700 std::string imageFileUri;
1701 CHECK_COND_WITH_MESSAGE(env,
1702 MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[PARAM1], imageFileUri) == napi_ok,
1703 "Failed to parse image file uri");
1704 std::string videoFileUri;
1705 CHECK_COND_WITH_MESSAGE(env,
1706 MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[PARAM2], videoFileUri) == napi_ok,
1707 "Failed to parse video file uri");
1708 std::string uri(imageFileUri + MOVING_PHOTO_URI_SPLIT + videoFileUri);
1709 context->photoUri = uri;
1710 RETURN_NAPI_TRUE(env);
1711 }
1712
JSLoadMovingPhotoComplete(napi_env env, napi_status status, void *data)1713 static void JSLoadMovingPhotoComplete(napi_env env, napi_status status, void *data)
1714 {
1715 MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1716 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1717
1718 MediaLibraryTracer tracer;
1719 tracer.Start("JSLoadMovingPhotoComplete");
1720
1721 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1722 jsContext->status = false;
1723
1724 if (context->error == ERR_DEFAULT) {
1725 napi_value movingPhoto = MovingPhotoNapi::NewMovingPhotoNapi(env, context->photoUri,
1726 SourceMode::EDITED_MODE);
1727 jsContext->data = movingPhoto;
1728 napi_get_undefined(env, &jsContext->error);
1729 jsContext->status = true;
1730 } else {
1731 context->HandleError(env, jsContext->error);
1732 napi_get_undefined(env, &jsContext->data);
1733 }
1734
1735 tracer.Finish();
1736 if (context->work != nullptr) {
1737 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1738 context->work, *jsContext);
1739 }
1740 delete context;
1741 }
1742
JSLoadMovingPhotoExecute(napi_env env, void *data)1743 static void JSLoadMovingPhotoExecute(napi_env env, void *data)
1744 {
1745 }
1746
JSLoadMovingPhoto(napi_env env, napi_callback_info info)1747 napi_value MediaAssetManagerNapi::JSLoadMovingPhoto(napi_env env, napi_callback_info info)
1748 {
1749 unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
1750 CHECK_ARGS(env, napi_get_cb_info(env, info, &(asyncContext->argc), asyncContext->argv, nullptr, nullptr),
1751 JS_INNER_FAIL);
1752 CHECK_NULLPTR_RET(ParseArgsForLoadMovingPhoto(env, asyncContext->argc, asyncContext->argv, asyncContext));
1753 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSLoadMovingPhoto", JSLoadMovingPhotoExecute,
1754 JSLoadMovingPhotoComplete);
1755 }
1756
GetFdFromSandBoxUri(const std::string &sandBoxUri)1757 int32_t MediaAssetManagerNapi::GetFdFromSandBoxUri(const std::string &sandBoxUri)
1758 {
1759 AppFileService::ModuleFileUri::FileUri destUri(sandBoxUri);
1760 string destPath = destUri.GetRealPath();
1761 if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
1762 NAPI_DEBUG_LOG("Create empty dest file in sandbox failed, path:%{private}s", destPath.c_str());
1763 return E_ERR;
1764 }
1765 string absDestPath;
1766 if (!PathToRealPath(destPath, absDestPath)) {
1767 NAPI_DEBUG_LOG("PathToRealPath failed, path:%{private}s", destPath.c_str());
1768 return E_ERR;
1769 }
1770 return MediaFileUtils::OpenFile(absDestPath, MEDIA_FILEMODE_WRITETRUNCATE);
1771 }
1772
CreateDataHandlerRef(napi_env env, const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)1773 napi_status MediaAssetManagerNapi::CreateDataHandlerRef(napi_env env,
1774 const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)
1775 {
1776 napi_status status = napi_create_reference(env, context->dataHandler, PARAM1, &dataHandlerRef);
1777 if (status != napi_ok) {
1778 dataHandlerRef = nullptr;
1779 NAPI_ERR_LOG("napi_create_reference failed");
1780 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "napi_create_reference fail");
1781 }
1782 return status;
1783 }
1784
CreateProgressHandlerRef(napi_env env, const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)1785 napi_status MediaAssetManagerNapi::CreateProgressHandlerRef(napi_env env,
1786 const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)
1787 {
1788 napi_status status = napi_create_reference(env, context->mediaAssetProgressHandler, PARAM1, &dataHandlerRef);
1789 if (status != napi_ok) {
1790 dataHandlerRef = nullptr;
1791 NAPI_ERR_LOG("napi_create_reference failed");
1792 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "napi_create_reference fail");
1793 }
1794 return status;
1795 }
1796
CreateOnDataPreparedThreadSafeFunc(napi_env env, const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &threadSafeFunc)1797 napi_status MediaAssetManagerNapi::CreateOnDataPreparedThreadSafeFunc(napi_env env,
1798 const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &threadSafeFunc)
1799 {
1800 NAPI_DEBUG_LOG("CreateOnDataPreparedThreadSafeFunc");
1801 napi_value workName = nullptr;
1802 napi_create_string_utf8(env, "Data Prepared", NAPI_AUTO_LENGTH, &workName);
1803 napi_status status = napi_create_threadsafe_function(env, context->dataHandler, NULL, workName, 0, 1,
1804 NULL, NULL, NULL, MediaAssetManagerNapi::OnDataPrepared, &threadSafeFunc);
1805 if (status != napi_ok) {
1806 NAPI_ERR_LOG("napi_create_threadsafe_function fail");
1807 threadSafeFunc = nullptr;
1808 NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
1809 }
1810 return status;
1811 }
1812
CreateOnProgressThreadSafeFunc(napi_env env, unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &progressFunc)1813 napi_status MediaAssetManagerNapi::CreateOnProgressThreadSafeFunc(napi_env env,
1814 unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &progressFunc)
1815 {
1816 napi_value workName = nullptr;
1817 napi_create_string_utf8(env, "ProgressThread", NAPI_AUTO_LENGTH, &workName);
1818 napi_status status = napi_create_threadsafe_function(env, context->mediaAssetProgressHandler, NULL, workName, 0, 1,
1819 NULL, NULL, NULL, MediaAssetManagerNapi::OnProgress, &progressFunc);
1820 if (status != napi_ok) {
1821 NAPI_ERR_LOG("napi_create_threadsafe_function fail");
1822 progressFunc = nullptr;
1823 NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
1824 }
1825 return status;
1826 }
1827
JSRequestExecute(napi_env env, void *data)1828 void MediaAssetManagerNapi::JSRequestExecute(napi_env env, void *data)
1829 {
1830 MediaLibraryTracer tracer;
1831 tracer.Start("JSRequestExecute");
1832 MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1833 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1834 OnHandleRequestImage(env, context);
1835 if (context->subType == PhotoSubType::MOVING_PHOTO) {
1836 string uri = LOG_MOVING_PHOTO;
1837 Uri logMovingPhotoUri(uri);
1838 DataShare::DataShareValuesBucket valuesBucket;
1839 string result;
1840 valuesBucket.Put("adapted", context->returnDataType == ReturnDataType::TYPE_MOVING_PHOTO);
1841 UserFileClient::InsertExt(logMovingPhotoUri, valuesBucket, result);
1842 }
1843 }
1844
JSRequestVideoFileExecute(napi_env env, void *data)1845 void MediaAssetManagerNapi::JSRequestVideoFileExecute(napi_env env, void *data)
1846 {
1847 MediaLibraryTracer tracer;
1848 tracer.Start("JSRequestVideoFileExecute");
1849 MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1850 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1851 OnHandleRequestVideo(env, context);
1852 OnHandleProgress(env, context);
1853 }
1854
JSRequestComplete(napi_env env, napi_status, void *data)1855 void MediaAssetManagerNapi::JSRequestComplete(napi_env env, napi_status, void *data)
1856 {
1857 MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1858 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1859 if (context->dataHandlerRef != nullptr) {
1860 napi_delete_reference(env, context->dataHandlerRef);
1861 context->dataHandlerRef = nullptr;
1862 }
1863 if (context->dataHandlerRef2 != nullptr) {
1864 napi_delete_reference(env, context->dataHandlerRef2);
1865 context->dataHandlerRef2 = nullptr;
1866 }
1867
1868 MediaLibraryTracer tracer;
1869 tracer.Start("JSRequestComplete");
1870
1871 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1872 jsContext->status = false;
1873 if (context->assetHandler) {
1874 NotifyMediaDataPrepared(context->assetHandler);
1875 context->assetHandler = nullptr;
1876 }
1877 if (context->error == ERR_DEFAULT) {
1878 napi_value requestId;
1879 napi_create_string_utf8(env, context->requestId.c_str(), NAPI_AUTO_LENGTH, &requestId);
1880 jsContext->data = requestId;
1881 napi_get_undefined(env, &jsContext->error);
1882 jsContext->status = true;
1883 } else {
1884 context->HandleError(env, jsContext->error);
1885 napi_get_undefined(env, &jsContext->data);
1886 }
1887
1888 if (context->work != nullptr) {
1889 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1890 context->work, *jsContext);
1891 }
1892 delete context;
1893 }
1894
JSCancelRequestExecute(napi_env env, void *data)1895 void MediaAssetManagerNapi::JSCancelRequestExecute(napi_env env, void *data)
1896 {
1897 MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1898 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1899 MediaAssetManagerNapi::CancelProcessImage(context->photoId);
1900 }
1901
JSCancelRequestComplete(napi_env env, napi_status, void *data)1902 void MediaAssetManagerNapi::JSCancelRequestComplete(napi_env env, napi_status, void *data)
1903 {
1904 MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1905 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1906
1907 MediaLibraryTracer tracer;
1908 tracer.Start("JSCancelRequestComplete");
1909
1910 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1911 jsContext->status = false;
1912
1913 if (context->error == ERR_DEFAULT) {
1914 napi_get_undefined(env, &jsContext->error);
1915 jsContext->status = true;
1916 } else {
1917 context->HandleError(env, jsContext->error);
1918 }
1919 napi_get_undefined(env, &jsContext->data);
1920
1921 if (context->work != nullptr) {
1922 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1923 context->work, *jsContext);
1924 }
1925 delete context;
1926 }
1927 } // namespace Media
1928 } // namespace OHOS