• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &notifyUris)
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 &notifyUri : 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