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