1 /*
2 * Copyright (C) 2023 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 "medialibrary_photo_operations.h"
17
18 #include <memory>
19
20 #include "abs_shared_result_set.h"
21 #include "file_asset.h"
22 #include "media_column.h"
23 #include "media_file_uri.h"
24 #include "media_file_utils.h"
25 #include "media_log.h"
26 #include "medialibrary_album_operations.h"
27 #include "medialibrary_asset_operations.h"
28 #include "medialibrary_command.h"
29 #include "medialibrary_data_manager_utils.h"
30 #include "medialibrary_db_const.h"
31 #include "medialibrary_errno.h"
32 #include "medialibrary_notify.h"
33 #include "medialibrary_object_utils.h"
34 #include "medialibrary_rdbstore.h"
35 #include "medialibrary_tracer.h"
36 #include "medialibrary_type_const.h"
37 #include "medialibrary_uripermission_operations.h"
38 #include "photo_album_column.h"
39 #include "photo_map_column.h"
40 #include "photo_map_operations.h"
41 #include "rdb_predicates.h"
42 #include "result_set_utils.h"
43 #include "thumbnail_const.h"
44 #include "userfile_manager_types.h"
45 #include "value_object.h"
46 #include "values_bucket.h"
47
48 using namespace OHOS::DataShare;
49 using namespace std;
50 using namespace OHOS::NativeRdb;
51 using namespace OHOS::RdbDataShareAdapter;
52
53 namespace OHOS {
54 namespace Media {
55
Create(MediaLibraryCommand & cmd)56 int32_t MediaLibraryPhotoOperations::Create(MediaLibraryCommand &cmd)
57 {
58 switch (cmd.GetApi()) {
59 case MediaLibraryApi::API_10:
60 return CreateV10(cmd);
61 case MediaLibraryApi::API_OLD:
62 return CreateV9(cmd);
63 default:
64 MEDIA_ERR_LOG("get api failed");
65 return E_FAIL;
66 }
67 }
68
Delete(MediaLibraryCommand & cmd)69 int32_t MediaLibraryPhotoOperations::Delete(MediaLibraryCommand& cmd)
70 {
71 string fileId = cmd.GetOprnFileId();
72 vector<string> columns = {
73 PhotoColumn::MEDIA_ID,
74 PhotoColumn::MEDIA_FILE_PATH,
75 PhotoColumn::MEDIA_RELATIVE_PATH,
76 PhotoColumn::MEDIA_TYPE
77 };
78 shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(PhotoColumn::MEDIA_ID,
79 fileId, cmd.GetOprnObject(), columns);
80 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_INVALID_FILEID, "Get fileAsset failed, fileId: %{public}s",
81 fileId.c_str());
82 int32_t deleteRow = DeletePhoto(fileAsset, cmd.GetApi());
83 CHECK_AND_RETURN_RET_LOG(deleteRow >= 0, deleteRow, "delete photo failed, deleteRow=%{public}d", deleteRow);
84
85 return deleteRow;
86 }
87
HandleGroupBy(AbsPredicates & predicates,const vector<string> & columns)88 static void HandleGroupBy(AbsPredicates &predicates, const vector<string> &columns)
89 {
90 auto it = find(columns.begin(), columns.end(), MEDIA_COLUMN_COUNT);
91 if (it == columns.end()) {
92 return;
93 }
94 if (!predicates.GetGroup().empty()) {
95 return;
96 }
97 string whereClause = predicates.GetWhereClause();
98 predicates.SetWhereClause(whereClause +
99 " GROUP BY (DATE(date_added, 'unixepoch', 'localtime')) ORDER BY date_added DESC ");
100 }
101
GetAlbumTypeSubTypeById(const string & albumId,PhotoAlbumType & type,PhotoAlbumSubType & subType)102 static int32_t GetAlbumTypeSubTypeById(const string &albumId, PhotoAlbumType &type, PhotoAlbumSubType &subType)
103 {
104 RdbPredicates predicates(PhotoAlbumColumns::TABLE);
105 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, albumId);
106 vector<string> columns = { PhotoAlbumColumns::ALBUM_TYPE, PhotoAlbumColumns::ALBUM_SUBTYPE };
107 auto resultSet = MediaLibraryRdbStore::Query(predicates, columns);
108 if (resultSet == nullptr) {
109 MEDIA_ERR_LOG("album id %{private}s is not exist", albumId.c_str());
110 return E_INVALID_ARGUMENTS;
111 }
112 CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK, E_INVALID_ARGUMENTS,
113 "album id is not exist");
114 type = static_cast<PhotoAlbumType>(GetInt32Val(PhotoAlbumColumns::ALBUM_TYPE, resultSet));
115 subType = static_cast<PhotoAlbumSubType>(GetInt32Val(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet));
116 return E_SUCCESS;
117 }
118
GetPredicatesByAlbumId(const string & albumId,RdbPredicates & predicates)119 static int32_t GetPredicatesByAlbumId(const string &albumId, RdbPredicates &predicates)
120 {
121 PhotoAlbumType type;
122 PhotoAlbumSubType subType;
123 CHECK_AND_RETURN_RET_LOG(GetAlbumTypeSubTypeById(albumId, type, subType) == E_SUCCESS, E_INVALID_ARGUMENTS,
124 "invalid album uri");
125
126 if ((!PhotoAlbum::CheckPhotoAlbumType(type)) || (!PhotoAlbum::CheckPhotoAlbumSubType(subType))) {
127 MEDIA_ERR_LOG("album id %{private}s type:%d subtype:%d", albumId.c_str(), type, subType);
128 return E_INVALID_ARGUMENTS;
129 }
130
131 if (PhotoAlbum::IsUserPhotoAlbum(type, subType)) {
132 PhotoAlbumColumns::GetUserAlbumPredicates(stoi(albumId), predicates);
133 return E_SUCCESS;
134 }
135
136 if ((type != PhotoAlbumType::SYSTEM) || (subType == PhotoAlbumSubType::USER_GENERIC) ||
137 (subType == PhotoAlbumSubType::ANY)) {
138 MEDIA_ERR_LOG("album id %{private}s type:%d subtype:%d", albumId.c_str(), type, subType);
139 return E_INVALID_ARGUMENTS;
140 }
141 PhotoAlbumColumns::GetSystemAlbumPredicates(subType, predicates);
142 return E_SUCCESS;
143 }
144
GetValidOrderClause(const DataSharePredicates & predicate,string & clause)145 static bool GetValidOrderClause(const DataSharePredicates &predicate, string &clause)
146 {
147 constexpr int32_t FIELD_IDX = 0;
148 vector<OperationItem> operations;
149 const auto &items = predicate.GetOperationList();
150 int32_t count = 0;
151 clause = "ROW_NUMBER() OVER (ORDER BY ";
152 for (const auto &item : items) {
153 if (item.operation == ORDER_BY_ASC) {
154 count++;
155 clause += static_cast<string>(item.GetSingle(FIELD_IDX)) + " ASC) as " + PHOTO_INDEX;
156 } else if (item.operation == ORDER_BY_DESC) {
157 count++;
158 clause += static_cast<string>(item.GetSingle(FIELD_IDX)) + " DESC) as " + PHOTO_INDEX;
159 }
160 }
161
162 // only support orderby with one item
163 return (count == 1);
164 }
165
HandleAlbumIndexOfUri(const vector<string> & columns,const string & photoId,const string & albumId)166 static shared_ptr<NativeRdb::ResultSet> HandleAlbumIndexOfUri(const vector<string> &columns, const string &photoId,
167 const string &albumId)
168 {
169 RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
170 CHECK_AND_RETURN_RET_LOG(GetPredicatesByAlbumId(albumId, predicates) == E_SUCCESS, nullptr, "invalid album uri");
171 return MediaLibraryRdbStore::GetIndexOfUri(predicates, columns, photoId);
172 }
173
HandleIndexOfUri(MediaLibraryCommand & cmd,RdbPredicates & predicates,const string & photoId,const string & albumId)174 static shared_ptr<NativeRdb::ResultSet> HandleIndexOfUri(MediaLibraryCommand &cmd, RdbPredicates &predicates,
175 const string &photoId, const string &albumId)
176 {
177 string orderClause;
178 CHECK_AND_RETURN_RET_LOG(GetValidOrderClause(cmd.GetDataSharePred(), orderClause), nullptr, "invalid orderby");
179 vector<string> columns;
180 columns.push_back(orderClause);
181 columns.push_back(MediaColumn::MEDIA_ID);
182 if (!albumId.empty()) {
183 return HandleAlbumIndexOfUri(columns, photoId, albumId);
184 } else {
185 predicates.And()->EqualTo(
186 PhotoColumn::PHOTO_SYNC_STATUS, std::to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)));
187 return MediaLibraryRdbStore::GetIndexOfUri(predicates, columns, photoId);
188 }
189 }
190
Query(MediaLibraryCommand & cmd,const vector<string> & columns)191 shared_ptr<NativeRdb::ResultSet> MediaLibraryPhotoOperations::Query(
192 MediaLibraryCommand &cmd, const vector<string> &columns)
193 {
194 RdbPredicates predicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
195 if (cmd.GetOprnType() == OperationType::INDEX) {
196 constexpr int32_t COLUMN_SIZE = 2;
197 CHECK_AND_RETURN_RET_LOG(columns.size() >= COLUMN_SIZE, nullptr, "invalid id param");
198 constexpr int32_t PHOTO_ID_INDEX = 0;
199 constexpr int32_t ALBUM_ID_INDEX = 1;
200 string photoId = columns[PHOTO_ID_INDEX];
201 string albumId;
202 if (!columns[ALBUM_ID_INDEX].empty()) {
203 albumId = columns[ALBUM_ID_INDEX];
204 }
205 return HandleIndexOfUri(cmd, predicates, photoId, albumId);
206 } else {
207 HandleGroupBy(predicates, columns);
208 return MediaLibraryRdbStore::Query(predicates, columns);
209 }
210 }
211
Update(MediaLibraryCommand & cmd)212 int32_t MediaLibraryPhotoOperations::Update(MediaLibraryCommand &cmd)
213 {
214 switch (cmd.GetApi()) {
215 case MediaLibraryApi::API_10:
216 return UpdateV10(cmd);
217 case MediaLibraryApi::API_OLD:
218 return UpdateV9(cmd);
219 default:
220 MEDIA_ERR_LOG("get api failed");
221 return E_FAIL;
222 }
223
224 return E_OK;
225 }
226
227 // temp function, delete after MediaFileUri::Getpath is finish
GetPathFromUri(const std::string & uri)228 static string GetPathFromUri(const std::string &uri)
229 {
230 string realTitle = uri;
231 size_t index = uri.rfind('/');
232 if (index == string::npos) {
233 return "";
234 }
235 realTitle = uri.substr(0, index);
236 index = realTitle.rfind('/');
237 if (index == string::npos) {
238 return "";
239 }
240 realTitle = realTitle.substr(index + 1);
241 index = realTitle.rfind('_');
242 if (index == string::npos) {
243 return "";
244 }
245 int32_t fileUniqueId = stoi(realTitle.substr(index + 1));
246 int32_t bucketNum = 0;
247 MediaLibraryAssetOperations::CreateAssetBucket(fileUniqueId, bucketNum);
248 string ext = MediaFileUtils::GetExtensionFromPath(uri);
249 if (ext.empty()) {
250 return "";
251 }
252
253 string path = ROOT_MEDIA_DIR + PHOTO_BUCKET + "/" + to_string(bucketNum) + "/" + realTitle + "." + ext;
254 if (!MediaFileUtils::IsFileExists(path)) {
255 MEDIA_ERR_LOG("file not exist, path=%{private}s", path.c_str());
256 return "";
257 }
258 return path;
259 }
260
261 const static vector<string> PHOTO_COLUMN_VECTOR = {
262 PhotoColumn::MEDIA_FILE_PATH,
263 PhotoColumn::MEDIA_TYPE,
264 PhotoColumn::MEDIA_TIME_PENDING
265 };
266
Open(MediaLibraryCommand & cmd,const string & mode)267 int32_t MediaLibraryPhotoOperations::Open(MediaLibraryCommand &cmd, const string &mode)
268 {
269 MediaLibraryTracer tracer;
270 tracer.Start("MediaLibraryPhotoOperations::Open");
271
272 string uriString = cmd.GetUriStringWithoutSegment();
273 string id = MediaLibraryDataManagerUtils::GetIdFromUri(uriString);
274 if (uriString.empty() || (!MediaLibraryDataManagerUtils::IsNumber(id))) {
275 return E_INVALID_URI;
276 }
277
278 shared_ptr<FileAsset> fileAsset = make_shared<FileAsset>();
279 string pendingStatus = cmd.GetQuerySetParam(MediaColumn::MEDIA_TIME_PENDING);
280 MediaFileUri fileUri(uriString);
281 if (pendingStatus.empty() || !fileUri.IsApi10()) {
282 fileAsset = GetFileAssetFromDb(PhotoColumn::MEDIA_ID, id, OperationObject::FILESYSTEM_PHOTO,
283 PHOTO_COLUMN_VECTOR);
284 if (fileAsset == nullptr) {
285 MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
286 return E_INVALID_URI;
287 }
288 } else {
289 string path = GetPathFromUri(uriString);
290 if (path.empty()) {
291 fileAsset = GetFileAssetFromDb(PhotoColumn::MEDIA_ID, id, OperationObject::FILESYSTEM_PHOTO,
292 PHOTO_COLUMN_VECTOR);
293 if (fileAsset == nullptr) {
294 MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
295 return E_INVALID_URI;
296 }
297 } else {
298 fileAsset->SetPath(path);
299 fileAsset->SetMediaType(MediaFileUtils::GetMediaType(path));
300 int32_t timePending = stoi(pendingStatus);
301 fileAsset->SetTimePending((timePending > 0) ? MediaFileUtils::UTCTimeSeconds() : timePending);
302 }
303 }
304
305 fileAsset->SetId(stoi(id));
306 fileAsset->SetUri(uriString);
307
308 if (uriString.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
309 return OpenAsset(fileAsset, mode, MediaLibraryApi::API_10);
310 }
311 return OpenAsset(fileAsset, mode, cmd.GetApi());
312 }
313
Close(MediaLibraryCommand & cmd)314 int32_t MediaLibraryPhotoOperations::Close(MediaLibraryCommand &cmd)
315 {
316 const ValuesBucket &values = cmd.GetValueBucket();
317 string uriString;
318 if (!GetStringFromValuesBucket(values, MEDIA_DATA_DB_URI, uriString)) {
319 return E_INVALID_VALUES;
320 }
321 string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(uriString);
322 if (uriString.empty() || (!MediaLibraryDataManagerUtils::IsNumber(fileId))) {
323 return E_INVALID_URI;
324 }
325
326 shared_ptr<FileAsset> fileAsset = make_shared<FileAsset>();
327 string pendingStatus = cmd.GetQuerySetParam(MediaColumn::MEDIA_TIME_PENDING);
328 MediaFileUri fileUri(uriString);
329 if (pendingStatus.empty() || !fileUri.IsApi10()) {
330 fileAsset = GetFileAssetFromDb(PhotoColumn::MEDIA_ID, fileId, OperationObject::FILESYSTEM_PHOTO,
331 PHOTO_COLUMN_VECTOR);
332 if (fileAsset == nullptr) {
333 MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
334 return E_INVALID_URI;
335 }
336 } else {
337 string path = GetPathFromUri(uriString);
338 if (path.empty()) {
339 fileAsset = GetFileAssetFromDb(PhotoColumn::MEDIA_ID, fileId, OperationObject::FILESYSTEM_PHOTO,
340 PHOTO_COLUMN_VECTOR);
341 if (fileAsset == nullptr) {
342 MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
343 return E_INVALID_URI;
344 }
345 } else {
346 fileAsset->SetPath(path);
347 fileAsset->SetMediaType(MediaFileUtils::GetMediaType(path));
348 int32_t timePending = stoi(pendingStatus);
349 fileAsset->SetTimePending((timePending > 0) ? MediaFileUtils::UTCTimeSeconds() : timePending);
350 }
351 }
352
353 fileAsset->SetId(stoi(fileId));
354 fileAsset->SetUri(uriString);
355
356 int32_t isSync = 0;
357 int32_t errCode = 0;
358 if (GetInt32FromValuesBucket(cmd.GetValueBucket(), CLOSE_CREATE_THUMB_STATUS, isSync) &&
359 isSync == CREATE_THUMB_SYNC_STATUS) {
360 errCode = CloseAsset(fileAsset, true);
361 } else {
362 errCode = CloseAsset(fileAsset, false);
363 }
364 return errCode;
365 }
366
SetPhotoTypeByRelativePath(const string & relativePath,FileAsset & fileAsset)367 static inline void SetPhotoTypeByRelativePath(const string &relativePath, FileAsset &fileAsset)
368 {
369 int32_t subType = static_cast<int32_t>(PhotoSubType::DEFAULT);
370 if (relativePath.compare(CAMERA_PATH) == 0) {
371 subType = static_cast<int32_t>(PhotoSubType::CAMERA);
372 } else if (relativePath.compare(SCREEN_RECORD_PATH) == 0 ||
373 relativePath.compare(SCREEN_SHOT_PATH) == 0) {
374 subType = static_cast<int32_t>(PhotoSubType::SCREENSHOT);
375 }
376
377 fileAsset.SetPhotoSubType(subType);
378 }
379
SetPhotoSubTypeFromCmd(MediaLibraryCommand & cmd,FileAsset & fileAsset)380 static inline void SetPhotoSubTypeFromCmd(MediaLibraryCommand &cmd, FileAsset &fileAsset)
381 {
382 int32_t subType = static_cast<int32_t>(PhotoSubType::DEFAULT);
383 ValueObject value;
384 if (cmd.GetValueBucket().GetObject(PhotoColumn::PHOTO_SUBTYPE, value)) {
385 value.GetInt(subType);
386 }
387 fileAsset.SetPhotoSubType(subType);
388 }
389
SetCameraShotKeyFromCmd(MediaLibraryCommand & cmd,FileAsset & fileAsset)390 static inline void SetCameraShotKeyFromCmd(MediaLibraryCommand &cmd, FileAsset &fileAsset)
391 {
392 string cameraShotKey;
393 ValueObject value;
394 if (cmd.GetValueBucket().GetObject(PhotoColumn::CAMERA_SHOT_KEY, value)) {
395 value.GetString(cameraShotKey);
396 }
397 fileAsset.SetCameraShotKey(cameraShotKey);
398 }
399
CreateV9(MediaLibraryCommand & cmd)400 int32_t MediaLibraryPhotoOperations::CreateV9(MediaLibraryCommand& cmd)
401 {
402 FileAsset fileAsset;
403 ValuesBucket &values = cmd.GetValueBucket();
404
405 string displayName;
406 CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, PhotoColumn::MEDIA_NAME, displayName),
407 E_HAS_DB_ERROR);
408 fileAsset.SetDisplayName(displayName);
409
410 string relativePath;
411 CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, PhotoColumn::MEDIA_RELATIVE_PATH, relativePath),
412 E_HAS_DB_ERROR);
413 fileAsset.SetRelativePath(relativePath);
414 MediaFileUtils::FormatRelativePath(relativePath);
415
416 int32_t mediaType = 0;
417 CHECK_AND_RETURN_RET(GetInt32FromValuesBucket(values, PhotoColumn::MEDIA_TYPE, mediaType),
418 E_HAS_DB_ERROR);
419 fileAsset.SetMediaType(static_cast<MediaType>(mediaType));
420
421 int32_t errCode = CheckRelativePathWithType(relativePath, mediaType);
422 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to Check RelativePath and Extention, "
423 "relativePath=%{private}s, mediaType=%{public}d", relativePath.c_str(), mediaType);
424 SetPhotoTypeByRelativePath(relativePath, fileAsset);
425 errCode = CheckDisplayNameWithType(displayName, mediaType);
426 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to Check Dir and Extention, "
427 "displayName=%{private}s, mediaType=%{public}d", displayName.c_str(), mediaType);
428
429 TransactionOperations transactionOprn;
430 errCode = transactionOprn.Start();
431 if (errCode != E_OK) {
432 return errCode;
433 }
434
435 errCode = SetAssetPathInCreate(fileAsset);
436 if (errCode != E_OK) {
437 MEDIA_ERR_LOG("Failed to Solve FileAsset Path and Name, displayName=%{private}s", displayName.c_str());
438 return errCode;
439 }
440
441 int32_t outRow = InsertAssetInDb(cmd, fileAsset);
442 if (outRow <= 0) {
443 MEDIA_ERR_LOG("insert file in db failed, error = %{public}d", outRow);
444 return E_HAS_DB_ERROR;
445 }
446 transactionOprn.Finish();
447 return outRow;
448 }
449
PhotoMapAddAsset(const int & albumId,const string & assetId,const string & extrUri)450 void PhotoMapAddAsset(const int &albumId, const string &assetId, const string &extrUri)
451 {
452 static const string INSERT_MAP_SQL = "INSERT INTO " + PhotoMap::TABLE +
453 " (" + PhotoMap::ALBUM_ID + ", " + PhotoMap::ASSET_ID + ") " +
454 "SELECT ?, ? WHERE " +
455 "(NOT EXISTS (SELECT * FROM " + PhotoMap::TABLE + " WHERE " +
456 PhotoMap::ALBUM_ID + " = ? AND " + PhotoMap::ASSET_ID + " = ?)) " +
457 "AND (EXISTS (SELECT " + MediaColumn::MEDIA_ID + " FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " +
458 MediaColumn::MEDIA_ID + " = ?)) " +
459 "AND (EXISTS (SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " + PhotoAlbumColumns::TABLE +
460 " WHERE " + PhotoAlbumColumns::ALBUM_ID + " = ? AND " + PhotoAlbumColumns::ALBUM_TYPE + " = ? AND " +
461 PhotoAlbumColumns::ALBUM_SUBTYPE + " = ?));";
462
463 vector<ValueObject> bindArgs = { albumId, assetId, albumId, assetId, assetId, albumId, PhotoAlbumType::USER,
464 PhotoAlbumSubType::USER_GENERIC };
465 int errCode = MediaLibraryRdbStore::ExecuteForLastInsertedRowId(INSERT_MAP_SQL, bindArgs);
466 auto watch = MediaLibraryNotify::GetInstance();
467 if (errCode > 0) {
468 watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, assetId, extrUri),
469 NotifyType::NOTIFY_ALBUM_ADD_ASSERT, albumId);
470 }
471 }
472
SolvePhotoAlbumInCreate(MediaLibraryCommand & cmd,FileAsset & fileAsset)473 void MediaLibraryPhotoOperations::SolvePhotoAlbumInCreate(MediaLibraryCommand &cmd, FileAsset &fileAsset)
474 {
475 ValuesBucket &values = cmd.GetValueBucket();
476 string albumUri;
477 GetStringFromValuesBucket(values, MEDIA_DATA_DB_ALARM_URI, albumUri);
478 if (!albumUri.empty()) {
479 PhotoMapAddAsset(stoi(MediaLibraryDataManagerUtils::GetIdFromUri(albumUri)), to_string(fileAsset.GetId()),
480 MediaFileUtils::GetExtraUri(fileAsset.GetDisplayName(), fileAsset.GetPath()));
481 }
482 }
483
CreateV10(MediaLibraryCommand & cmd)484 int32_t MediaLibraryPhotoOperations::CreateV10(MediaLibraryCommand& cmd)
485 {
486 FileAsset fileAsset;
487 ValuesBucket &values = cmd.GetValueBucket();
488 string displayName;
489 string extention;
490 string title;
491 bool isContains = false;
492 bool isNeedGrant = false;
493 if (GetStringFromValuesBucket(values, PhotoColumn::MEDIA_NAME, displayName)) {
494 fileAsset.SetDisplayName(displayName);
495 fileAsset.SetTimePending(UNCREATE_FILE_TIMEPENDING);
496 isContains = true;
497 } else {
498 CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, ASSET_EXTENTION, extention), E_HAS_DB_ERROR);
499 isNeedGrant = true;
500 fileAsset.SetTimePending(UNOPEN_FILE_COMPONENT_TIMEPENDING);
501 if (GetStringFromValuesBucket(values, PhotoColumn::MEDIA_TITLE, title)) {
502 displayName = title + "." + extention;
503 fileAsset.SetDisplayName(displayName);
504 isContains = true;
505 }
506 }
507 int32_t mediaType = 0;
508 CHECK_AND_RETURN_RET(GetInt32FromValuesBucket(values, PhotoColumn::MEDIA_TYPE, mediaType), E_HAS_DB_ERROR);
509 fileAsset.SetMediaType(static_cast<MediaType>(mediaType));
510 SetPhotoSubTypeFromCmd(cmd, fileAsset);
511 SetCameraShotKeyFromCmd(cmd, fileAsset);
512 // Check rootdir and extention
513 int32_t errCode = CheckWithType(isContains, displayName, extention, mediaType);
514 CHECK_AND_RETURN_RET(errCode == E_OK, errCode);
515 TransactionOperations transactionOprn;
516 errCode = transactionOprn.Start();
517 CHECK_AND_RETURN_RET(errCode == E_OK, errCode);
518 errCode = isContains ? SetAssetPathInCreate(fileAsset) : SetAssetPath(fileAsset, extention);
519 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode,
520 "Failed to Solve FileAsset Path and Name, displayName=%{private}s", displayName.c_str());
521 int32_t outRow = InsertAssetInDb(cmd, fileAsset);
522 CHECK_AND_RETURN_RET_LOG(outRow > 0, errCode, "insert file in db failed, error = %{public}d", outRow);
523 fileAsset.SetId(outRow);
524 SolvePhotoAlbumInCreate(cmd, fileAsset);
525 transactionOprn.Finish();
526 string fileUri = CreateExtUriForV10Asset(fileAsset);
527 if (isNeedGrant) {
528 int32_t ret = GrantUriPermission(fileUri, cmd.GetBundleName(), fileAsset.GetPath());
529 CHECK_AND_RETURN_RET(ret == E_OK, ret);
530 }
531 cmd.SetResult(fileUri);
532 return outRow;
533 }
534
DeletePhoto(const shared_ptr<FileAsset> & fileAsset,MediaLibraryApi api)535 int32_t MediaLibraryPhotoOperations::DeletePhoto(const shared_ptr<FileAsset> &fileAsset, MediaLibraryApi api)
536 {
537 string filePath = fileAsset->GetPath();
538 CHECK_AND_RETURN_RET_LOG(!filePath.empty(), E_INVALID_PATH, "get file path failed");
539 bool res = MediaFileUtils::DeleteFile(filePath);
540 CHECK_AND_RETURN_RET_LOG(res, E_HAS_FS_ERROR, "Delete photo file failed, errno: %{public}d", errno);
541
542 // delete thumbnail
543 int32_t fileId = fileAsset->GetId();
544 InvalidateThumbnail(to_string(fileId), fileAsset->GetMediaType());
545
546 TransactionOperations transactionOprn;
547 int32_t errCode = transactionOprn.Start();
548 if (errCode != E_OK) {
549 return errCode;
550 }
551
552 string displayName = fileAsset->GetDisplayName();
553 // delete file in db
554 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::DELETE);
555 cmd.GetAbsRdbPredicates()->EqualTo(PhotoColumn::MEDIA_ID, to_string(fileId));
556 int32_t deleteRows = DeleteAssetInDb(cmd);
557 if (deleteRows <= 0) {
558 MEDIA_ERR_LOG("Delete photo in database failed, errCode=%{public}d", deleteRows);
559 return E_HAS_DB_ERROR;
560 }
561
562 transactionOprn.Finish();
563 auto watch = MediaLibraryNotify::GetInstance();
564
565 string notifyDeleteUri =
566 MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(deleteRows),
567 (api == MediaLibraryApi::API_10 ? MediaFileUtils::GetExtraUri(displayName, filePath) : ""));
568 watch->Notify(notifyDeleteUri, NotifyType::NOTIFY_REMOVE);
569 return deleteRows;
570 }
571
TrashPhotosSendNotify(vector<string> & notifyUris)572 static void TrashPhotosSendNotify(vector<string> ¬ifyUris)
573 {
574 auto watch = MediaLibraryNotify::GetInstance();
575 int trashAlbumId = watch->GetAlbumIdBySubType(PhotoAlbumSubType::TRASH);
576 if (trashAlbumId <= 0) {
577 return;
578 }
579
580 for (const auto ¬ifyUri : notifyUris) {
581 watch->Notify(notifyUri, NotifyType::NOTIFY_REMOVE);
582 watch->Notify(notifyUri, NotifyType::NOTIFY_ALBUM_REMOVE_ASSET);
583 watch->Notify(notifyUri, NotifyType::NOTIFY_ALBUM_ADD_ASSERT, trashAlbumId);
584 }
585 }
586
TrashPhotos(MediaLibraryCommand & cmd)587 int32_t MediaLibraryPhotoOperations::TrashPhotos(MediaLibraryCommand &cmd)
588 {
589 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
590 if (rdbStore == nullptr) {
591 return E_HAS_DB_ERROR;
592 }
593
594 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(cmd.GetDataSharePred(),
595 PhotoColumn::PHOTOS_TABLE);
596 vector<string> notifyUris;
597 MediaLibraryNotify::GetNotifyUris(rdbPredicate, notifyUris);
598 ValuesBucket values;
599 values.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
600 cmd.SetValueBucket(values);
601 int32_t updatedRows = rdbStore->Update(values, rdbPredicate);
602 if (updatedRows < 0) {
603 MEDIA_ERR_LOG("Trash photo failed. Result %{public}d.", updatedRows);
604 return E_HAS_DB_ERROR;
605 }
606
607 MediaLibraryAlbumOperations::UpdateUserAlbumInternal();
608 MediaLibraryAlbumOperations::UpdateSystemAlbumInternal();
609 if (static_cast<size_t>(updatedRows) != notifyUris.size()) {
610 MEDIA_WARN_LOG("Try to notify %{public}zu items, but only %{public}d items updated.",
611 notifyUris.size(), updatedRows);
612 }
613 TrashPhotosSendNotify(notifyUris);
614 return updatedRows;
615 }
616
UpdateV10(MediaLibraryCommand & cmd)617 int32_t MediaLibraryPhotoOperations::UpdateV10(MediaLibraryCommand &cmd)
618 {
619 if (cmd.GetOprnType() == OperationType::TRASH_PHOTO) {
620 return TrashPhotos(cmd);
621 } else if (cmd.GetOprnType() == OperationType::UPDATE_PENDING) {
622 return SetPendingStatus(cmd);
623 }
624
625 vector<string> columns = {
626 PhotoColumn::MEDIA_ID,
627 PhotoColumn::MEDIA_FILE_PATH,
628 PhotoColumn::MEDIA_TYPE,
629 PhotoColumn::MEDIA_NAME
630 };
631 shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
632 OperationObject::FILESYSTEM_PHOTO, columns);
633 if (fileAsset == nullptr) {
634 return E_INVALID_VALUES;
635 }
636
637 int32_t errCode;
638 if (cmd.GetOprnType() == OperationType::SET_USER_COMMENT) {
639 errCode = SetUserComment(cmd, fileAsset);
640 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Edit user comment errCode = %{private}d", errCode);
641 }
642
643 // Update if FileAsset.title or FileAsset.displayName is modified
644 bool isNameChanged = false;
645 errCode = UpdateFileName(cmd, fileAsset, isNameChanged);
646 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Photo Name failed, fileName=%{private}s",
647 fileAsset->GetDisplayName().c_str());
648
649 TransactionOperations transactionOprn;
650 errCode = transactionOprn.Start();
651 if (errCode != E_OK) {
652 return errCode;
653 }
654
655 int32_t rowId = UpdateFileInDb(cmd);
656 if (rowId < 0) {
657 MEDIA_ERR_LOG("Update Photo In database failed, rowId=%{public}d", rowId);
658 return rowId;
659 }
660 transactionOprn.Finish();
661
662 string extraUri = MediaFileUtils::GetExtraUri(fileAsset->GetDisplayName(), fileAsset->GetPath());
663 errCode = SendTrashNotify(cmd, fileAsset->GetId(), extraUri);
664 if (errCode == E_OK) {
665 return rowId;
666 }
667 SendFavoriteNotify(cmd, fileAsset->GetId(), extraUri);
668 SendHideNotify(cmd, fileAsset->GetId(), extraUri);
669 SendModifyUserCommentNotify(cmd, fileAsset->GetId(), extraUri);
670 auto watch = MediaLibraryNotify::GetInstance();
671 watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileAsset->GetId()),
672 extraUri), NotifyType::NOTIFY_UPDATE);
673 return rowId;
674 }
675
UpdateV9(MediaLibraryCommand & cmd)676 int32_t MediaLibraryPhotoOperations::UpdateV9(MediaLibraryCommand &cmd)
677 {
678 vector<string> columns = {
679 PhotoColumn::MEDIA_ID,
680 PhotoColumn::MEDIA_FILE_PATH,
681 PhotoColumn::MEDIA_TYPE,
682 PhotoColumn::MEDIA_NAME,
683 PhotoColumn::MEDIA_RELATIVE_PATH
684 };
685 shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
686 OperationObject::FILESYSTEM_PHOTO, columns);
687 if (fileAsset == nullptr) {
688 return E_INVALID_VALUES;
689 }
690
691 // Update if FileAsset.title or FileAsset.displayName is modified
692 bool isNameChanged = false;
693 int32_t errCode = UpdateFileName(cmd, fileAsset, isNameChanged);
694 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Photo Name failed, fileName=%{private}s",
695 fileAsset->GetDisplayName().c_str());
696 errCode = UpdateRelativePath(cmd, fileAsset, isNameChanged);
697 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Photo RelativePath failed, relativePath=%{private}s",
698 fileAsset->GetRelativePath().c_str());
699 if (isNameChanged) {
700 UpdateVirtualPath(cmd, fileAsset);
701 }
702
703 TransactionOperations transactionOprn;
704 errCode = transactionOprn.Start();
705 if (errCode != E_OK) {
706 return errCode;
707 }
708
709 int32_t rowId = UpdateFileInDb(cmd);
710 if (rowId < 0) {
711 MEDIA_ERR_LOG("Update Photo In database failed, rowId=%{public}d", rowId);
712 return rowId;
713 }
714 transactionOprn.Finish();
715
716 errCode = SendTrashNotify(cmd, fileAsset->GetId());
717 if (errCode == E_OK) {
718 return rowId;
719 }
720 SendFavoriteNotify(cmd, fileAsset->GetId());
721 auto watch = MediaLibraryNotify::GetInstance();
722 watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileAsset->GetId())),
723 NotifyType::NOTIFY_UPDATE);
724 return rowId;
725 }
726 } // namespace Media
727 } // namespace OHOS
728