• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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