1 /*
2 * Copyright (C) 2025 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 #include "media_library_ani.h"
17
18 #include <string>
19 #include <array>
20 #include <mutex>
21 #include "ani.h"
22 #include "ani_class_name.h"
23 #include "medialibrary_ani_log.h"
24 #include "medialibrary_tracer.h"
25 #include "userfile_client.h"
26 #include "vision_column.h"
27 #include "story_album_column.h"
28 #include "media_change_request_ani.h"
29 #include "medialibrary_ani_utils.h"
30 #include "directory_ex.h"
31 #include "medialibrary_db_const.h"
32 #include "medialibrary_errno.h"
33 #include "medialibrary_ani_enum_comm.h"
34 #include "media_file_utils.h"
35 #include "media_file_uri.h"
36 #include "media_ani_native_impl.h"
37 #include "datashare_predicates.h"
38 #include "userfilemgr_uri.h"
39 #include "datashare_helper.h"
40 #include "safe_map.h"
41 #include "ani_error.h"
42 #include "album_operation_uri.h"
43
44 #define MEDIALIBRARY_COMPATIBILITY
45
46 using namespace OHOS::DataShare;
47
48 namespace OHOS {
49 namespace Media {
50 std::mutex MediaLibraryAni::sUserFileClientMutex_;
51 thread_local std::unique_ptr<ChangeListenerAni> g_listObj = nullptr;
52
53 static SafeMap<int32_t, std::shared_ptr<ThumbnailBatchGenerateObserver>> thumbnailGenerateObserverMap;
54 static SafeMap<int32_t, std::shared_ptr<ThumbnailGenerateHandler>> thumbnailGenerateHandlerMap;
55 static std::atomic<int32_t> requestIdCounter_ = 0;
56 static std::atomic<int32_t> requestIdCallback_ = 0;
57
58 const int32_t SECOND_ENUM = 2;
59 const int32_t THIRD_ENUM = 3;
60
PhotoAccessHelperInit(ani_env * env)61 ani_status MediaLibraryAni::PhotoAccessHelperInit(ani_env *env)
62 {
63 static const char *className = ANI_CLASS_PHOTO_ACCESS_HELPER.c_str();
64 ani_class cls;
65 ani_status status = env->FindClass(className, &cls);
66 if (status != ANI_OK) {
67 ANI_ERR_LOG("Failed to find class: %{public}s", className);
68 return status;
69 }
70
71 std::array methods = {
72 ani_native_function {"getAlbumsInner", nullptr, reinterpret_cast<void *>(GetPhotoAlbums)},
73 ani_native_function {"release", nullptr, reinterpret_cast<void *>(Release)},
74 ani_native_function {"applyChanges", nullptr, reinterpret_cast<void *>(ApplyChanges)},
75 ani_native_function {"createAsset1", nullptr, reinterpret_cast<void *>(createAsset1)},
76 ani_native_function {"getAssetsSync", nullptr, reinterpret_cast<void *>(GetAssetsSync)},
77 ani_native_function {"getFileAssetsInfo", nullptr, reinterpret_cast<void *>(GetFileAssetsInfo)},
78 ani_native_function {"getAssetsInner", nullptr, reinterpret_cast<void *>(GetAssetsInner)},
79 ani_native_function {"stopThumbnailCreationTask", nullptr,
80 reinterpret_cast<void *>(PhotoAccessStopCreateThumbnailTask)},
81 ani_native_function {"startCreateThumbnailTask", nullptr,
82 reinterpret_cast<void *>(PhotoAccessStartCreateThumbnailTask)},
83 };
84
85 status = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
86 if (status != ANI_OK) {
87 ANI_ERR_LOG("Failed to bind native methods to: %{public}s", className);
88 return status;
89 }
90
91 ANI_INFO_LOG("PhotoAccessHelperInit ok");
92 return ANI_OK;
93 }
94
ParseArgsStartCreateThumbnailTask(ani_env * env,ani_object object,ani_object predicate,ani_object callback,unique_ptr<MediaLibraryAsyncContext> & context)95 static ani_status ParseArgsStartCreateThumbnailTask(ani_env *env, ani_object object, ani_object predicate,
96 ani_object callback, unique_ptr<MediaLibraryAsyncContext> &context)
97 {
98 if (!MediaLibraryAniUtils::IsSystemApp()) {
99 AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
100 return ANI_ERROR;
101 }
102
103 context->objectInfo = MediaLibraryAni::Unwrap(env, object);
104 CHECK_COND_RET(context->objectInfo != nullptr, ANI_INVALID_ARGS, "objectInfo is nullptr");
105 // get callback function
106 if (callback != nullptr) {
107 context->callback = callback;
108 }
109
110 CHECK_STATUS_RET(MediaLibraryAniUtils::ParsePredicates(env, predicate, context, ASSET_FETCH_OPT),
111 "invalid predicate");
112 return ANI_OK;
113 }
114
RegisterThumbnailGenerateObserver(ani_env * env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)115 static void RegisterThumbnailGenerateObserver(ani_env *env,
116 std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
117 {
118 std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
119 if (thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
120 ANI_INFO_LOG("RequestId: %{public}d exist in observer map, no need to register", requestId);
121 return;
122 }
123 dataObserver = std::make_shared<ThumbnailBatchGenerateObserver>();
124 std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
125 UserFileClient::RegisterObserverExt(Uri(observerUri), dataObserver, false);
126 thumbnailGenerateObserverMap.Insert(requestId, dataObserver);
127 }
128
UnregisterThumbnailGenerateObserver(int32_t requestId)129 static void UnregisterThumbnailGenerateObserver(int32_t requestId)
130 {
131 std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
132 if (!thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
133 ANI_DEBUG_LOG("UnregisterThumbnailGenerateObserver with RequestId: %{public}d not exist in observer map",
134 requestId);
135 return;
136 }
137
138 std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
139 UserFileClient::UnregisterObserverExt(Uri(observerUri), dataObserver);
140 thumbnailGenerateObserverMap.Erase(requestId);
141 }
142
DeleteThumbnailHandler(int32_t requestId)143 static void DeleteThumbnailHandler(int32_t requestId)
144 {
145 std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
146 if (!thumbnailGenerateHandlerMap.Find(requestId, dataHandler)) {
147 ANI_DEBUG_LOG("DeleteThumbnailHandler with RequestId: %{public}d not exist in handler map", requestId);
148 return;
149 }
150 thumbnailGenerateHandlerMap.Erase(requestId);
151 }
152
ReleaseThumbnailTask(int32_t requestId)153 static void ReleaseThumbnailTask(int32_t requestId)
154 {
155 UnregisterThumbnailGenerateObserver(requestId);
156 DeleteThumbnailHandler(requestId);
157 }
158
CreateThumbnailHandler(ani_env * env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)159 static void CreateThumbnailHandler(ani_env *env, std::unique_ptr<MediaLibraryAsyncContext> &asyncContext,
160 int32_t requestId)
161 {
162 ani_object callback = asyncContext->callback;
163 ThreadFunciton threadSafeFunc = MediaLibraryAni::OnThumbnailGenerated;
164
165 std::shared_ptr<ThumbnailGenerateHandler> dataHandler =
166 std::make_shared<ThumbnailGenerateHandler>(callback, threadSafeFunc);
167 thumbnailGenerateHandlerMap.Insert(requestId, dataHandler);
168 }
169
OnThumbnailGenerated(ani_env * env,ani_object callback,void * context,void * data)170 void MediaLibraryAni::OnThumbnailGenerated(ani_env *env, ani_object callback, void *context, void *data)
171 {
172 if (env == nullptr) {
173 return;
174 }
175 std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
176 if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
177 return;
178 }
179
180 // calling onDataPrepared
181 ani_vm *etsVm;
182 ani_env *etsEnv;
183 [[maybe_unused]] int res = env->GetVM(&etsVm);
184 if (res != ANI_OK) {
185 return;
186 }
187 ani_option interopEnabled {"--interop=disable", nullptr};
188 ani_options aniArgs {1, &interopEnabled};
189 if (ANI_OK != etsVm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &etsEnv)) {
190 return;
191 }
192 auto fnObject = reinterpret_cast<ani_fn_object>(static_cast<ani_ref>(callback));
193 const std::string str = "AsyncWorkName:ThumbSafeThread";
194 ani_string arg1 = {};
195 if (ANI_OK != etsEnv->String_NewUTF8(str.c_str(), str.size(), &arg1)) {
196 return;
197 }
198 std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(arg1)};
199
200 ani_ref result;
201 if (ANI_OK != etsEnv->FunctionalObject_Call(fnObject, args.size(), args.data(), &result)) {
202 return;
203 }
204 if (ANI_OK != etsVm->DetachCurrentThread()) {
205 return;
206 }
207 }
208
AssignRequestId()209 static int32_t AssignRequestId()
210 {
211 return ++requestIdCounter_;
212 }
213
GetRequestId()214 static int32_t GetRequestId()
215 {
216 return requestIdCounter_;
217 }
218
PhotoAccessStartCreateThumbnailTask(ani_env * env,ani_object object,ani_object predicate)219 ani_int MediaLibraryAni::PhotoAccessStartCreateThumbnailTask([[maybe_unused]] ani_env *env,
220 [[maybe_unused]] ani_object object, ani_object predicate)
221 {
222 ani_object callback = nullptr;
223 std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
224 CHECK_COND_WITH_RET_MESSAGE(env,
225 ParseArgsStartCreateThumbnailTask(env, object, predicate, callback, asyncContext) == ANI_OK,
226 ANI_INVALID_ARGS, "ParseArgsStartCreateThumbnailTask error");
227
228 ReleaseThumbnailTask(GetRequestId());
229 int32_t requestId = AssignRequestId();
230 RegisterThumbnailGenerateObserver(env, asyncContext, requestId);
231 CreateThumbnailHandler(env, asyncContext, requestId);
232
233 DataShare::DataShareValuesBucket valuesBucket;
234 valuesBucket.Put(THUMBNAIL_BATCH_GENERATE_REQUEST_ID, requestId);
235 string updateUri = PAH_START_GENERATE_THUMBNAILS;
236 MediaLibraryAniUtils::UriAppendKeyValue(updateUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
237 Uri uri(updateUri);
238 int changedRows = UserFileClient::Update(uri, asyncContext->predicates, valuesBucket);
239 if (changedRows < 0) {
240 ReleaseThumbnailTask(requestId);
241 asyncContext->SaveError(changedRows);
242 ANI_ERR_LOG("Create thumbnail task, update failed, err: %{public}d", changedRows);
243 return changedRows;
244 }
245 return requestId;
246 }
247
OnChange(const ChangeInfo & changeInfo)248 void ThumbnailBatchGenerateObserver::OnChange(const ChangeInfo &changeInfo)
249 {
250 if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_THUMB_ADD)) {
251 return;
252 }
253
254 for (auto &uri : changeInfo.uris_) {
255 string uriString = uri.ToString();
256 auto pos = uriString.find_last_of('/');
257 if (pos == std::string::npos) {
258 continue;
259 }
260
261 try {
262 requestIdCallback_ = std::stoi(uriString.substr(pos + 1));
263 } catch (const std::invalid_argument& e) {
264 ANI_ERR_LOG("Invalid argument: %{public}s", e.what());
265 continue;
266 } catch (const std::out_of_range& e) {
267 ANI_ERR_LOG("Out of range: %{public}s", e.what());
268 continue;
269 }
270
271 std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
272 if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
273 continue;
274 }
275 // napi_call_threadsafe_function
276 }
277 }
278
ParseArgsStopCreateThumbnailTask(ani_env * env,ani_object object,unique_ptr<MediaLibraryAsyncContext> & context)279 static ani_status ParseArgsStopCreateThumbnailTask(ani_env *env, ani_object object,
280 unique_ptr<MediaLibraryAsyncContext> &context)
281 {
282 if (!MediaLibraryAniUtils::IsSystemApp()) {
283 AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
284 return ANI_ERROR;
285 }
286
287 context->objectInfo = MediaLibraryAni::Unwrap(env, object);
288 CHECK_COND_RET(context->objectInfo != nullptr, ANI_INVALID_ARGS, "objectInfo is nullptr");
289 return ANI_OK;
290 }
291
PhotoAccessStopCreateThumbnailTask(ani_env * env,ani_object object,ani_double taskId)292 void MediaLibraryAni::PhotoAccessStopCreateThumbnailTask([[maybe_unused]] ani_env *env,
293 [[maybe_unused]] ani_object object, ani_double taskId)
294 {
295 ANI_DEBUG_LOG("PhotoAccessStopCreateThumbnailTask with taskId: %{public}d", static_cast<int32_t>(taskId));
296 std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
297
298 if (ParseArgsStopCreateThumbnailTask(env, object, asyncContext) != ANI_OK) {
299 ANI_ERR_LOG("ParseArgsStopCreateThumbnailTask error");
300 return;
301 }
302
303 int32_t requestId = static_cast<int32_t>(taskId);
304 if (requestId <= 0) {
305 ANI_ERR_LOG("PhotoAccessStopCreateThumbnailTask with Invalid requestId: %{public}d", requestId);
306 return;
307 }
308
309 ReleaseThumbnailTask(requestId);
310
311 DataShare::DataShareValuesBucket valuesBucket;
312 valuesBucket.Put(THUMBNAIL_BATCH_GENERATE_REQUEST_ID, requestId);
313 string updateUri = PAH_STOP_GENERATE_THUMBNAILS;
314 MediaLibraryAniUtils::UriAppendKeyValue(updateUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
315 Uri uri(updateUri);
316 int changedRows = UserFileClient::Update(uri, asyncContext->predicates, valuesBucket);
317 if (changedRows < 0) {
318 asyncContext->SaveError(changedRows);
319 ANI_ERR_LOG("Stop create thumbnail task, update failed, err: %{public}d", changedRows);
320 }
321 ANI_DEBUG_LOG("MediaLibraryAni::PhotoAccessStopCreateThumbnailTask Finished");
322 }
323
GetFileAssetsInfo(ani_env * env,ani_object object,ani_object options)324 ani_object MediaLibraryAni::GetFileAssetsInfo([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object,
325 ani_object options)
326 {
327 MediaLibraryTracer tracer;
328 tracer.Start("GetFileAssetsInfo");
329 ANI_DEBUG_LOG("GetFileAssetsInfo start");
330
331 ani_ref fetchColumns;
332 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "fetchColumns", &fetchColumns)) {
333 ANI_ERR_LOG("get fieldname fetchCloumns failed");
334 return nullptr;
335 }
336 std::vector<std::string> fetchColumnsVec;
337 if (ANI_OK != MediaLibraryAniUtils::GetStringArray(env, (ani_object)fetchColumns, fetchColumnsVec)) {
338 ANI_ERR_LOG("GetStringArray failed");
339 return nullptr;
340 }
341
342 ani_ref predicates;
343 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "predicates", &predicates)) {
344 ANI_ERR_LOG("get fieldname predicates failed");
345 return nullptr;
346 }
347 DataSharePredicates* predicate = MediaLibraryAniUtils::UnwrapPredicate(env, (ani_object)predicates);
348 if (predicate == nullptr) {
349 ANI_ERR_LOG("UnwrapPredicate failed");
350 return nullptr;
351 }
352
353 std::vector<std::unique_ptr<FileAsset>> fileAssetArray = MediaAniNativeImpl::GetFileAssetsInfo(fetchColumnsVec,
354 predicate);
355
356 ani_object result = nullptr;
357 if (ANI_OK != MediaLibraryAniUtils::ToFileAssetInfoAniArray(env, fileAssetArray, result)) {
358 ANI_ERR_LOG("MediaLibraryAniUtils::ToFileAssetInfoAniArray failed");
359 }
360
361 ANI_DEBUG_LOG("GetFileAssetsInfo end");
362 return result;
363 }
364
GetAssetsSync(ani_env * env,ani_object object,ani_object options)365 ani_object MediaLibraryAni::GetAssetsSync([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object,
366 ani_object options)
367 {
368 MediaLibraryTracer tracer;
369 tracer.Start("GetAssetsSync");
370 ANI_DEBUG_LOG("GetAssetsSync start");
371
372 ani_ref fetchColumns;
373 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "fetchColumns", &fetchColumns)) {
374 ANI_ERR_LOG("get fieldname fetchCloumns failed");
375 return nullptr;
376 }
377 std::vector<std::string> fetchColumnsVec;
378 if (ANI_OK != MediaLibraryAniUtils::GetStringArray(env, (ani_object)fetchColumns, fetchColumnsVec)) {
379 ANI_ERR_LOG("GetStringArray failed");
380 return nullptr;
381 }
382
383 ani_ref predicates;
384 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "predicates", &predicates)) {
385 ANI_ERR_LOG("get fieldname predicates failed");
386 return nullptr;
387 }
388 DataSharePredicates* predicate = MediaLibraryAniUtils::UnwrapPredicate(env, (ani_object)predicates);
389 if (predicate == nullptr) {
390 ANI_ERR_LOG("UnwrapPredicate failed");
391 return nullptr;
392 }
393 std::vector<std::unique_ptr<FileAsset>> fileAssetArray = MediaAniNativeImpl::GetAssetsSync(fetchColumnsVec,
394 predicate);
395
396 ani_object result = nullptr;
397 if (ANI_OK != MediaLibraryAniUtils::ToFileAssetAniArray(env, fileAssetArray, result)) {
398 ANI_ERR_LOG("MediaLibraryAniUtils::ToFileAssetAniArray failed");
399 }
400
401 ANI_DEBUG_LOG("GetAssetsSync end");
402 return result;
403 }
404
GetAssetsInner(ani_env * env,ani_object object,ani_object options)405 ani_object MediaLibraryAni::GetAssetsInner([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object,
406 ani_object options)
407 {
408 MediaLibraryTracer tracer;
409 tracer.Start("GetAssets");
410 ANI_DEBUG_LOG("GetAssetsInner start");
411
412 ani_ref fetchColumns;
413 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "fetchColumns", &fetchColumns)) {
414 ANI_ERR_LOG("get fieldname fetchCloumns failed");
415 return nullptr;
416 }
417 std::vector<std::string> fetchColumnsVec;
418 if (ANI_OK != MediaLibraryAniUtils::GetStringArray(env, (ani_object)fetchColumns, fetchColumnsVec)) {
419 ANI_ERR_LOG("GetStringArray failed");
420 return nullptr;
421 }
422
423 ani_ref predicates;
424 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, "predicates", &predicates)) {
425 ANI_ERR_LOG("get fieldname predicates failed");
426 return nullptr;
427 }
428 DataSharePredicates* predicate = MediaLibraryAniUtils::UnwrapPredicate(env, (ani_object)predicates);
429 if (predicate == nullptr) {
430 ANI_ERR_LOG("UnwrapPredicate failed");
431 return nullptr;
432 }
433 std::unique_ptr<FetchResult<FileAsset>> fileAsset = MediaAniNativeImpl::GetAssets(fetchColumnsVec, predicate);
434
435 ani_object result = nullptr;
436 if (ANI_OK != MediaLibraryAniUtils::ToFileAssetAniPtr(env, std::move(fileAsset), result)) {
437 ANI_ERR_LOG("MediaLibraryAniUtils::ToFileAssetAniPtr failed");
438 }
439
440 ANI_DEBUG_LOG("GetAssetsInner end");
441 return result;
442 }
443
InitUserFileClient(ani_env * env,ani_object context,bool isAsync=false)444 bool InitUserFileClient(ani_env *env, [[maybe_unused]] ani_object context, bool isAsync = false)
445 {
446 if (isAsync) {
447 std::unique_lock<std::mutex> helperLock(MediaLibraryAni::sUserFileClientMutex_);
448 if (!UserFileClient::IsValid()) {
449 UserFileClient::Init(env, context);
450 if (!UserFileClient::IsValid()) {
451 ANI_ERR_LOG("UserFileClient creation failed");
452 helperLock.unlock();
453 return false;
454 }
455 }
456 helperLock.unlock();
457 }
458 return true;
459 }
460
Constructor(ani_env * env,ani_object context)461 ani_object MediaLibraryAni::Constructor(ani_env *env, ani_object context)
462 {
463 ANI_INFO_LOG("getPhotoAccessHelper start");
464 if (context == nullptr) {
465 ANI_ERR_LOG("context is nullptr");
466 return nullptr;
467 }
468
469 ani_object result = nullptr;
470 MediaLibraryTracer tracer;
471 tracer.Start("PhotoAcessHelperAniConstructor");
472 std::unique_ptr<MediaLibraryAni> nativeHandle = std::make_unique<MediaLibraryAni>();
473
474 nativeHandle->env_ = env;
475 // Initialize the ChangeListener object
476 if (g_listObj == nullptr) {
477 g_listObj = std::make_unique<ChangeListenerAni>(env);
478 }
479
480 bool isAsync = true;
481 if (!InitUserFileClient(env, context, isAsync)) {
482 ANI_ERR_LOG("Constructor InitUserFileClient failed");
483 return result;
484 }
485
486 static const char *className = ANI_CLASS_PHOTO_ACCESS_HELPER.c_str();
487 ani_class cls;
488 if (ANI_OK != env->FindClass(className, &cls)) {
489 ANI_ERR_LOG("Failed to find class: %{public}s", className);
490 return result;
491 }
492
493 ani_method ctor;
494 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "J:V", &ctor)) {
495 ANI_ERR_LOG("Failed to find method: %{public}s", "ctor");
496 return result;
497 }
498
499 if (ANI_OK !=env->Object_New(cls, ctor, &result, reinterpret_cast<ani_long>(nativeHandle.release()))) {
500 ANI_ERR_LOG("New PhotoAccessHelper Fail");
501 }
502 return result;
503 }
504
Unwrap(ani_env * env,ani_object object)505 MediaLibraryAni* MediaLibraryAni::Unwrap(ani_env *env, ani_object object)
506 {
507 ani_long photoAccessHelper;
508 if (ANI_OK != env->Object_GetFieldByName_Long(object, "nativePhotoAccessHelper", &photoAccessHelper)) {
509 return nullptr;
510 }
511 return reinterpret_cast<MediaLibraryAni*>(photoAccessHelper);
512 }
513
ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> & context,const int32_t albumSubType)514 static bool ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> &context, const int32_t albumSubType)
515 {
516 if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
517 context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
518 context->fetchColumn.insert(context->fetchColumn.end(),
519 PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
520 PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
521 MediaLibraryAniUtils::GetAllLocationPredicates(context->predicates);
522 return false;
523 } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
524 context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
525 context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
526 string onClause = PhotoAlbumColumns::ALBUM_NAME + " = " + CITY_ID;
527 context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
528 context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
529 }
530 return true;
531 }
532
ParseAlbumTypes(ani_env * env,ani_enum_item albumTypeItem,ani_enum_item albumSubtype,std::unique_ptr<MediaLibraryAsyncContext> & context)533 static ani_status ParseAlbumTypes(ani_env *env, ani_enum_item albumTypeItem, ani_enum_item albumSubtype,
534 std::unique_ptr<MediaLibraryAsyncContext>& context)
535 {
536 /* Parse the first argument to photo album type */
537 AlbumType albumType;
538 int32_t albumTypeInt;
539 CHECK_COND_WITH_RET_MESSAGE(env, MediaLibraryEnumAni::EnumGetValueInt32(env, albumTypeItem,
540 albumTypeInt) == ANI_OK, ANI_INVALID_ARGS, "Failed to get albumType");
541 albumType = static_cast<AlbumType>(albumTypeInt);
542 if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumTypeInt))) {
543 AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
544 return ANI_ERROR;
545 }
546 context->isAnalysisAlbum = (albumTypeInt == PhotoAlbumType::SMART) ? 1 : 0;
547
548 /* Parse the second argument to photo album subType */
549 PhotoAlbumSubType photoAlbumSubType;
550 int32_t albumSubTypeInt;
551 CHECK_COND_WITH_RET_MESSAGE(env, MediaLibraryEnumAni::EnumGetValueInt32(env, albumSubtype,
552 albumSubTypeInt) == ANI_OK, ANI_INVALID_ARGS, "Failed to get albumSubtype");
553 photoAlbumSubType = static_cast<PhotoAlbumSubType>(albumSubTypeInt);
554 if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubTypeInt))) {
555 AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
556 return ANI_ERROR;
557 }
558
559 if (!ParseLocationAlbumTypes(context, albumSubTypeInt)) {
560 return ANI_OK;
561 }
562
563 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumTypeInt));
564 if (albumSubTypeInt != ANY) {
565 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubTypeInt));
566 }
567 if (albumSubTypeInt == PhotoAlbumSubType::SHOOTING_MODE || albumSubTypeInt == PhotoAlbumSubType::GEOGRAPHY_CITY) {
568 context->predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
569 }
570 if (albumSubTypeInt == PhotoAlbumSubType::HIGHLIGHT ||
571 albumSubTypeInt == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
572 context->isHighlightAlbum = albumSubTypeInt;
573 vector<string> onClause = {
574 ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
575 HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
576 };
577 context->predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
578 context->predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
579 }
580
581 return ANI_OK;
582 }
583
RestrictAlbumSubtypeOptions(unique_ptr<MediaLibraryAsyncContext> & context)584 static void RestrictAlbumSubtypeOptions(unique_ptr<MediaLibraryAsyncContext> &context)
585 {
586 if (!MediaLibraryAniUtils::IsSystemApp()) {
587 context->predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
588 to_string(PhotoAlbumSubType::USER_GENERIC),
589 to_string(PhotoAlbumSubType::FAVORITE),
590 to_string(PhotoAlbumSubType::VIDEO),
591 to_string(PhotoAlbumSubType::IMAGE),
592 }));
593 } else {
594 context->predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
595 }
596 }
597
AddDefaultPhotoAlbumColumns(ani_env * env,vector<string> & fetchColumn)598 static ani_status AddDefaultPhotoAlbumColumns(ani_env *env, vector<string> &fetchColumn)
599 {
600 auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
601 for (const auto &column : fetchColumn) {
602 if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
603 validFetchColumns.insert(column);
604 } else if (column.compare(MEDIA_DATA_DB_URI) == 0) {
605 // uri is default property of album
606 continue;
607 } else {
608 ANI_ERR_LOG("unknown columns:%{public}s", column.c_str());
609 AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
610 return ANI_ERROR;
611 }
612 }
613 fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
614 return ANI_OK;
615 }
616
AddDefaultColumnsForNonAnalysisAlbums(MediaLibraryAsyncContext & context)617 static void AddDefaultColumnsForNonAnalysisAlbums(MediaLibraryAsyncContext& context)
618 {
619 if (!context.isAnalysisAlbum) {
620 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
621 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
622 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_LPATH);
623 }
624 }
625
GetAlbumFetchOption(ani_env * env,unique_ptr<MediaLibraryAsyncContext> & context,ani_object fetchOptions)626 static ani_status GetAlbumFetchOption(ani_env *env, unique_ptr<MediaLibraryAsyncContext> &context,
627 ani_object fetchOptions)
628 {
629 CHECK_COND_WITH_RET_MESSAGE(env, MediaLibraryAniUtils::GetFetchOption(env, fetchOptions,
630 ALBUM_FETCH_OPT, context) == ANI_OK, ANI_INVALID_ARGS, "GetAlbumFetchOption error");
631 if (!context->uri.empty()) {
632 if (context->uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != std::string::npos) {
633 context->isAnalysisAlbum = 1; // 1:is an analysis album
634 }
635 }
636 return ANI_OK;
637 }
638
639
ParseArgsGetPhotoAlbum(ani_env * env,ani_enum_item albumTypeItem,ani_enum_item albumSubtypeItem,ani_object fetchOptions,std::unique_ptr<MediaLibraryAsyncContext> & context)640 static ani_status ParseArgsGetPhotoAlbum(ani_env *env, ani_enum_item albumTypeItem, ani_enum_item albumSubtypeItem,
641 ani_object fetchOptions, std::unique_ptr<MediaLibraryAsyncContext>& context)
642 {
643 // Parse fetchOptions if exists.
644 ani_boolean isUndefined;
645 env->Reference_IsUndefined(fetchOptions, &isUndefined);
646 if (!isUndefined) {
647 CHECK_COND_WITH_RET_MESSAGE(env, GetAlbumFetchOption(env, context, fetchOptions) == ANI_OK,
648 ANI_INVALID_ARGS, "GetAlbumFetchOption error");
649 } else {
650 ANI_INFO_LOG("fetchOptions is undefined. There is no need to parse fetchOptions.");
651 }
652 // Parse albumType and albumSubtype
653 CHECK_COND_WITH_RET_MESSAGE(env, ParseAlbumTypes(env, albumTypeItem, albumSubtypeItem,
654 context) == ANI_OK, ANI_INVALID_ARGS, "ParseAlbumTypes error");
655 RestrictAlbumSubtypeOptions(context);
656 if (context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
657 context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
658 CHECK_COND_WITH_RET_MESSAGE(env, AddDefaultPhotoAlbumColumns(env, context->fetchColumn) == ANI_OK,
659 ANI_INVALID_ARGS, "AddDefaultPhotoAlbumColumns error");
660 AddDefaultColumnsForNonAnalysisAlbums(*context);
661 if (context->isHighlightAlbum) {
662 context->fetchColumn.erase(std::remove(context->fetchColumn.begin(), context->fetchColumn.end(),
663 PhotoAlbumColumns::ALBUM_ID), context->fetchColumn.end());
664 context->fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
665 PhotoAlbumColumns::ALBUM_ID);
666 }
667 }
668 return ANI_OK;
669 }
670
GetPhotoAlbumsExecute(ani_env * env,unique_ptr<MediaLibraryAsyncContext> & context)671 static void GetPhotoAlbumsExecute(ani_env *env, unique_ptr<MediaLibraryAsyncContext> &context)
672 {
673 MediaLibraryTracer tracer;
674 tracer.Start("GetPhotoAlbumsExecute");
675
676 string queryUri;
677 if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
678 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
679 UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
680 } else if (context->isAnalysisAlbum) {
681 queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
682 PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
683 } else {
684 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
685 UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
686 }
687 Uri uri(queryUri);
688 int errCode = 0;
689 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
690 if (resultSet == nullptr) {
691 ANI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
692 if (errCode == E_PERMISSION_DENIED) {
693 context->SaveError(E_PERMISSION_DENIED);
694 } else {
695 context->SaveError(E_HAS_DB_ERROR);
696 }
697 return;
698 }
699
700 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
701 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
702 context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
703 context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
704 PhotoAlbumSubType::GEOGRAPHY_LOCATION);
705 }
706
GetPhotoAlbumsComplete(ani_env * env,unique_ptr<MediaLibraryAsyncContext> & context)707 static ani_object GetPhotoAlbumsComplete(ani_env *env, unique_ptr<MediaLibraryAsyncContext> &context)
708 {
709 MediaLibraryTracer tracer;
710 tracer.Start("GetPhotoAlbumsComplete");
711
712 ani_object fetchRes {};
713 ani_object errorObj {};
714 if (context->error != ERR_DEFAULT || context->fetchPhotoAlbumResult == nullptr) {
715 ANI_ERR_LOG("No fetch file result found!");
716 context->HandleError(env, errorObj);
717 } else {
718 fetchRes = FetchFileResultAni::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
719 if (fetchRes == nullptr) {
720 MediaLibraryAniUtils::CreateAniErrorObject(env, errorObj, ERR_MEM_ALLOCATION,
721 "Failed to create ani object for FetchFileResult");
722 }
723 }
724 tracer.Finish();
725 context.reset();
726 return fetchRes;
727 }
728
GetPhotoAlbums(ani_env * env,ani_object object,ani_enum_item albumTypeItem,ani_enum_item albumSubtypeItem,ani_object fetchOptions)729 ani_object MediaLibraryAni::GetPhotoAlbums(ani_env *env, ani_object object, ani_enum_item albumTypeItem,
730 ani_enum_item albumSubtypeItem, ani_object fetchOptions)
731 {
732 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
733 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
734 asyncContext->objectInfo = Unwrap(env, object);
735 CHECK_COND_WITH_RET_MESSAGE(env, ParseArgsGetPhotoAlbum(env, albumTypeItem, albumSubtypeItem,
736 fetchOptions, asyncContext) == ANI_OK, nullptr, "Failed to parse get albums options");
737 GetPhotoAlbumsExecute(env, asyncContext);
738 return(GetPhotoAlbumsComplete(env, asyncContext));
739 }
740
Release(ani_env * env,ani_object object)741 ani_status MediaLibraryAni::Release(ani_env *env, ani_object object)
742 {
743 auto mediaLibraryAni = Unwrap(env, object);
744 if (mediaLibraryAni == nullptr) {
745 ANI_ERR_LOG("mediaLibraryAni is nullptr");
746 return ANI_ERROR;
747 }
748 delete mediaLibraryAni;
749 mediaLibraryAni = nullptr;
750 return ANI_OK;
751 }
752
ApplyChanges(ani_env * env,ani_object object)753 ani_status MediaLibraryAni::ApplyChanges(ani_env *env, ani_object object)
754 {
755 auto* mediaChangeRequestAni = MediaChangeRequestAni::Unwrap(env, object);
756 if (mediaChangeRequestAni == nullptr) {
757 ANI_ERR_LOG("Failed to unwrap MediaChangeRequestAni");
758 return ANI_ERROR;
759 }
760 return mediaChangeRequestAni->ApplyChanges(env, object);
761 }
762
CheckDisplayNameParams(MediaLibraryAsyncContext * context)763 static bool CheckDisplayNameParams(MediaLibraryAsyncContext* context)
764 {
765 if (context == nullptr) {
766 ANI_ERR_LOG("Async context is null");
767 return false;
768 }
769 if (!context->isCreateByComponent) {
770 bool isValid = false;
771 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
772 if (!isValid) {
773 ANI_ERR_LOG("getting displayName is invalid");
774 return false;
775 }
776 if (displayName.empty()) {
777 return false;
778 }
779 }
780
781 return true;
782 }
783
IsDirectory(const string & dirName)784 static bool IsDirectory(const string &dirName)
785 {
786 struct stat statInfo {};
787 if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == E_SUCCESS) {
788 if (statInfo.st_mode & S_IFDIR) {
789 return true;
790 }
791 }
792
793 return false;
794 }
795
GetFirstDirName(const string & relativePath)796 static string GetFirstDirName(const string &relativePath)
797 {
798 string firstDirName = "";
799 if (!relativePath.empty()) {
800 string::size_type pos = relativePath.find_first_of('/');
801 if (pos == relativePath.length()) {
802 return relativePath;
803 }
804 firstDirName = relativePath.substr(0, pos + 1);
805 ANI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
806 }
807 return firstDirName;
808 }
809
CheckTypeOfType(const string & firstDirName,int32_t fileMediaType)810 static bool CheckTypeOfType(const string &firstDirName, int32_t fileMediaType)
811 {
812 // "CDSA/"
813 if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
814 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
815 return true;
816 } else {
817 return false;
818 }
819 }
820 // "Movies/"
821 if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
822 if (fileMediaType == MEDIA_TYPE_VIDEO) {
823 return true;
824 } else {
825 return false;
826 }
827 }
828 if (!strcmp(firstDirName.c_str(), directoryEnumValues[SECOND_ENUM].c_str())) {
829 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
830 return true;
831 } else {
832 ANI_INFO_LOG("CheckTypeOfType RETURN FALSE");
833 return false;
834 }
835 }
836 if (!strcmp(firstDirName.c_str(), directoryEnumValues[THIRD_ENUM].c_str())) {
837 if (fileMediaType == MEDIA_TYPE_AUDIO) {
838 return true;
839 } else {
840 return false;
841 }
842 }
843 return true;
844 }
845
CheckRelativePathParams(MediaLibraryAsyncContext * context)846 static bool CheckRelativePathParams(MediaLibraryAsyncContext *context)
847 {
848 if (context == nullptr) {
849 ANI_ERR_LOG("Async context is null");
850 return false;
851 }
852 bool isValid = false;
853 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
854 if (!isValid) {
855 ANI_DEBUG_LOG("getting relativePath is invalid");
856 return false;
857 }
858 isValid = false;
859 int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
860 if (!isValid) {
861 ANI_DEBUG_LOG("getting fileMediaType is invalid");
862 return false;
863 }
864 if (relativePath.empty()) {
865 return false;
866 }
867
868 if (IsDirectory(relativePath)) {
869 return true;
870 }
871
872 string firstDirName = GetFirstDirName(relativePath);
873 if (!firstDirName.empty() && IsDirectory(firstDirName)) {
874 return true;
875 }
876
877 if (!firstDirName.empty()) {
878 ANI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
879 for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
880 ANI_DEBUG_LOG("directoryEnumValues%{private}d = %{private}s", i, directoryEnumValues[i].c_str());
881 if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
882 return CheckTypeOfType(firstDirName, fileMediaType);
883 }
884 if (!strcmp(firstDirName.c_str(), DOCS_PATH.c_str())) {
885 return true;
886 }
887 }
888 ANI_ERR_LOG("Failed to check relative path, firstDirName = %{private}s", firstDirName.c_str());
889 }
890 return false;
891 }
892
GetCreateUri(MediaLibraryAsyncContext * context,string & uri)893 static void GetCreateUri(MediaLibraryAsyncContext *context, string &uri)
894 {
895 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
896 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
897 switch (context->assetType) {
898 case TYPE_PHOTO:
899 uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
900 ((context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO) :
901 ((context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT : PAH_CREATE_PHOTO);
902 break;
903 case TYPE_AUDIO:
904 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
905 break;
906 default:
907 ANI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
908 return;
909 }
910 MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
911 } else {
912 #ifdef MEDIALIBRARY_COMPATIBILITY
913 bool isValid = false;
914 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
915 if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
916 MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
917 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
918 MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
919 return;
920 }
921 switch (context->assetType) {
922 case TYPE_PHOTO:
923 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
924 break;
925 case TYPE_AUDIO:
926 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
927 break;
928 case TYPE_DEFAULT:
929 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
930 break;
931 default:
932 ANI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
933 return;
934 }
935 MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
936 #else
937 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
938 #endif
939 }
940 }
941
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)942 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
943 MediaLibraryAsyncContext *context)
944 {
945 bool isValid = false;
946 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
947 if (!isValid) {
948 ANI_ERR_LOG("getting title is invalid");
949 return;
950 }
951 auto fileAsset = make_unique<FileAsset>();
952 fileAsset->SetId(id);
953 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
954 fileAsset->SetUri(uri);
955 fileAsset->SetMediaType(mediaType);
956 fileAsset->SetDisplayName(displayName);
957 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
958 fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
959 fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
960 context->fileAsset = move(fileAsset);
961 }
962
963 #ifdef MEDIALIBRARY_COMPATIBILITY
SetFileAssetByIdV9(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)964 static void SetFileAssetByIdV9(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
965 {
966 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
967 bool isValid = false;
968 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
969 if (!isValid) {
970 ANI_ERR_LOG("get title is invalid");
971 return;
972 }
973 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
974 if (!isValid) {
975 ANI_ERR_LOG("get relativePath is invalid");
976 return;
977 }
978 unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
979 fileAsset->SetId(id);
980 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
981 string uri;
982 if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
983 MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
984 uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(MediaType::MEDIA_TYPE_FILE,
985 to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
986 relativePath = MediaFileUtils::RemoveDocsFromRelativePath(relativePath);
987 } else {
988 uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(mediaType,
989 to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
990 }
991 fileAsset->SetUri(uri);
992 fileAsset->SetMediaType(mediaType);
993 fileAsset->SetDisplayName(displayName);
994 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
995 fileAsset->SetResultNapiType(ResultNapiType::TYPE_MEDIALIBRARY);
996 fileAsset->SetRelativePath(relativePath);
997 context->fileAsset = move(fileAsset);
998 }
999 #endif
1000
PhotoAccessCreateAssetExecute(MediaLibraryAsyncContext * context)1001 static void PhotoAccessCreateAssetExecute(MediaLibraryAsyncContext* context)
1002 {
1003 MediaLibraryTracer tracer;
1004 tracer.Start("PhotoAccessCreateAssetExecute");
1005
1006 if (context == nullptr) {
1007 ANI_ERR_LOG("PhotoAccessCreateAssetExecute: context is null");
1008 return;
1009 }
1010
1011 if (!CheckDisplayNameParams(context)) {
1012 context->error = JS_E_DISPLAYNAME;
1013 return;
1014 }
1015 if ((context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) && (!CheckRelativePathParams(context))) {
1016 context->error = JS_E_RELATIVEPATH;
1017 return;
1018 }
1019
1020 string uri;
1021 GetCreateUri(context, uri);
1022 Uri createFileUri(uri);
1023 string outUri;
1024 int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
1025 if (index < 0) {
1026 context->SaveError(index);
1027 ANI_ERR_LOG("InsertExt fail, index: %{public}d.", index);
1028 } else {
1029 if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1030 if (context->isCreateByComponent) {
1031 context->uri = outUri;
1032 } else {
1033 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
1034 }
1035 } else {
1036 #ifdef MEDIALIBRARY_COMPATIBILITY
1037 SetFileAssetByIdV9(index, "", context);
1038 #else
1039 getFileAssetById(index, "", context);
1040 #endif
1041 }
1042 }
1043 }
1044
createAsset1(ani_env * env,ani_object thisObject,ani_string stringObj)1045 ani_object MediaLibraryAni::createAsset1([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object thisObject,
1046 [[maybe_unused]] ani_string stringObj)
1047 {
1048 MediaLibraryTracer tracer;
1049 tracer.Start("createAsset1");
1050 ani_object result_obj = {};
1051 MediaLibraryAsyncContext *context = nullptr;
1052 PhotoAccessCreateAssetExecute(context);
1053 return result_obj;
1054 }
1055 } // namespace Media
1056 } // namespace OHOS
1057