• 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 "ani_class_name.h"
17 #include "datashare_values_bucket.h"
18 #include "exif_rotate_utils.h"
19 #include "file_asset_ani.h"
20 #include "medialibrary_ani_log.h"
21 #include "medialibrary_ani_utils.h"
22 #include "medialibrary_db_const.h"
23 #include "media_log.h"
24 #include "media_column.h"
25 #include "media_file_utils.h"
26 #include "thumbnail_const.h"
27 #include "thumbnail_manager_ani.h"
28 #include "userfile_manager_types.h"
29 #include "medialibrary_ani_utils.h"
30 #include "userfile_client.h"
31 #include "userfilemgr_uri.h"
32 #include "datashare_predicates.h"
33 #include "values_bucket.h"
34 #include "vision_column.h"
35 #include "vision_total_column.h"
36 #include "vision_aesthetics_score_column.h"
37 #include "vision_album_column.h"
38 #include "vision_column_comm.h"
39 #include "vision_column.h"
40 #include "vision_composition_column.h"
41 #include "vision_face_tag_column.h"
42 #include "vision_head_column.h"
43 #include "vision_image_face_column.h"
44 #include "vision_label_column.h"
45 #include "vision_object_column.h"
46 #include "vision_ocr_column.h"
47 #include "vision_photo_map_column.h"
48 #include "vision_pose_column.h"
49 #include "vision_recommendation_column.h"
50 #include "vision_saliency_detect_column.h"
51 #include "vision_segmentation_column.h"
52 #include "vision_total_column.h"
53 #include "vision_video_label_column.h"
54 #include "vision_multi_crop_column.h"
55 #include "location_column.h"
56 #include "locale_config.h"
57 #include "userfile_manager_types.h"
58 #include "medialibrary_ani_log.h"
59 #include "medialibrary_tracer.h"
60 
61 using namespace std;
62 using namespace OHOS::DataShare;
63 
64 namespace OHOS::Media {
65 
66 struct FileAssetAttributes {
67     std::string uri;
68     MediaType photoType;
69     std::string displayName;
70 };
71 static const std::string ANALYSIS_NO_RESULTS = "[]";
72 static const std::string ANALYSIS_INIT_VALUE = "0";
73 static const std::string ANALYSIS_STATUS_ANALYZED = "Analyzed, no results";
74 
75 constexpr int32_t IS_HIDDEN = 1;
76 constexpr int32_t NOT_HIDDEN = 0;
77 
78 constexpr int32_t IS_FAV = 1;
79 constexpr int32_t NOT_FAV = 0;
80 
81 constexpr int32_t USER_COMMENT_MAX_LEN = 420;
82 
83 thread_local std::shared_ptr<FileAsset> FileAssetAni::sFileAsset_ = nullptr;
84 
85 struct AnalysisSourceInfo {
86     std::string fieldStr;
87     std::string uriStr;
88     std::vector<std::string> fetchColumn;
89 };
90 
91 static const map<int32_t, struct AnalysisSourceInfo> ANALYSIS_SOURCE_INFO_MAP = {
92     { ANALYSIS_AESTHETICS_SCORE, { AESTHETICS_SCORE, PAH_QUERY_ANA_ATTS, { AESTHETICS_SCORE, PROB } } },
93     { ANALYSIS_LABEL, { LABEL, PAH_QUERY_ANA_LABEL, { CATEGORY_ID, SUB_LABEL, PROB, FEATURE, SIM_RESULT,
94         SALIENCY_SUB_PROB } } },
95     { ANALYSIS_VIDEO_LABEL, { VIDEO_LABEL, PAH_QUERY_ANA_VIDEO_LABEL, { CATEGORY_ID, CONFIDENCE_PROBABILITY,
96         SUB_CATEGORY, SUB_CONFIDENCE_PROB, SUB_LABEL, SUB_LABEL_PROB, SUB_LABEL_TYPE, TRACKS, VIDEO_PART_FEATURE,
97         FILTER_TAG} } },
98     { ANALYSIS_OCR, { OCR, PAH_QUERY_ANA_OCR, { OCR_TEXT, OCR_TEXT_MSG, OCR_WIDTH, OCR_HEIGHT } } },
99     { ANALYSIS_FACE, { FACE, PAH_QUERY_ANA_FACE, { FACE_ID, TAG_ID, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT,
100         LANDMARKS, PITCH, YAW, ROLL, PROB, TOTAL_FACES, FEATURES, FACE_OCCLUSION, BEAUTY_BOUNDER_X, BEAUTY_BOUNDER_Y,
101         BEAUTY_BOUNDER_WIDTH, BEAUTY_BOUNDER_HEIGHT, FACE_AESTHETICS_SCORE, JOINT_BEAUTY_BOUNDER_X,
102         JOINT_BEAUTY_BOUNDER_Y, JOINT_BEAUTY_BOUNDER_WIDTH, JOINT_BEAUTY_BOUNDER_HEIGHT} } },
103     { ANALYSIS_OBJECT, { OBJECT, PAH_QUERY_ANA_OBJECT, { OBJECT_ID, OBJECT_LABEL, OBJECT_SCALE_X, OBJECT_SCALE_Y,
104         OBJECT_SCALE_WIDTH, OBJECT_SCALE_HEIGHT, PROB, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
105     { ANALYSIS_RECOMMENDATION, { RECOMMENDATION, PAH_QUERY_ANA_RECOMMENDATION, { RECOMMENDATION_ID,
106         RECOMMENDATION_RESOLUTION, RECOMMENDATION_SCALE_X, RECOMMENDATION_SCALE_Y, RECOMMENDATION_SCALE_WIDTH,
107         RECOMMENDATION_SCALE_HEIGHT, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
108     { ANALYSIS_SEGMENTATION, { SEGMENTATION, PAH_QUERY_ANA_SEGMENTATION, { SEGMENTATION_AREA, SEGMENTATION_NAME,
109         PROB } } },
110     { ANALYSIS_COMPOSITION, { COMPOSITION, PAH_QUERY_ANA_COMPOSITION, { COMPOSITION_ID, COMPOSITION_RESOLUTION,
111         CLOCK_STYLE, CLOCK_LOCATION_X, CLOCK_LOCATION_Y, CLOCK_COLOUR, COMPOSITION_SCALE_X, COMPOSITION_SCALE_Y,
112         COMPOSITION_SCALE_WIDTH, COMPOSITION_SCALE_HEIGHT, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
113     { ANALYSIS_SALIENCY, { SALIENCY, PAH_QUERY_ANA_SAL, { SALIENCY_X, SALIENCY_Y } } },
114     { ANALYSIS_DETAIL_ADDRESS, { DETAIL_ADDRESS, PAH_QUERY_ANA_ADDRESS, { PhotoColumn::PHOTOS_TABLE + "." + LATITUDE,
115         PhotoColumn::PHOTOS_TABLE + "." + LONGITUDE, LANGUAGE, COUNTRY, ADMIN_AREA, SUB_ADMIN_AREA, LOCALITY,
116         SUB_LOCALITY, THOROUGHFARE, SUB_THOROUGHFARE, FEATURE_NAME, CITY_NAME, ADDRESS_DESCRIPTION, LOCATION_TYPE,
117         AOI, POI, FIRST_AOI, FIRST_POI, LOCATION_VERSION, FIRST_AOI_CATEGORY, FIRST_POI_CATEGORY, FILE_ID} } },
118     { ANALYSIS_HUMAN_FACE_TAG, { FACE_TAG, PAH_QUERY_ANA_FACE_TAG, { VISION_FACE_TAG_TABLE + "." + TAG_ID, TAG_NAME,
119         USER_OPERATION, GROUP_TAG, RENAME_OPERATION, CENTER_FEATURES, USER_DISPLAY_LEVEL, TAG_ORDER, IS_ME, COVER_URI,
120         COUNT, PORTRAIT_DATE_MODIFY, ALBUM_TYPE, IS_REMOVED } } },
121     { ANALYSIS_HEAD_POSITION, { HEAD, PAH_QUERY_ANA_HEAD, { HEAD_ID, HEAD_LABEL, HEAD_SCALE_X, HEAD_SCALE_Y,
122         HEAD_SCALE_WIDTH, HEAD_SCALE_HEIGHT, PROB, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
123     { ANALYSIS_BONE_POSE, { POSE, PAH_QUERY_ANA_POSE, { POSE_ID, POSE_LANDMARKS, POSE_SCALE_X, POSE_SCALE_Y,
124         POSE_SCALE_WIDTH, POSE_SCALE_HEIGHT, PROB, POSE_TYPE, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
125     { ANALYSIS_MULTI_CROP, { RECOMMENDATION, PAH_QUERY_ANA_RECOMMENDATION, { MOVEMENT_CROP, MOVEMENT_VERSION } } },
126 };
127 
FileAssetAni(std::shared_ptr<FileAsset> fileAsset)128 FileAssetAni::FileAssetAni(std::shared_ptr<FileAsset> fileAsset)
129 {
130     fileAssetPtr = fileAsset;
131 }
132 
FileAssetAni()133 FileAssetAni::FileAssetAni() {}
134 
135 FileAssetAni::~FileAssetAni() = default;
136 
Destructor(ani_env env,void * nativeObject,void * finalize_hint)137 void FileAssetAni::Destructor(ani_env env, void *nativeObject, void *finalize_hint)
138 {
139     FileAssetAni *fileAssetObj = reinterpret_cast<FileAssetAni*>(nativeObject);
140     if (fileAssetObj != nullptr) {
141         delete fileAssetObj;
142         fileAssetObj = nullptr;
143     }
144 }
145 
FileAssetAniInit(ani_env * env)146 ani_status FileAssetAni::FileAssetAniInit(ani_env *env)
147 {
148     static const char *className = ANI_CLASS_PHOTO_ASSET.c_str();
149     ani_class cls;
150     ani_status status = env->FindClass(className, &cls);
151     if (status != ANI_OK) {
152         ANI_ERR_LOG("Failed to find class: %{public}s", className);
153         return status;
154     }
155 
156     std::array methods = {
157         ani_native_function {"create", nullptr, reinterpret_cast<void *>(FileAssetAni::Constructor)},
158         ani_native_function {"set", nullptr, reinterpret_cast<void *>(FileAssetAni::Set)},
159         ani_native_function {"get", nullptr, reinterpret_cast<void *>(FileAssetAni::Get)},
160         ani_native_function {"commitModifySync", nullptr, reinterpret_cast<void *>(FileAssetAni::CommitModify)},
161         ani_native_function {"setUserCommentSync", nullptr, reinterpret_cast<void *>(FileAssetAni::SetUserComment)},
162         ani_native_function {"openSync", nullptr, reinterpret_cast<void *>(FileAssetAni::Open)},
163         ani_native_function {"closeSync", nullptr, reinterpret_cast<void *>(FileAssetAni::Close)},
164         ani_native_function {"getAnalysisDataSync", nullptr, reinterpret_cast<void *>(FileAssetAni::GetAnalysisData)},
165         ani_native_function {"setHiddenSync", nullptr, reinterpret_cast<void *>(FileAssetAni::SetHidden)},
166         ani_native_function {"setFavoriteSync", nullptr, reinterpret_cast<void *>(FileAssetAni::SetFavorite)},
167         ani_native_function {"getThumbnailSync", nullptr, reinterpret_cast<void *>(FileAssetAni::GetThumbnail)},
168     };
169 
170     status = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
171     if (status != ANI_OK) {
172         ANI_ERR_LOG("Failed to bind native methods to: %{public}s", className);
173         return status;
174     }
175 
176     ANI_INFO_LOG("FileAssetAniInit ok");
177     return ANI_OK;
178 }
179 
GetFileAssetAttributes(ani_env * env,ani_object object,FileAssetAttributes & attrs)180 static ani_status GetFileAssetAttributes(ani_env *env, ani_object object, FileAssetAttributes &attrs)
181 {
182     FileAssetAni *fileAssetAni = FileAssetAni::Unwrap(env, object);
183     CHECK_COND_RET(fileAssetAni != nullptr, ANI_ERROR, "FileAssetAni is nullptr");
184     auto fileAsset = fileAssetAni->GetFileAssetInstance();
185     CHECK_COND_RET(fileAsset != nullptr, ANI_ERROR, "FileAsset is nullptr");
186 
187     attrs.uri = fileAsset->GetUri();
188     attrs.photoType = fileAsset->GetMediaType();
189     attrs.displayName = fileAsset->GetDisplayName();
190     return ANI_OK;
191 }
192 
BindAniAttributes(ani_env * env,ani_class cls,ani_object object)193 static ani_status BindAniAttributes(ani_env *env, ani_class cls, ani_object object)
194 {
195     FileAssetAttributes attrs;
196     CHECK_STATUS_RET(GetFileAssetAttributes(env, object, attrs), "GetFileAssetAttributes fail");
197     ANI_DEBUG_LOG("GetFileAsset uri: %{private}s, displayName: %{private}s, photoType: %{public}d",
198         attrs.uri.c_str(), attrs.displayName.c_str(), attrs.photoType);
199 
200     ani_method photoTypeSetter {};
201     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>photoType", nullptr, &photoTypeSetter), "No <set>photoType");
202     ani_enum_item photoType = 0;
203     CHECK_STATUS_RET(MediaLibraryEnumAni::ToAniEnum(env, attrs.photoType, photoType), "Get photoType index fail");
204     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, photoTypeSetter, photoType), "<set>photoType fail");
205 
206     ani_method uriSetter {};
207     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>uri", nullptr, &uriSetter), "No <set>uri");
208     ani_string uri {};
209     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.uri, uri), "ToAniString uri fail");
210     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, uriSetter, uri), "<set>uri fail");
211 
212     ani_method displayNameSetter {};
213     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>displayName", nullptr, &displayNameSetter),
214         "No <set>displayName");
215     ani_string displayName {};
216     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.displayName, displayName),
217         "ToAniString displayName fail");
218     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, displayNameSetter, displayName), "<set>displayName fail");
219     return ANI_OK;
220 }
221 
BindAniAttributes(ani_env * env,ani_object object,const FileAssetAniMethod & fileAssetAniMethod,const FileAssetAttributes & attrs)222 static ani_status BindAniAttributes(ani_env *env, ani_object object,
223     const FileAssetAniMethod &fileAssetAniMethod, const FileAssetAttributes &attrs)
224 {
225     ani_enum_item photoType = 0;
226     CHECK_STATUS_RET(MediaLibraryEnumAni::ToAniEnum(env, attrs.photoType, photoType), "Get photoType index fail");
227     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, fileAssetAniMethod.setPhotoType, photoType),
228         "<set>photoType fail");
229 
230     ani_string uri {};
231     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.uri, uri), "ToAniString uri fail");
232     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, fileAssetAniMethod.setUri, uri), "<set>uri fail");
233 
234     ani_string displayName {};
235     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.displayName, displayName),
236         "ToAniString displayName fail");
237     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, fileAssetAniMethod.setDisplayName, displayName),
238         "<set>displayName fail");
239     return ANI_OK;
240 }
241 
Constructor(ani_env * env,ani_class clazz)242 ani_object FileAssetAni::Constructor([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz)
243 {
244     std::shared_ptr<FileAsset> fileAssetPtr = std::make_shared<FileAsset>();
245     std::unique_ptr<FileAssetAni> nativeFileAssetAni = std::make_unique<FileAssetAni>(fileAssetPtr);
246 
247     ani_class cls;
248     if (ANI_OK != env->FindClass(ANI_CLASS_PHOTO_ASSET.c_str(), &cls)) {
249         ANI_ERR_LOG("Failed to find class: %{public}s", ANI_CLASS_PHOTO_ASSET.c_str());
250         ani_object nullobj = nullptr;
251         return nullobj;
252     }
253 
254     ani_method ctor;
255     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "J:V", &ctor)) {
256         ANI_ERR_LOG("Failed to find method: %{public}s", "ctor");
257         ani_object nullobj = nullptr;
258         return nullobj;
259     }
260 
261     ani_object fileAsset_object;
262     if (ANI_OK != env->Object_New(cls, ctor, &fileAsset_object,
263         reinterpret_cast<ani_long>(nativeFileAssetAni.release()))) {
264         ANI_ERR_LOG("New FileAsset Fail");
265     }
266     CHECK_COND_RET(BindAniAttributes(env, cls, fileAsset_object) == ANI_OK, nullptr,
267         "fileAsset BindAniAttributes Fail");
268 
269     ANI_INFO_LOG("FileAssetAni Constructor ok");
270     return fileAsset_object;
271 }
272 
GetFileAssetInstance() const273 shared_ptr<FileAsset> FileAssetAni::GetFileAssetInstance() const
274 {
275     return fileAssetPtr;
276 }
277 
CreatePhotoAsset(ani_env * env,std::shared_ptr<FileAsset> & fileAsset)278 FileAssetAni* FileAssetAni::CreatePhotoAsset(ani_env *env, std::shared_ptr<FileAsset> &fileAsset)
279 {
280     if (fileAsset == nullptr || fileAsset->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
281         ANI_ERR_LOG("Unsupported fileAsset");
282         return nullptr;
283     }
284 
285     std::unique_ptr<FileAssetAni> fileAssetAni = std::make_unique<FileAssetAni>(fileAsset);
286     return fileAssetAni.release();
287 }
288 
CreateFileAsset(ani_env * env,std::unique_ptr<FileAsset> & fileAsset)289 FileAssetAni* FileAssetAni::CreateFileAsset(ani_env *env, std::unique_ptr<FileAsset> &fileAsset)
290 {
291     if (fileAsset == nullptr || fileAsset->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
292         ANI_ERR_LOG("Unsupported fileAsset");
293         return nullptr;
294     }
295     sFileAsset_ = std::move(fileAsset);
296     std::unique_ptr<FileAssetAni> fileAssetAni = std::make_unique<FileAssetAni>(sFileAsset_);
297     sFileAsset_ = nullptr;
298     return fileAssetAni.release();
299 }
300 
InitFileAssetAniMethod(ani_env * env,ResultNapiType classType,FileAssetAniMethod & fileAssetAniMethod)301 ani_status FileAssetAni::InitFileAssetAniMethod(ani_env *env, ResultNapiType classType,
302     FileAssetAniMethod &fileAssetAniMethod)
303 {
304     std::string className;
305     if (classType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
306         className = ANI_CLASS_PHOTO_ASSET;
307     } else if (classType == ResultNapiType::TYPE_USERFILE_MGR) {
308         className = UFM_ANI_CLASS_PHOTO_ALBUM_HANDLE;
309     } else {
310         ANI_ERR_LOG("type not support");
311         return ANI_ERROR;
312     }
313 
314     CHECK_STATUS_RET(env->FindClass(className.c_str(), &fileAssetAniMethod.cls),
315         "No className: %{public}s", className.c_str());
316     CHECK_STATUS_RET(env->Class_FindMethod(fileAssetAniMethod.cls, "<ctor>", "J:V", &fileAssetAniMethod.ctor),
317         "No <ctor>");
318     CHECK_STATUS_RET(env->Class_FindMethod(fileAssetAniMethod.cls, "<set>uri", nullptr, &fileAssetAniMethod.setUri),
319         "No <set>uri");
320     CHECK_STATUS_RET(env->Class_FindMethod(fileAssetAniMethod.cls, "<set>photoType", nullptr,
321         &fileAssetAniMethod.setPhotoType), "No <set>photoType");
322     CHECK_STATUS_RET(env->Class_FindMethod(fileAssetAniMethod.cls, "<set>displayName", nullptr,
323         &fileAssetAniMethod.setDisplayName), "No <set>displayName");
324 
325     return ANI_OK;
326 }
327 
Wrap(ani_env * env,FileAssetAni * fileAssetAni,const FileAssetAniMethod & fileAssetAniMethod)328 ani_object FileAssetAni::Wrap(ani_env *env, FileAssetAni *fileAssetAni, const FileAssetAniMethod &fileAssetAniMethod)
329 {
330     if (fileAssetAni == nullptr || fileAssetAni->GetFileAssetInstance() == nullptr) {
331         ANI_ERR_LOG("fileAssetAni is nullptr");
332         return nullptr;
333     }
334 
335     std::shared_ptr<FileAsset> fileAsset = fileAssetAni->GetFileAssetInstance();
336     FileAssetAttributes attrs;
337     attrs.uri = fileAsset->GetUri();
338     attrs.photoType = fileAsset->GetMediaType();
339     attrs.displayName = fileAsset->GetDisplayName();
340 
341     ani_object fileAsset_object = nullptr;
342     if (ANI_OK != env->Object_New(fileAssetAniMethod.cls, fileAssetAniMethod.ctor, &fileAsset_object,
343         reinterpret_cast<ani_long>(fileAssetAni))) {
344         ANI_ERR_LOG("New FileAsset Fail");
345         return nullptr;
346     }
347 
348     if (ANI_OK != BindAniAttributes(env, fileAsset_object, fileAssetAniMethod, attrs)) {
349         ANI_ERR_LOG("fileAsset BindAniAttributes Fail");
350         return nullptr;
351     }
352     return fileAsset_object;
353 }
354 
Wrap(ani_env * env,FileAssetAni * fileAssetAni)355 ani_object FileAssetAni::Wrap(ani_env *env, FileAssetAni *fileAssetAni)
356 {
357     MediaLibraryTracer tracer;
358     tracer.Start("FileAssetAni::Wrap");
359 
360     ani_class cls;
361     if (ANI_OK != env->FindClass(ANI_CLASS_PHOTO_ASSET.c_str(), &cls)) {
362         ANI_ERR_LOG("Failed to find class: %{public}s", ANI_CLASS_PHOTO_ASSET.c_str());
363         ani_object nullobj = nullptr;
364         return nullobj;
365     }
366 
367     ani_method ctor;
368     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "J:V", &ctor)) {
369         ANI_ERR_LOG("Failed to find method: %{public}s", "ctor");
370         ani_object nullobj = nullptr;
371         return nullobj;
372     }
373 
374     ani_object fileAsset_object;
375     if (ANI_OK != env->Object_New(cls, ctor, &fileAsset_object, reinterpret_cast<ani_long>(fileAssetAni))) {
376         ANI_ERR_LOG("New FileAsset Fail");
377     }
378     CHECK_COND_RET(BindAniAttributes(env, cls, fileAsset_object) == ANI_OK, nullptr,
379         "fileAsset BindAniAttributes Fail");
380     return fileAsset_object;
381 }
382 
Unwrap(ani_env * env,ani_object object)383 FileAssetAni* FileAssetAni::Unwrap(ani_env *env, ani_object object)
384 {
385     ani_long fileAsset;
386     if (ANI_OK != env->Object_GetFieldByName_Long(object, "nativePhotoAsset", &fileAsset)) {
387         ANI_ERR_LOG("get FileAssetAni nativePhotoAsset failed");
388         return nullptr;
389     }
390     return reinterpret_cast<FileAssetAni*>(fileAsset);
391 }
392 
Set(ani_env * env,ani_object object,ani_string member,ani_string value)393 void FileAssetAni::Set(ani_env *env, ani_object object, ani_string member, ani_string value)
394 {
395     auto fileAssetAni = Unwrap(env, object);
396     if (fileAssetAni == nullptr || fileAssetAni->fileAssetPtr == nullptr) {
397         ANI_ERR_LOG("fileAssetAni is nullptr");
398         return;
399     }
400 
401     std::string memberStr;
402     MediaLibraryAniUtils::GetString(env, member, memberStr);
403     std::string valueStr;
404     MediaLibraryAniUtils::GetString(env, value, valueStr);
405 
406     std::shared_ptr<FileAsset> fileAssetPtr = fileAssetAni->fileAssetPtr;
407     ResultNapiType resultNapiType = fileAssetPtr->GetResultNapiType();
408     ANI_INFO_LOG("fileAsset set key: %{public}s, value: %{public}s, type: %{public}d",
409         memberStr.c_str(), valueStr.c_str(), resultNapiType);
410     if (resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
411         if (memberStr == MediaColumn::MEDIA_TITLE) {
412             fileAssetPtr->SetTitle(valueStr);
413         } else {
414             ANI_ERR_LOG("invalid key %{private}s, no support key", memberStr.c_str());
415             AniError::ThrowError(env, JS_E_FILE_KEY);
416         }
417     } else if (resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
418         if (memberStr == MediaColumn::MEDIA_NAME) {
419             fileAssetPtr->SetDisplayName(valueStr);
420             fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(valueStr));
421         } else if (memberStr == MediaColumn::MEDIA_TITLE) {
422             fileAssetPtr->SetTitle(valueStr);
423             string displayName = fileAssetPtr->GetDisplayName();
424             if (!displayName.empty()) {
425                 string extention = MediaFileUtils::SplitByChar(displayName, '.');
426                 fileAssetPtr->SetDisplayName(valueStr + "." + extention);
427             }
428         } else {
429             ANI_ERR_LOG("invalid key %{private}s, no support key", memberStr.c_str());
430             AniError::ThrowError(env, JS_E_FILE_KEY);
431         }
432     } else {
433         ANI_ERR_LOG("invalid resultNapiType");
434         AniError::ThrowError(env, JS_E_FILE_KEY);
435     }
436 }
437 
CheckSystemApiKeys(ani_env * env,const string & key)438 static int32_t CheckSystemApiKeys(ani_env *env, const string &key)
439 {
440     static const set<string> SYSTEM_API_KEYS = {
441         PhotoColumn::PHOTO_POSITION,
442         MediaColumn::MEDIA_DATE_TRASHED,
443         MediaColumn::MEDIA_HIDDEN,
444         PhotoColumn::PHOTO_USER_COMMENT,
445         PhotoColumn::CAMERA_SHOT_KEY,
446         PhotoColumn::MOVING_PHOTO_EFFECT_MODE,
447         PhotoColumn::SUPPORTED_WATERMARK_TYPE,
448         PENDING_STATUS,
449         MEDIA_DATA_DB_DATE_TRASHED_MS,
450         PhotoColumn::PHOTO_EXIF_ROTATE,
451     };
452 
453     if (SYSTEM_API_KEYS.find(key) != SYSTEM_API_KEYS.end() && !MediaLibraryAniUtils::IsSystemApp()) {
454         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This key can only be used by system apps");
455         return E_CHECK_SYSTEMAPP_FAIL;
456     }
457     return E_SUCCESS;
458 }
459 
HandleDateTransitionKey(ani_env * env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)460 static ani_object HandleDateTransitionKey(ani_env *env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
461 {
462     ani_object aniResult = nullptr;
463     if (fileAssetPtr->GetMemberMap().count(key) == 0) {
464         AniError::ThrowError(env, JS_E_FILE_KEY);
465         return aniResult;
466     }
467 
468     auto m = fileAssetPtr->GetMemberMap().at(key);
469     if (m.index() == MEMBER_TYPE_INT64) {
470         double val = static_cast<double>(get<int64_t>(m));
471         MediaLibraryAniUtils::ToAniDoubleObject(env, val, aniResult);
472     } else {
473         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
474         return aniResult;
475     }
476     return aniResult;
477 }
478 
IsSpecialKey(const string & key)479 static bool IsSpecialKey(const string &key)
480 {
481     static const set<string> SPECIAL_KEY = {
482         PENDING_STATUS,
483         PhotoColumn::PHOTO_EXIF_ROTATE,
484     };
485 
486     if (SPECIAL_KEY.find(key) != SPECIAL_KEY.end()) {
487         return true;
488     }
489     return false;
490 }
491 
HandleGettingSpecialKey(ani_env * env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)492 static ani_object HandleGettingSpecialKey(ani_env *env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
493 {
494     if (key == PENDING_STATUS) {
495         bool isTimePending = (fileAssetPtr->GetTimePending() != 0);
496         ani_object aniResult = nullptr;
497         MediaLibraryAniUtils::ToAniBooleanObject(env, isTimePending, aniResult);
498         return aniResult;
499     } else if (key == PhotoColumn::PHOTO_EXIF_ROTATE) {
500         int32_t value = fileAssetPtr->GetExifRotate();
501         int32_t exifRotate = value == 0 ? static_cast<int32_t>(ExifRotateType::TOP_LEFT) : value;
502         ani_object aniResult = nullptr;
503         MediaLibraryAniUtils::ToAniDoubleObject(env, static_cast<double>(exifRotate), aniResult);
504         return aniResult;
505     }
506 
507     return nullptr;
508 }
509 
UpdateDetailTimeByDateTaken(ani_env * env,const shared_ptr<FileAsset> & fileAssetPtr,const string & detailTime)510 static void UpdateDetailTimeByDateTaken(ani_env *env, const shared_ptr<FileAsset> &fileAssetPtr,
511     const string &detailTime)
512 {
513     string uri = PAH_UPDATE_PHOTO;
514     MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
515     Uri updateAssetUri(uri);
516     DataSharePredicates predicates;
517     DataShareValuesBucket valuesBucket;
518     valuesBucket.Put(PhotoColumn::PHOTO_DETAIL_TIME, detailTime);
519     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
520     predicates.SetWhereArgs({ MediaFileUtils::GetIdFromUri(fileAssetPtr->GetUri()) });
521     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
522     if (changedRows < 0) {
523         ANI_ERR_LOG("Failed to modify detail time, err: %{public}d", changedRows);
524         AniError::ThrowError(env, JS_INNER_FAIL);
525     }
526 }
527 
GetDateTakenFromResultSet(const shared_ptr<DataShareResultSet> & resultSet,int64_t & dateTaken)528 static bool GetDateTakenFromResultSet(const shared_ptr<DataShareResultSet> &resultSet, int64_t &dateTaken)
529 {
530     if (resultSet == nullptr) {
531         ANI_ERR_LOG("ResultSet is null");
532         return false;
533     }
534     int32_t count = 0;
535     int32_t errCode = resultSet->GetRowCount(count);
536     if (errCode != OHOS::DataShare::E_OK) {
537         ANI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
538         return false;
539     }
540     if (count == 0) {
541         ANI_ERR_LOG("Can not find photo edit time from database");
542         return false;
543     }
544     errCode = resultSet->GoToFirstRow();
545     if (errCode != OHOS::DataShare::E_OK) {
546         ANI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
547         return false;
548     }
549     int32_t index = 0;
550     errCode = resultSet->GetColumnIndex(PhotoColumn::MEDIA_DATE_TAKEN, index);
551     if (errCode != OHOS::DataShare::E_OK) {
552         ANI_ERR_LOG("ResultSet GetColumnIndex failed, errCode=%{public}d", errCode);
553         return false;
554     }
555     errCode = resultSet->GetLong(index, dateTaken);
556     if (errCode != OHOS::DataShare::E_OK) {
557         ANI_ERR_LOG("ResultSet GetLong failed, errCode=%{public}d", errCode);
558         return false;
559     }
560     return true;
561 }
562 
HandleGettingDetailTimeKey(ani_env * env,const shared_ptr<FileAsset> & fileAssetPtr)563 static ani_object HandleGettingDetailTimeKey(ani_env *env, const shared_ptr<FileAsset> &fileAssetPtr)
564 {
565     ani_object aniResult = nullptr;
566     auto detailTimeValue = fileAssetPtr->GetMemberMap().at(PhotoColumn::PHOTO_DETAIL_TIME);
567     if (detailTimeValue.index() == MEMBER_TYPE_STRING && !get<string>(detailTimeValue).empty()) {
568         ANI_INFO_LOG("detailTimeValue type is string");
569         ani_string aniDetailTime {};
570         MediaLibraryAniUtils::ToAniString(env, get<string>(detailTimeValue), aniDetailTime);
571         return reinterpret_cast<ani_object>(aniDetailTime);
572     } else {
573         ANI_INFO_LOG("detailTimeValue from database");
574         string fileId = MediaFileUtils::GetIdFromUri(fileAssetPtr->GetUri());
575         string queryUriStr = PAH_QUERY_PHOTO;
576         MediaLibraryAniUtils::UriAppendKeyValue(queryUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
577         Uri uri(queryUriStr);
578         DataSharePredicates predicates;
579         predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
580         DataShareValuesBucket values;
581         vector<string> columns = { MediaColumn::MEDIA_DATE_TAKEN };
582         int32_t errCode = 0;
583         int64_t dateTaken = 0;
584         shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
585         if (GetDateTakenFromResultSet(resultSet, dateTaken)) {
586             if (dateTaken > SECONDS_LEVEL_LIMIT) {
587                 dateTaken = dateTaken / MSEC_TO_SEC;
588             }
589             string detailTime = MediaFileUtils::StrCreateTime(PhotoColumn::PHOTO_DETAIL_TIME_FORMAT, dateTaken);
590             ani_string aniDetailTime {};
591             MediaLibraryAniUtils::ToAniString(env, detailTime, aniDetailTime);
592             UpdateDetailTimeByDateTaken(env, fileAssetPtr, detailTime);
593             return reinterpret_cast<ani_object>(aniDetailTime);
594         } else {
595             AniError::ThrowError(env, JS_INNER_FAIL);
596         }
597     }
598     return aniResult;
599 }
600 
GetCompatDate(const string inputKey,const int64_t date)601 static inline int64_t GetCompatDate(const string inputKey, const int64_t date)
602 {
603     if (inputKey == MEDIA_DATA_DB_DATE_ADDED || inputKey == MEDIA_DATA_DB_DATE_MODIFIED ||
604         inputKey == MEDIA_DATA_DB_DATE_TRASHED || inputKey == MEDIA_DATA_DB_DATE_TAKEN) {
605             return date / MSEC_TO_SEC;
606         }
607     return date;
608 }
609 
Get(ani_env * env,ani_object object,ani_string member)610 ani_object FileAssetAni::Get(ani_env *env, ani_object object, ani_string member)
611 {
612     auto fileAssetAni = Unwrap(env, object);
613     if (fileAssetAni == nullptr || fileAssetAni->GetFileAssetInstance() == nullptr) {
614         ANI_ERR_LOG("fileAssetAni is nullptr");
615         return nullptr;
616     }
617     auto fileAssetPtr = fileAssetAni->fileAssetPtr;
618 
619     std::string inputKey;
620     MediaLibraryAniUtils::GetString(env, member, inputKey);
621     ANI_DEBUG_LOG("FileAsset get key: %{public}s", inputKey.c_str());
622 
623     if (CheckSystemApiKeys(env, inputKey) < 0) {
624         ANI_ERR_LOG("CheckSystemApiKeys failed");
625         return nullptr;
626     }
627 
628     ani_object aniResult = nullptr;
629     if (DATE_TRANSITION_MAP.count(inputKey) != 0) {
630         ANI_DEBUG_LOG("key not in DATE_TRANSITION_MAP");
631         return HandleDateTransitionKey(env, DATE_TRANSITION_MAP.at(inputKey), fileAssetPtr);
632     }
633 
634     if (fileAssetPtr->GetMemberMap().count(inputKey) == 0) {
635         ANI_ERR_LOG("key not found");
636         AniError::ThrowError(env, JS_E_FILE_KEY);
637         return aniResult;
638     }
639 
640     if (IsSpecialKey(inputKey)) {
641         ANI_DEBUG_LOG("IsSpecialKey");
642         return HandleGettingSpecialKey(env, inputKey, fileAssetPtr);
643     }
644     if (inputKey == PhotoColumn::PHOTO_DETAIL_TIME) {
645         ANI_WARN_LOG("inputKey == PHOTO_DETAIL_TIME");
646         return HandleGettingDetailTimeKey(env, fileAssetPtr);
647     }
648     auto m = fileAssetPtr->GetMemberMap().at(inputKey);
649     ANI_DEBUG_LOG("FileAsset get value type: %{public}d", (int)m.index());
650     if (m.index() == MEMBER_TYPE_STRING) {
651         ani_string aniString {};
652         MediaLibraryAniUtils::ToAniString(env, std::get<std::string>(m), aniString);
653         return reinterpret_cast<ani_object>(aniString);
654     } else if (m.index() == MEMBER_TYPE_INT32) {
655         double val = static_cast<double>(std::get<int32_t>(m));
656         MediaLibraryAniUtils::ToAniDoubleObject(env, val, aniResult);
657     } else if (m.index() == MEMBER_TYPE_INT64) {
658         double val = static_cast<double>(GetCompatDate(inputKey, get<int64_t>(m)));
659         MediaLibraryAniUtils::ToAniDoubleObject(env, val, aniResult);
660     } else {
661         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
662     }
663     return aniResult;
664 }
665 
BuildCommitModifyUriApi10(FileAssetContext * context,string & uri)666 static void BuildCommitModifyUriApi10(FileAssetContext *context, string &uri)
667 {
668     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
669         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
670         uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ? UFM_UPDATE_PHOTO : PAH_UPDATE_PHOTO;
671     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
672         uri = UFM_UPDATE_AUDIO;
673     }
674 }
675 
BuildCommitModifyValuesBucket(FileAssetContext * context,OHOS::DataShare::DataShareValuesBucket & valuesBucket)676 static void BuildCommitModifyValuesBucket(FileAssetContext* context,
677     OHOS::DataShare::DataShareValuesBucket &valuesBucket)
678 {
679     const auto fileAsset = context->objectPtr;
680     valuesBucket.Put(MediaColumn::MEDIA_TITLE, fileAsset->GetTitle());
681 }
682 
CommitModify(ani_env * env,ani_object object)683 void FileAssetAni::CommitModify(ani_env *env, ani_object object)
684 {
685     auto fileAssetAni = Unwrap(env, object);
686     if (fileAssetAni == nullptr || fileAssetAni->GetFileAssetInstance() == nullptr) {
687         ANI_ERR_LOG("fileAssetAni is nullptr");
688         return;
689     }
690 
691     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
692     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
693     context->objectPtr = fileAssetPtr;
694     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
695 
696     string uri;
697     BuildCommitModifyUriApi10(context.get(), uri);
698     MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
699 
700     OHOS::Uri updateAssetUri(uri);
701     MediaType mediaType = context->objectPtr->GetMediaType();
702     string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
703     DataSharePredicates predicates;
704     DataShareValuesBucket valuesBucket;
705     BuildCommitModifyValuesBucket(context.get(), valuesBucket);
706     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
707     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
708 
709     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
710     if (changedRows < 0) {
711         context->SaveError(changedRows);
712         ANI_ERR_LOG("File asset modification failed, err: %{public}d", changedRows);
713     } else {
714         context->changedRows = changedRows;
715         Uri modifyNotify(notifyUri);
716         UserFileClient::NotifyChange(modifyNotify);
717     }
718 }
719 
Open(ani_env * env,ani_object object,ani_string mode)720 ani_double FileAssetAni::Open(ani_env *env, ani_object object, ani_string mode)
721 {
722     ani_double aniDouble {};
723     auto fileAssetAni = Unwrap(env, object);
724     if (fileAssetAni == nullptr || fileAssetAni->GetFileAssetInstance() == nullptr) {
725         ANI_ERR_LOG("fileAssetAni is nullptr");
726         return ANI_ERROR;
727     }
728 
729     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
730     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
731     context->objectPtr = fileAssetPtr;
732 
733     if (!MediaLibraryAniUtils::IsSystemApp()) {
734         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
735         return aniDouble;
736     }
737     auto fileUri = context->objectPtr->GetUri();
738     MediaLibraryAniUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
739     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
740 
741     std::string modeStr;
742     MediaLibraryAniUtils::GetString(env, mode, modeStr);
743     transform(modeStr.begin(), modeStr.end(), modeStr.begin(), ::tolower);
744     if (!MediaFileUtils::CheckMode(modeStr)) {
745         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
746         return aniDouble;
747     }
748     context->valuesBucket.Put(MEDIA_FILEMODE, modeStr);
749 
750     if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
751         MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
752             to_string(context->objectPtr->GetTimePending()));
753     }
754     Uri openFileUri(fileUri);
755     int32_t retVal = UserFileClient::OpenFile(openFileUri, modeStr);
756     if (retVal <= 0) {
757         context->SaveError(retVal);
758         ANI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
759     } else {
760         context->fd = retVal;
761         if (modeStr.find('w') != string::npos) {
762             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
763         } else {
764             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
765         }
766         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
767             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
768         }
769     }
770     MediaLibraryAniUtils::ToAniDouble(env, context->fd, aniDouble);
771     return aniDouble;
772 }
773 
CheckFileOpenStatus(FileAssetContext * context,int fd)774 static bool CheckFileOpenStatus(FileAssetContext *context, int fd)
775 {
776     auto fileAssetPtr = context->objectPtr;
777     int ret = fileAssetPtr->GetOpenStatus(fd);
778     if (ret < 0) {
779         return false;
780     } else {
781         fileAssetPtr->RemoveOpenStatus(fd);
782         if (ret == OPEN_TYPE_READONLY) {
783             return false;
784         } else {
785             return true;
786         }
787     }
788 }
789 
Close(ani_env * env,ani_object object,ani_double fd)790 void FileAssetAni::Close(ani_env *env, ani_object object, ani_double fd)
791 {
792     ANI_INFO_LOG("fileAsset close fd: %{public}lf", fd);
793     auto fileAssetAni = Unwrap(env, object);
794     if (fileAssetAni == nullptr || fileAssetAni->GetFileAssetInstance() == nullptr) {
795         ANI_ERR_LOG("fileAssetAni is nullptr");
796         return;
797     }
798 
799     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
800     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
801     context->objectPtr = fileAssetPtr;
802     UniqueFd unifd(context->fd);
803     if (!CheckFileOpenStatus(context.get(), unifd.Get())) {
804         ANI_ERR_LOG("CheckFileOpenStatus failed");
805         return;
806     }
807     string closeUri;
808     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
809         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
810         closeUri = PAH_CLOSE_PHOTO;
811     } else {
812         ANI_ERR_LOG("fileAsset close failed");
813         context->SaveError(-EINVAL);
814         return;
815     }
816     MediaLibraryAniUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
817     MediaLibraryAniUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
818         to_string(context->objectPtr->GetTimePending()));
819     Uri closeAssetUri(closeUri);
820     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
821     if (ret != E_SUCCESS) {
822         ANI_ERR_LOG("fileAsset close failed, ret: %{public}d", ret);
823         context->SaveError(ret);
824         return;
825     } else {
826         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
827             context->objectPtr->SetTimePending(0);
828         }
829     }
830 }
831 
GetThumbnail(ani_env * env,ani_object object,ani_object size)832 ani_object FileAssetAni::GetThumbnail(ani_env *env, ani_object object, ani_object size)
833 {
834     auto fileAssetAni = Unwrap(env, object);
835     if (fileAssetAni == nullptr || fileAssetAni->GetFileAssetInstance() == nullptr) {
836         ANI_ERR_LOG("fileAssetAni is nullptr");
837         return nullptr;
838     }
839 
840     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
841     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
842     context->objectPtr = fileAssetPtr;
843 
844     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
845     context->size.width = DEFAULT_THUMB_SIZE;
846     context->size.height = DEFAULT_THUMB_SIZE;
847 
848     if (MediaLibraryAniUtils::isUndefined(env, size) == ANI_FALSE) {
849         ani_class cls;
850         if (ANI_OK != env->FindClass(ANI_CLASS_SIZE.c_str(), &cls)) {
851             ANI_ERR_LOG("FindClass: %{public}s failed", ANI_CLASS_SIZE.c_str());
852             return nullptr;
853         }
854         ani_method heightGetter;
855         ani_method widthGetter;
856         if (ANI_OK != env->Class_FindMethod(cls, "<get>height", nullptr, &heightGetter)) {
857             ANI_ERR_LOG("Class_FindMethod Fail %{public}s", ANI_CLASS_SIZE.c_str());
858         }
859         if (ANI_OK != env->Class_FindMethod(cls, "<get>width", nullptr, &widthGetter)) {
860             ANI_ERR_LOG("Class_FindMethod Fail %{public}s", ANI_CLASS_SIZE.c_str());
861         }
862 
863         ani_double heightValue;
864         ani_double widthValue;
865         if (ANI_OK != env->Object_CallMethod_Double(size, heightGetter, &heightValue)) {
866             ANI_ERR_LOG("get height failed");
867             return nullptr;
868         }
869         if (ANI_OK != env->Object_CallMethod_Double(size, widthGetter, &widthValue)) {
870             ANI_ERR_LOG("get width failed");
871             return nullptr;
872         }
873         double height;
874         double width;
875         MediaLibraryAniUtils::GetDouble(env, heightValue, height);
876         MediaLibraryAniUtils::GetDouble(env, widthValue, width);
877 
878         context->size.width = width;
879         context->size.height = height;
880     }
881     std::string path = fileAssetPtr->GetPath();
882 #ifndef MEDIALIBRARY_COMPATIBILITY
883     if (path.empty() && !fileAssetPtr->GetRelativePath().empty() && !fileAssetPtr->GetDisplayName().empty()) {
884         path = ROOT_MEDIA_DIR + fileAssetPtr->GetRelativePath() + fileAssetPtr->GetDisplayName();
885     }
886 #endif
887     context->pixelmap = ThumbnailManagerAni::QueryThumbnail(fileAssetPtr->GetUri(), context->size, path);
888 
889     return nullptr;
890 }
891 
SetUserComment(ani_env * env,ani_object object,ani_string userComment)892 void FileAssetAni::SetUserComment([[maybe_unused]] ani_env *env, ani_object object, ani_string userComment)
893 {
894     auto fileAssetAni = Unwrap(env, object);
895     if (fileAssetAni == nullptr || fileAssetAni->fileAssetPtr == nullptr) {
896         ANI_ERR_LOG("fileAssetAni is nullptr");
897         return;
898     }
899 
900     if (!MediaLibraryAniUtils::IsSystemApp()) {
901         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
902         return;
903     }
904 
905     string userCommentStr;
906     MediaLibraryAniUtils::GetString(env, userComment, userCommentStr);
907     ANI_INFO_LOG("SetUserComment: %{public}s", userCommentStr.c_str());
908 
909     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
910     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
911     context->objectPtr = fileAssetPtr;
912     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
913 
914     if (context->userComment.length() > USER_COMMENT_MAX_LEN) {
915         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
916         return;
917     }
918 
919     string uri = PAH_EDIT_USER_COMMENT_PHOTO;
920     MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
921     Uri editUserCommentUri(uri);
922     DataSharePredicates predicates;
923     DataShareValuesBucket valuesBucket;
924     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, userCommentStr);
925     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
926     predicates.SetWhereArgs({to_string(fileAssetPtr->GetId())});
927     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
928     if (changedRows < 0) {
929         context->SaveError(changedRows);
930         ANI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
931     } else {
932         fileAssetPtr->SetUserComment(userCommentStr);
933         context->changedRows = changedRows;
934     }
935 }
936 
GetAnalysisData(ani_env * env,ani_object object,ani_enum_item analysisType)937 ani_string FileAssetAni::GetAnalysisData([[maybe_unused]] ani_env *env, ani_object object, ani_enum_item analysisType)
938 {
939     ani_string aniString {};
940     auto fileAssetAni = Unwrap(env, object);
941     if (fileAssetAni == nullptr || fileAssetAni->fileAssetPtr == nullptr) {
942         ANI_ERR_LOG("fileAssetAni is nullptr");
943         return aniString;
944     }
945 
946     int32_t value;
947     MediaLibraryEnumAni::EnumGetValueInt32(env, analysisType, value);
948 
949     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
950     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
951     context->objectPtr = fileAssetPtr;
952     context->analysisType = value;
953     if (ANALYSIS_SOURCE_INFO_MAP.find(context->analysisType) == ANALYSIS_SOURCE_INFO_MAP.end()) {
954         ANI_ERR_LOG("Invalid analysisType");
955         return aniString;
956     }
957     auto &analysisInfo = ANALYSIS_SOURCE_INFO_MAP.at(context->analysisType);
958     DataSharePredicates predicates;
959     if (context->analysisType == ANALYSIS_HUMAN_FACE_TAG) {
960         string onClause = VISION_IMAGE_FACE_TABLE + "." + TAG_ID + " = " + VISION_FACE_TAG_TABLE + "." + TAG_ID;
961         predicates.InnerJoin(VISION_IMAGE_FACE_TABLE)->On({ onClause });
962     }
963     string fileId = to_string(fileAssetPtr->GetId());
964     if (context->analysisType == ANALYSIS_DETAIL_ADDRESS) {
965         string language = Global::I18n::LocaleConfig::GetSystemLanguage();
966         vector<string> onClause = { PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_LATITUDE + " = " +
967             GEO_KNOWLEDGE_TABLE + "." + LATITUDE + " AND " + PhotoColumn::PHOTOS_TABLE + "." +
968             PhotoColumn::PHOTO_LONGITUDE + " = " + GEO_KNOWLEDGE_TABLE + "." + LONGITUDE + " AND " +
969             GEO_KNOWLEDGE_TABLE + "." + LANGUAGE + " = \'" + language + "\'" };
970         predicates.LeftOuterJoin(GEO_KNOWLEDGE_TABLE)->On(onClause);
971         predicates.EqualTo(PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, fileId);
972     } else {
973         predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
974     }
975     Uri uri(analysisInfo.uriStr);
976     std::vector<std::string> fetchColumn = analysisInfo.fetchColumn;
977     int errCode = 0;
978     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
979     context->analysisData = context->analysisType == ANALYSIS_FACE ?
980         MediaLibraryAniUtils::ParseAnalysisFace2JsonStr(resultSet, fetchColumn) :
981         MediaLibraryAniUtils::ParseResultSet2JsonStr(resultSet, fetchColumn);
982     if (context->analysisData == ANALYSIS_NO_RESULTS) {
983         Uri uri(PAH_QUERY_ANA_TOTAL);
984         DataSharePredicates predicates;
985         std::vector<std::string> fetchColumn = { analysisInfo.fieldStr };
986         predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
987         auto fieldValue = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
988         string value = MediaLibraryAniUtils::ParseResultSet2JsonStr(fieldValue, fetchColumn);
989         if (strstr(value.c_str(), ANALYSIS_INIT_VALUE.c_str()) == NULL) {
990             context->analysisData = ANALYSIS_STATUS_ANALYZED;
991         }
992         MediaLibraryAniUtils::ToAniString(env, value, aniString);
993         return aniString;
994     }
995     return aniString;
996 }
997 
SetHidden(ani_env * env,ani_object object,ani_boolean hiddenState)998 void FileAssetAni::SetHidden([[maybe_unused]] ani_env *env, ani_object object, ani_boolean hiddenState)
999 {
1000     auto fileAssetAni = Unwrap(env, object);
1001     if (fileAssetAni == nullptr || fileAssetAni->fileAssetPtr == nullptr) {
1002         ANI_ERR_LOG("fileAssetAni is nullptr");
1003         return;
1004     }
1005 
1006     if (!MediaLibraryAniUtils::IsSystemApp()) {
1007         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1008         return;
1009     }
1010 
1011     bool isHidden;
1012     MediaLibraryAniUtils::GetBool(env, hiddenState, isHidden);
1013 
1014     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
1015     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
1016     context->objectPtr = fileAssetPtr;
1017     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
1018         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
1019         context->SaveError(-EINVAL);
1020         return;
1021     }
1022 
1023     string uri = UFM_HIDE_PHOTO;
1024     MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1025     Uri updateAssetUri(uri);
1026     DataSharePredicates predicates;
1027     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
1028     DataShareValuesBucket valuesBucket;
1029     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
1030 
1031     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1032     if (changedRows < 0) {
1033         ANI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
1034     } else {
1035         context->SaveError(changedRows);
1036         context->objectPtr->SetHidden(context->isHidden);
1037         context->changedRows = changedRows;
1038     }
1039 
1040     ANI_INFO_LOG("SetHidden ok");
1041 }
1042 
SetFavorite(ani_env * env,ani_object object,ani_boolean favoriteState)1043 void FileAssetAni::SetFavorite([[maybe_unused]] ani_env *env, ani_object object, ani_boolean favoriteState)
1044 {
1045     auto fileAssetAni = Unwrap(env, object);
1046     if (fileAssetAni == nullptr || fileAssetAni->fileAssetPtr == nullptr) {
1047         ANI_ERR_LOG("fileAssetAni is nullptr");
1048         return;
1049     }
1050 
1051     if (!MediaLibraryAniUtils::IsSystemApp()) {
1052         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1053         return;
1054     }
1055 
1056     bool isFavorite;
1057     MediaLibraryAniUtils::GetBool(env, favoriteState, isFavorite);
1058 
1059     auto fileAssetPtr = fileAssetAni->GetFileAssetInstance();
1060     unique_ptr<FileAssetContext> context = make_unique<FileAssetContext>();
1061     context->objectPtr = fileAssetPtr;
1062     string uri;
1063     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1064         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1065         uri = PAH_UPDATE_PHOTO;
1066     } else {
1067         context->SaveError(-EINVAL);
1068         return;
1069     }
1070 
1071     MediaLibraryAniUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1072     Uri updateAssetUri(uri);
1073     DataSharePredicates predicates;
1074     DataShareValuesBucket valuesBucket;
1075     int32_t changedRows = 0;
1076     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
1077     ANI_INFO_LOG("update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
1078         context->isFavorite ? IS_FAV : NOT_FAV);
1079     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
1080     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
1081 
1082     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1083     if (changedRows < 0) {
1084         context->SaveError(changedRows);
1085         ANI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
1086     } else {
1087         context->objectPtr->SetFavorite(context->isFavorite);
1088         context->changedRows = changedRows;
1089     }
1090 
1091     ANI_INFO_LOG("SetFavorite ok");
1092 }
1093 } // namespace OHOS::Media