1 /*
2 * Copyright (c) 2024 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 "photo_asset_impl.h"
17
18 #include <algorithm>
19 #include <cstring>
20
21 #include "datashare_errno.h"
22 #include "datashare_predicates.h"
23 #include "datashare_result_set.h"
24 #include "image_type.h"
25 #include "media_column.h"
26 #include "media_file_utils.h"
27 #include "medialibrary_db_const.h"
28 #include "medialibrary_errno.h"
29 #include "pixel_map_impl.h"
30 #include "thumbnail_const.h"
31 #include "thumbnail_utils.h"
32 #include "userfile_client.h"
33 #include "userfilemgr_uri.h"
34
35 using namespace std;
36 using namespace OHOS::DataShare;
37
38 namespace OHOS {
39 namespace Media {
PhotoAssetImpl(unique_ptr<FileAsset> fileAssetPtr_)40 PhotoAssetImpl::PhotoAssetImpl(unique_ptr<FileAsset> fileAssetPtr_)
41 {
42 fileAssetPtr = move(fileAssetPtr_);
43 }
44
PhotoAssetImpl(shared_ptr<FileAsset> fileAssetPtr_)45 PhotoAssetImpl::PhotoAssetImpl(shared_ptr<FileAsset> fileAssetPtr_)
46 {
47 fileAssetPtr = fileAssetPtr_;
48 }
49
GetFileAssetInstance()50 shared_ptr<FileAsset> PhotoAssetImpl::GetFileAssetInstance()
51 {
52 return fileAssetPtr;
53 }
54
GetFileUri()55 string PhotoAssetImpl::GetFileUri()
56 {
57 return fileAssetPtr->GetUri();
58 }
59
GetMediaType()60 Media::MediaType PhotoAssetImpl::GetMediaType()
61 {
62 return fileAssetPtr->GetMediaType();
63 }
64
GetFileDisplayName()65 string PhotoAssetImpl::GetFileDisplayName()
66 {
67 return fileAssetPtr->GetDisplayName();
68 }
69
GetFileId()70 int32_t PhotoAssetImpl::GetFileId()
71 {
72 return fileAssetPtr->GetId();
73 }
74
CheckSystemApiKeys(const string & key)75 static int32_t CheckSystemApiKeys(const string &key)
76 {
77 static const set<string> SYSTEM_API_KEYS = {
78 MediaColumn::MEDIA_DATE_TRASHED,
79 MediaColumn::MEDIA_HIDDEN,
80 PhotoColumn::PHOTO_USER_COMMENT,
81 PhotoColumn::CAMERA_SHOT_KEY,
82 PhotoColumn::MOVING_PHOTO_EFFECT_MODE,
83 PhotoColumn::SUPPORTED_WATERMARK_TYPE,
84 PhotoColumn::PHOTO_IS_AUTO,
85 PhotoColumn::PHOTO_IS_RECENT_SHOW,
86 PhotoColumn::PHOTO_ORIGINAL_SUBTYPE,
87 PENDING_STATUS,
88 MEDIA_DATA_DB_DATE_TRASHED_MS,
89 MEDIA_SUM_SIZE,
90 PhotoColumn::PHOTO_EXIF_ROTATE,
91 };
92
93 if (SYSTEM_API_KEYS.find(key) != SYSTEM_API_KEYS.end() && !MediaLibraryNapiUtils::IsSystemApp()) {
94 LOGE("This key can only be used by system apps");
95 return E_CHECK_SYSTEMAPP_FAIL;
96 }
97 return E_SUCCESS;
98 }
99
HandleDateTransitionKey(const string & key,const shared_ptr<FileAsset> & fileAssetPtr,int32_t & errCode)100 static PhotoAssetMember HandleDateTransitionKey(const string &key,
101 const shared_ptr<FileAsset> &fileAssetPtr, int32_t &errCode)
102 {
103 PhotoAssetMember assetMember = {
104 .memberType = -1,
105 .stringValue = nullptr,
106 .boolValue = false
107 };
108 if (fileAssetPtr->GetMemberMap().count(key) == 0) {
109 errCode = JS_E_FILE_KEY;
110 return assetMember;
111 }
112
113 auto m = fileAssetPtr->GetMemberMap().at(key);
114 if (m.index() == MEMBER_TYPE_INT64) {
115 assetMember.memberType = MEMBER_TYPE_INT32; // int64_t
116 assetMember.intValue = get<int64_t>(m);
117 } else {
118 errCode = JS_ERR_PARAMETER_INVALID;
119 }
120 return assetMember;
121 }
122
IsSpecialKey(const string & key)123 static bool IsSpecialKey(const string &key)
124 {
125 static const set<string> SPECIAL_KEY = {
126 PENDING_STATUS
127 };
128
129 if (SPECIAL_KEY.find(key) != SPECIAL_KEY.end()) {
130 return true;
131 }
132 return false;
133 }
134
HandleGettingSpecialKey(const string & key,const shared_ptr<FileAsset> & fileAssetPtr)135 static PhotoAssetMember HandleGettingSpecialKey(const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
136 {
137 PhotoAssetMember assetMember = {
138 .memberType = -1,
139 .stringValue = nullptr,
140 .boolValue = false
141 };
142 if (key == PENDING_STATUS) {
143 assetMember.memberType = MEMBER_TYPE_STRING; // 2
144 if (fileAssetPtr->GetTimePending() == 0) {
145 assetMember.boolValue = false;
146 } else {
147 assetMember.boolValue = true;
148 }
149 }
150 return assetMember;
151 }
152
GetCompatDate(const string inputKey,const int64_t date)153 static inline int64_t GetCompatDate(const string inputKey, const int64_t date)
154 {
155 if (inputKey == MEDIA_DATA_DB_DATE_ADDED || inputKey == MEDIA_DATA_DB_DATE_MODIFIED ||
156 inputKey == MEDIA_DATA_DB_DATE_TRASHED || inputKey == MEDIA_DATA_DB_DATE_TAKEN) {
157 return date / MSEC_TO_SEC;
158 }
159 return date;
160 }
161
UserFileMgrGet(string & inputKey,int32_t & errCode)162 PhotoAssetMember PhotoAssetImpl::UserFileMgrGet(string &inputKey, int32_t &errCode)
163 {
164 PhotoAssetMember assetMember = {
165 .memberType = -1,
166 .stringValue = nullptr,
167 .boolValue = false
168 };
169 if (CheckSystemApiKeys(inputKey) < 0) {
170 return assetMember;
171 }
172 if (DATE_TRANSITION_MAP.count(inputKey) != 0) {
173 return HandleDateTransitionKey(DATE_TRANSITION_MAP.at(inputKey), fileAssetPtr, errCode);
174 }
175
176 if (fileAssetPtr->GetMemberMap().count(inputKey) == 0) {
177 // no exist throw error
178 errCode = JS_E_FILE_KEY;
179 return assetMember;
180 }
181
182 if (IsSpecialKey(inputKey)) {
183 return HandleGettingSpecialKey(inputKey, fileAssetPtr);
184 }
185
186 auto m = fileAssetPtr->GetMemberMap().at(inputKey);
187 if (m.index() == MEMBER_TYPE_STRING) {
188 assetMember.memberType = MEMBER_TYPE_INT64; // 1
189 assetMember.stringValue = MallocCString(get<string>(m));
190 } else if (m.index() == MEMBER_TYPE_INT32) {
191 assetMember.memberType = MEMBER_TYPE_INT32;
192 assetMember.intValue = static_cast<int64_t>(get<int32_t>(m));
193 } else if (m.index() == MEMBER_TYPE_INT64) {
194 assetMember.memberType = MEMBER_TYPE_INT32;
195 assetMember.intValue = GetCompatDate(inputKey, get<int64_t>(m));
196 } else {
197 errCode = JS_ERR_PARAMETER_INVALID;
198 }
199 return assetMember;
200 }
201
HandleParamSet(const string & inputKey,const string & value,ResultNapiType resultNapiType)202 bool PhotoAssetImpl::HandleParamSet(const string &inputKey, const string &value, ResultNapiType resultNapiType)
203 {
204 if (resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
205 if (inputKey == MediaColumn::MEDIA_TITLE) {
206 fileAssetPtr->SetTitle(value);
207 } else {
208 LOGE("invalid key %{private}s, no support key", inputKey.c_str());
209 return false;
210 }
211 } else if (resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
212 if (inputKey == MediaColumn::MEDIA_NAME) {
213 fileAssetPtr->SetDisplayName(value);
214 fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(value));
215 } else if (inputKey == MediaColumn::MEDIA_TITLE) {
216 fileAssetPtr->SetTitle(value);
217 string displayName = fileAssetPtr->GetDisplayName();
218 if (!displayName.empty()) {
219 string extention = MediaFileUtils::SplitByChar(displayName, '.');
220 fileAssetPtr->SetDisplayName(value + "." + extention);
221 }
222 } else {
223 LOGE("invalid key %{private}s, no support key", inputKey.c_str());
224 return false;
225 }
226 } else {
227 LOGE("invalid resultNapiType");
228 return false;
229 }
230 return true;
231 }
232
UserFileMgrSet(string & inputKey,string & value,int32_t & errCode)233 void PhotoAssetImpl::UserFileMgrSet(string &inputKey, string &value, int32_t &errCode)
234 {
235 if (!HandleParamSet(inputKey, value)) {
236 errCode = JS_E_FILE_KEY;
237 }
238 }
239
CommitModify(int32_t & errCode)240 void PhotoAssetImpl::CommitModify(int32_t &errCode)
241 {
242 string uri;
243 if (fileAssetPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
244 fileAssetPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
245 uri = PAH_UPDATE_PHOTO;
246 } else if (fileAssetPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
247 uri = UFM_UPDATE_AUDIO;
248 }
249 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
250
251 Uri updateAssetUri(uri);
252 MediaType mediaType = fileAssetPtr->GetMediaType();
253 string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
254 DataSharePredicates predicates;
255 DataShareValuesBucket valuesBucket;
256 valuesBucket.Put(MediaColumn::MEDIA_TITLE, fileAssetPtr->GetTitle());
257 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
258 predicates.SetWhereArgs({to_string(fileAssetPtr->GetId())});
259
260 int32_t changedRows = static_cast<int32_t>(UserFileClient::Update(updateAssetUri, predicates, valuesBucket));
261 if (changedRows < 0) {
262 errCode = static_cast<int32_t>(MediaLibraryNapiUtils::TransErrorCode("CommitModify", changedRows));
263 LOGE("File asset modification failed, err: %{public}d", changedRows);
264 } else {
265 Uri modifyNotify(notifyUri);
266 UserFileClient::NotifyChange(modifyNotify);
267 }
268 }
269
GetThumbnail(CSize cSize,int32_t & errCode)270 int64_t PhotoAssetImpl::GetThumbnail(CSize cSize, int32_t &errCode)
271 {
272 int result = -1;
273 Size size = {
274 .width = cSize.width < 0 ? DEFAULT_THUMB_SIZE : cSize.width,
275 .height = cSize.height < 0 ? DEFAULT_THUMB_SIZE : cSize.height
276 };
277 string path = fileAssetPtr->GetPath();
278 #ifndef MEDIALIBRARY_COMPATIBILITY
279 if (path.empty()
280 && !fileAssetPtr->GetRelativePath().empty() && !fileAssetPtr->GetDisplayName().empty()) {
281 path = ROOT_MEDIA_DIR + fileAssetPtr->GetRelativePath() + fileAssetPtr->GetDisplayName();
282 }
283 #endif
284 auto pixelmap = ThumbnailManager::QueryThumbnail(fileAssetPtr->GetUri(), size, path);
285 if (pixelmap != nullptr) {
286 std::shared_ptr<PixelMap> pixelmapSptr = move(pixelmap);
287 auto native = FFIData::Create<PixelMapImpl>(pixelmapSptr);
288 if (native != nullptr) {
289 result = native->GetID();
290 } else {
291 LOGE("Create native PixelMapImpl failed.");
292 errCode = JS_INNER_FAIL;
293 }
294 } else {
295 LOGE("Create PixelMapImpl failed.");
296 errCode = JS_INNER_FAIL;
297 }
298 return result;
299 }
300 }
301 }