• 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_audio_operations.h"
17 
18 #include "abs_shared_result_set.h"
19 #include "file_asset.h"
20 #include "media_column.h"
21 #include "media_file_uri.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "medialibrary_asset_operations.h"
25 #include "medialibrary_command.h"
26 #include "medialibrary_data_manager_utils.h"
27 #include "medialibrary_db_const.h"
28 #include "medialibrary_errno.h"
29 #include "medialibrary_notify.h"
30 #include "medialibrary_object_utils.h"
31 #include "medialibrary_rdbstore.h"
32 #include "medialibrary_type_const.h"
33 #include "medialibrary_uripermission_operations.h"
34 #include "thumbnail_const.h"
35 #include "userfile_manager_types.h"
36 #include "value_object.h"
37 
38 using namespace std;
39 using namespace OHOS::NativeRdb;
40 using namespace OHOS::RdbDataShareAdapter;
41 
42 namespace OHOS {
43 namespace Media {
Create(MediaLibraryCommand & cmd)44 int32_t MediaLibraryAudioOperations::Create(MediaLibraryCommand &cmd)
45 {
46     switch (cmd.GetApi()) {
47         case MediaLibraryApi::API_10:
48             return CreateV10(cmd);
49         case MediaLibraryApi::API_OLD:
50             return CreateV9(cmd);
51         default:
52             MEDIA_ERR_LOG("get api failed");
53             return E_FAIL;
54     }
55 }
56 
Delete(MediaLibraryCommand & cmd)57 int32_t MediaLibraryAudioOperations::Delete(MediaLibraryCommand& cmd)
58 {
59     string fileId = cmd.GetOprnFileId();
60     vector<string> columns = {
61         AudioColumn::MEDIA_ID,
62         AudioColumn::MEDIA_FILE_PATH,
63         AudioColumn::MEDIA_RELATIVE_PATH,
64         AudioColumn::MEDIA_TYPE
65     };
66     shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(AudioColumn::MEDIA_ID,
67         fileId, cmd.GetOprnObject(), columns);
68     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_INVALID_FILEID, "Get fileAsset failed, fileId: %{public}s",
69         fileId.c_str());
70 
71     int32_t deleteRow = DeleteAudio(fileAsset, cmd.GetApi());
72     CHECK_AND_RETURN_RET_LOG(deleteRow >= 0, deleteRow, "delete audio failed, deleteRow=%{public}d", deleteRow);
73 
74     return deleteRow;
75 }
76 
Query(MediaLibraryCommand & cmd,const vector<string> & columns)77 std::shared_ptr<NativeRdb::ResultSet> MediaLibraryAudioOperations::Query(
78     MediaLibraryCommand &cmd, const vector<string> &columns)
79 {
80     return MediaLibraryRdbStore::Query(
81         RdbUtils::ToPredicates(cmd.GetDataSharePred(), AudioColumn::AUDIOS_TABLE), columns);
82 }
83 
Update(MediaLibraryCommand & cmd)84 int32_t MediaLibraryAudioOperations::Update(MediaLibraryCommand &cmd)
85 {
86     switch (cmd.GetApi()) {
87         case MediaLibraryApi::API_10:
88             return UpdateV10(cmd);
89         case MediaLibraryApi::API_OLD:
90             return UpdateV9(cmd);
91         default:
92             MEDIA_ERR_LOG("get api failed");
93             return E_FAIL;
94     }
95 
96     return E_OK;
97 }
98 
99 // temp function, delete after MediaFileUri::Getpath is finish
GetPathFromUri(const std::string & uri)100 static string GetPathFromUri(const std::string &uri)
101 {
102     string realTitle = uri;
103     size_t index = uri.rfind('/');
104     if (index == string::npos) {
105         return "";
106     }
107     realTitle = uri.substr(0, index);
108     index = realTitle.rfind('/');
109     if (index == string::npos) {
110         return "";
111     }
112     realTitle = realTitle.substr(index + 1);
113     index = realTitle.rfind('_');
114     if (index == string::npos) {
115         return "";
116     }
117     int32_t fileUniqueId = stoi(realTitle.substr(index + 1));
118     int32_t bucketNum = 0;
119     MediaLibraryAssetOperations::CreateAssetBucket(fileUniqueId, bucketNum);
120     string ext = MediaFileUtils::GetExtensionFromPath(uri);
121     if (ext.empty()) {
122         return "";
123     }
124     string path = ROOT_MEDIA_DIR + AUDIO_BUCKET + "/" + to_string(bucketNum) + "/" + realTitle + "." + ext;
125     if (!MediaFileUtils::IsFileExists(path)) {
126         MEDIA_ERR_LOG("file not exist, path=%{private}s", path.c_str());
127         return "";
128     }
129     return path;
130 }
131 
132 const static vector<string> AUDIO_COLUMN_VECTOR = {
133     AudioColumn::MEDIA_FILE_PATH,
134     AudioColumn::MEDIA_TIME_PENDING
135 };
136 
Open(MediaLibraryCommand & cmd,const string & mode)137 int32_t MediaLibraryAudioOperations::Open(MediaLibraryCommand &cmd, const string &mode)
138 {
139     string uriString = cmd.GetUriStringWithoutSegment();
140     string id = MediaFileUri(uriString).GetFileId();
141     if (uriString.empty() || (!MediaLibraryDataManagerUtils::IsNumber(id))) {
142         return E_INVALID_URI;
143     }
144 
145     shared_ptr<FileAsset> fileAsset = make_shared<FileAsset>();
146     string pendingStatus = cmd.GetQuerySetParam(MediaColumn::MEDIA_TIME_PENDING);
147     MediaFileUri fileUri(uriString);
148     if (pendingStatus.empty() || !fileUri.IsApi10()) {
149         fileAsset = GetFileAssetFromDb(AudioColumn::MEDIA_ID, id, OperationObject::FILESYSTEM_AUDIO,
150             AUDIO_COLUMN_VECTOR);
151         if (fileAsset == nullptr) {
152             MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
153             return E_INVALID_URI;
154         }
155     } else {
156         string path = GetPathFromUri(uriString);
157         if (path.empty()) {
158             fileAsset = GetFileAssetFromDb(AudioColumn::MEDIA_ID, id, OperationObject::FILESYSTEM_AUDIO,
159                 AUDIO_COLUMN_VECTOR);
160             if (fileAsset == nullptr) {
161                 MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
162                 return E_INVALID_URI;
163             }
164         } else {
165             fileAsset->SetPath(path);
166             int32_t timePending = stoi(pendingStatus);
167             fileAsset->SetTimePending((timePending > 0) ? MediaFileUtils::UTCTimeSeconds() : timePending);
168         }
169     }
170 
171     fileAsset->SetMediaType(MediaType::MEDIA_TYPE_AUDIO);
172     fileAsset->SetId(stoi(id));
173     fileAsset->SetUri(uriString);
174 
175     if (uriString.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
176         return OpenAsset(fileAsset, mode, MediaLibraryApi::API_10);
177     }
178     return OpenAsset(fileAsset, mode, cmd.GetApi());
179 }
180 
Close(MediaLibraryCommand & cmd)181 int32_t MediaLibraryAudioOperations::Close(MediaLibraryCommand &cmd)
182 {
183     const ValuesBucket &values = cmd.GetValueBucket();
184     string uriString;
185     if (!GetStringFromValuesBucket(values, MEDIA_DATA_DB_URI, uriString)) {
186         return E_INVALID_VALUES;
187     }
188     string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(uriString);
189     if (uriString.empty() || (!MediaLibraryDataManagerUtils::IsNumber(fileId))) {
190         return E_INVALID_URI;
191     }
192 
193     shared_ptr<FileAsset> fileAsset = make_shared<FileAsset>();
194     string pendingStatus = cmd.GetQuerySetParam(MediaColumn::MEDIA_TIME_PENDING);
195     MediaFileUri fileUri(uriString);
196     if (pendingStatus.empty() || !fileUri.IsApi10()) {
197         fileAsset = GetFileAssetFromDb(AudioColumn::MEDIA_ID, fileId, OperationObject::FILESYSTEM_AUDIO,
198             AUDIO_COLUMN_VECTOR);
199         if (fileAsset == nullptr) {
200             MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
201             return E_INVALID_URI;
202         }
203     } else {
204         string path = GetPathFromUri(uriString);
205         if (path.empty()) {
206             fileAsset = GetFileAssetFromDb(AudioColumn::MEDIA_ID, fileId, OperationObject::FILESYSTEM_AUDIO,
207                 AUDIO_COLUMN_VECTOR);
208             if (fileAsset == nullptr) {
209                 MEDIA_ERR_LOG("Failed to obtain path from Database, uri=%{private}s", uriString.c_str());
210                 return E_INVALID_URI;
211             }
212         } else {
213             fileAsset->SetPath(path);
214             int32_t timePending = stoi(pendingStatus);
215             fileAsset->SetTimePending((timePending > 0) ? MediaFileUtils::UTCTimeSeconds() : timePending);
216         }
217     }
218 
219     fileAsset->SetMediaType(MediaType::MEDIA_TYPE_AUDIO);
220     fileAsset->SetId(stoi(fileId));
221     fileAsset->SetUri(uriString);
222 
223     int32_t isSync = 0;
224     int32_t errCode = 0;
225     if (GetInt32FromValuesBucket(cmd.GetValueBucket(), CLOSE_CREATE_THUMB_STATUS, isSync) &&
226         isSync == CREATE_THUMB_SYNC_STATUS) {
227         errCode = CloseAsset(fileAsset, true);
228     } else {
229         errCode = CloseAsset(fileAsset, false);
230     }
231     return errCode;
232 }
233 
CreateV9(MediaLibraryCommand & cmd)234 int32_t MediaLibraryAudioOperations::CreateV9(MediaLibraryCommand& cmd)
235 {
236     FileAsset fileAsset;
237     ValuesBucket &values = cmd.GetValueBucket();
238 
239     string displayName;
240     CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, AudioColumn::MEDIA_NAME, displayName),
241         E_HAS_DB_ERROR);
242     fileAsset.SetDisplayName(displayName);
243 
244     string relativePath;
245     CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, AudioColumn::MEDIA_RELATIVE_PATH, relativePath),
246         E_HAS_DB_ERROR);
247     fileAsset.SetRelativePath(relativePath);
248     MediaFileUtils::FormatRelativePath(relativePath);
249 
250     int32_t mediaType = 0;
251     CHECK_AND_RETURN_RET(GetInt32FromValuesBucket(values, AudioColumn::MEDIA_TYPE, mediaType),
252         E_HAS_DB_ERROR);
253     if (mediaType != MediaType::MEDIA_TYPE_AUDIO) {
254         return E_CHECK_MEDIATYPE_FAIL;
255     }
256     fileAsset.SetMediaType(MediaType::MEDIA_TYPE_AUDIO);
257 
258     int32_t errCode = CheckRelativePathWithType(relativePath, MediaType::MEDIA_TYPE_AUDIO);
259     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to Check RelativePath and Extention, "
260         "relativePath=%{private}s, mediaType=%{public}d", relativePath.c_str(), mediaType);
261     errCode = CheckDisplayNameWithType(displayName, MediaType::MEDIA_TYPE_AUDIO);
262     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to Check Dir and Extention, "
263         "displayName=%{private}s, mediaType=%{public}d", displayName.c_str(), mediaType);
264 
265     TransactionOperations transactionOprn;
266     errCode = transactionOprn.Start();
267     if (errCode != E_OK) {
268         return errCode;
269     }
270 
271     errCode = SetAssetPathInCreate(fileAsset);
272     if (errCode != E_OK) {
273         MEDIA_ERR_LOG("Failed to Solve FileAsset Path and Name, displayName=%{private}s", displayName.c_str());
274         return errCode;
275     }
276 
277     int32_t outRow = InsertAssetInDb(cmd, fileAsset);
278     if (outRow <= 0) {
279         MEDIA_ERR_LOG("insert file in db failed, error = %{public}d", outRow);
280         return E_HAS_DB_ERROR;
281     }
282     transactionOprn.Finish();
283     return outRow;
284 }
285 
CreateV10(MediaLibraryCommand & cmd)286 int32_t MediaLibraryAudioOperations::CreateV10(MediaLibraryCommand& cmd)
287 {
288     FileAsset fileAsset;
289     ValuesBucket &values = cmd.GetValueBucket();
290     string displayName;
291     string extention;
292     string title;
293     bool isContains = false;
294     bool isNeedGrant = false;
295     if (GetStringFromValuesBucket(values, AudioColumn::MEDIA_NAME, displayName)) {
296         fileAsset.SetDisplayName(displayName);
297         fileAsset.SetTimePending(UNCREATE_FILE_TIMEPENDING);
298         isContains = true;
299     } else {
300         CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, ASSET_EXTENTION, extention), E_HAS_DB_ERROR);
301         isNeedGrant = true;
302         fileAsset.SetTimePending(UNOPEN_FILE_COMPONENT_TIMEPENDING);
303         if (GetStringFromValuesBucket(values, AudioColumn::MEDIA_TITLE, title)) {
304             displayName = title + "." + extention;
305             fileAsset.SetDisplayName(displayName);
306             isContains = true;
307         }
308     }
309 
310     int32_t mediaType = 0;
311     CHECK_AND_RETURN_RET(GetInt32FromValuesBucket(values, AudioColumn::MEDIA_TYPE, mediaType),
312         E_HAS_DB_ERROR);
313     CHECK_AND_RETURN_RET(mediaType == MediaType::MEDIA_TYPE_AUDIO, E_CHECK_MEDIATYPE_FAIL);
314     fileAsset.SetMediaType(MediaType::MEDIA_TYPE_AUDIO);
315 
316     // Check rootdir and extention
317     int32_t errCode = CheckWithType(isContains, displayName, extention, MediaType::MEDIA_TYPE_AUDIO);
318     CHECK_AND_RETURN_RET(errCode == E_OK, errCode);
319     TransactionOperations transactionOprn;
320     errCode = transactionOprn.Start();
321     CHECK_AND_RETURN_RET(errCode == E_OK, errCode);
322     errCode = isContains ? SetAssetPathInCreate(fileAsset) : SetAssetPath(fileAsset, extention);
323     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode,
324         "Failed to Solve FileAsset Path and Name, displayName=%{private}s", displayName.c_str());
325 
326     int32_t outRow = InsertAssetInDb(cmd, fileAsset);
327     CHECK_AND_RETURN_RET_LOG(outRow > 0, errCode, "insert file in db failed, error = %{public}d", outRow);
328     transactionOprn.Finish();
329     fileAsset.SetId(outRow);
330     string fileUri = CreateExtUriForV10Asset(fileAsset);
331     if (isNeedGrant) {
332         int32_t ret = GrantUriPermission(fileUri, cmd.GetBundleName(), fileAsset.GetPath());
333         CHECK_AND_RETURN_RET(ret == E_OK, ret);
334     }
335     cmd.SetResult(fileUri);
336     return outRow;
337 }
338 
DeleteAudio(const shared_ptr<FileAsset> & fileAsset,MediaLibraryApi api)339 int32_t MediaLibraryAudioOperations::DeleteAudio(const shared_ptr<FileAsset> &fileAsset, MediaLibraryApi api)
340 {
341     string filePath = fileAsset->GetPath();
342     CHECK_AND_RETURN_RET_LOG(!filePath.empty(), E_INVALID_PATH, "get file path failed");
343     bool res = MediaFileUtils::DeleteFile(filePath);
344     CHECK_AND_RETURN_RET_LOG(res, E_HAS_FS_ERROR, "Delete audio file failed, errno: %{public}d", errno);
345 
346     // delete thumbnail
347     int32_t fileId = fileAsset->GetId();
348     InvalidateThumbnail(to_string(fileId), fileAsset->GetMediaType());
349 
350     TransactionOperations transactionOprn;
351     int32_t errCode = transactionOprn.Start();
352     if (errCode != E_OK) {
353         return errCode;
354     }
355     string displayName = fileAsset->GetDisplayName();
356     // delete file in db
357     MediaLibraryCommand cmd(OperationObject::FILESYSTEM_AUDIO, OperationType::DELETE);
358     cmd.GetAbsRdbPredicates()->EqualTo(AudioColumn::MEDIA_ID, to_string(fileId));
359     int32_t deleteRows = DeleteAssetInDb(cmd);
360     if (deleteRows <= 0) {
361         MEDIA_ERR_LOG("Delete audio in database failed, errCode=%{public}d", deleteRows);
362         return E_HAS_DB_ERROR;
363     }
364     transactionOprn.Finish();
365 
366     auto watch = MediaLibraryNotify::GetInstance();
367     string notifyUri = MediaFileUtils::GetUriByExtrConditions(AudioColumn::AUDIO_URI_PREFIX, to_string(fileId),
368         (api == MediaLibraryApi::API_10 ? MediaFileUtils::GetExtraUri(displayName, filePath) : ""));
369 
370     watch->Notify(notifyUri, NotifyType::NOTIFY_REMOVE);
371     return deleteRows;
372 }
373 
UpdateV10(MediaLibraryCommand & cmd)374 int32_t MediaLibraryAudioOperations::UpdateV10(MediaLibraryCommand &cmd)
375 {
376     if (cmd.GetOprnType() == OperationType::UPDATE_PENDING) {
377         return SetPendingStatus(cmd);
378     }
379     vector<string> columns = {
380         AudioColumn::MEDIA_ID,
381         AudioColumn::MEDIA_FILE_PATH,
382         AudioColumn::MEDIA_TYPE,
383         AudioColumn::MEDIA_NAME
384     };
385     shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
386         OperationObject::FILESYSTEM_AUDIO, columns);
387     if (fileAsset == nullptr) {
388         return E_INVALID_VALUES;
389     }
390 
391     // Update if FileAsset.title or FileAsset.displayName is modified
392     bool isNameChanged = false;
393     int32_t errCode = UpdateFileName(cmd, fileAsset, isNameChanged);
394     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Audio Name failed, fileName=%{private}s",
395         fileAsset->GetDisplayName().c_str());
396 
397     TransactionOperations transactionOprn;
398     errCode = transactionOprn.Start();
399     if (errCode != E_OK) {
400         return errCode;
401     }
402 
403     int32_t rowId = UpdateFileInDb(cmd);
404     if (rowId < 0) {
405         MEDIA_ERR_LOG("Update Audio In database failed, rowId=%{public}d", rowId);
406         return rowId;
407     }
408     transactionOprn.Finish();
409 
410     string extraUri = MediaFileUtils::GetExtraUri(fileAsset->GetDisplayName(), fileAsset->GetPath());
411     errCode = SendTrashNotify(cmd, fileAsset->GetId(), extraUri);
412     if (errCode == E_OK) {
413         return rowId;
414     }
415 
416     // Audio has no favorite album, do not send favorite notify
417     auto watch = MediaLibraryNotify::GetInstance();
418     watch->Notify(MediaFileUtils::GetUriByExtrConditions(AudioColumn::AUDIO_URI_PREFIX, to_string(fileAsset->GetId()),
419         extraUri), NotifyType::NOTIFY_UPDATE);
420     return rowId;
421 }
422 
UpdateV9(MediaLibraryCommand & cmd)423 int32_t MediaLibraryAudioOperations::UpdateV9(MediaLibraryCommand &cmd)
424 {
425     vector<string> columns = {
426         AudioColumn::MEDIA_ID,
427         AudioColumn::MEDIA_FILE_PATH,
428         AudioColumn::MEDIA_TYPE,
429         AudioColumn::MEDIA_NAME,
430         AudioColumn::MEDIA_RELATIVE_PATH
431     };
432     shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
433         OperationObject::FILESYSTEM_AUDIO, columns);
434     if (fileAsset == nullptr) {
435         return E_INVALID_VALUES;
436     }
437 
438     // Update if FileAsset.title or FileAsset.displayName is modified
439     bool isNameChanged = false;
440     int32_t errCode = UpdateFileName(cmd, fileAsset, isNameChanged);
441     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Audio Name failed, fileName=%{private}s",
442         fileAsset->GetDisplayName().c_str());
443     errCode = UpdateRelativePath(cmd, fileAsset, isNameChanged);
444     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Audio RelativePath failed, relativePath=%{private}s",
445         fileAsset->GetRelativePath().c_str());
446     if (isNameChanged) {
447         UpdateVirtualPath(cmd, fileAsset);
448     }
449 
450     TransactionOperations transactionOprn;
451     errCode = transactionOprn.Start();
452     if (errCode != E_OK) {
453         return errCode;
454     }
455 
456     int32_t rowId = UpdateFileInDb(cmd);
457     if (rowId < 0) {
458         MEDIA_ERR_LOG("Update Audio In database failed, rowId=%{public}d", rowId);
459         return rowId;
460     }
461     transactionOprn.Finish();
462 
463     errCode = SendTrashNotify(cmd, fileAsset->GetId());
464     if (errCode == E_OK) {
465         return rowId;
466     }
467 
468     // Audio has no favorite album, do not send favorite notify
469     auto watch = MediaLibraryNotify::GetInstance();
470     watch->Notify(MediaFileUtils::GetUriByExtrConditions(AudioColumn::AUDIO_URI_PREFIX, to_string(fileAsset->GetId())),
471         NotifyType::NOTIFY_UPDATE);
472     return rowId;
473 }
474 
TrashAging()475 int32_t MediaLibraryAudioOperations::TrashAging()
476 {
477     auto time = MediaFileUtils::UTCTimeSeconds();
478     RdbPredicates predicates(AudioColumn::AUDIOS_TABLE);
479     predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
480     predicates.And()->LessThanOrEqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(time - AGING_TIME));
481     int32_t deletedRows = MediaLibraryRdbStore::DeleteFromDisk(predicates);
482     if (deletedRows < 0) {
483         return deletedRows;
484     }
485     return E_OK;
486 }
487 } // namespace Media
488 } // namespace OHOS