• 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_db_const.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_notify.h"
29 #include "medialibrary_object_utils.h"
30 #include "medialibrary_rdb_transaction.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 #include "hi_audit.h"
38 
39 using namespace std;
40 using namespace OHOS::NativeRdb;
41 using namespace OHOS::RdbDataShareAdapter;
42 
43 namespace OHOS {
44 namespace Media {
45 const string MUSIC_DIR = "/storage/media/local/files/Docs/Music/";
46 const string CLOUD_AUDIO_DIR = "/storage/cloud/files/Audio/";
47 const string LOCAL_AUDIO_DIR = "/storage/media/local/files/Audio/";
48 
Create(MediaLibraryCommand & cmd)49 int32_t MediaLibraryAudioOperations::Create(MediaLibraryCommand &cmd)
50 {
51     switch (cmd.GetApi()) {
52         case MediaLibraryApi::API_10:
53             return CreateV10(cmd);
54         case MediaLibraryApi::API_OLD:
55             return CreateV9(cmd);
56         default:
57             MEDIA_ERR_LOG("get api failed");
58             return E_FAIL;
59     }
60 }
61 
Delete(MediaLibraryCommand & cmd)62 int32_t MediaLibraryAudioOperations::Delete(MediaLibraryCommand& cmd)
63 {
64     string fileId = cmd.GetOprnFileId();
65     vector<string> columns = {
66         AudioColumn::MEDIA_ID,
67         AudioColumn::MEDIA_FILE_PATH,
68         AudioColumn::MEDIA_RELATIVE_PATH,
69         AudioColumn::MEDIA_TYPE
70     };
71     shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
72         cmd.GetOprnObject(), columns);
73     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_INVALID_FILEID, "Get fileAsset failed, fileId: %{private}s",
74         fileId.c_str());
75 
76     int32_t deleteRow = DeleteAudio(fileAsset, cmd.GetApi());
77     CHECK_AND_RETURN_RET_LOG(deleteRow >= 0, deleteRow, "delete audio failed, deleteRow=%{public}d", deleteRow);
78 
79     return deleteRow;
80 }
81 
Query(MediaLibraryCommand & cmd,const vector<string> & columns)82 std::shared_ptr<NativeRdb::ResultSet> MediaLibraryAudioOperations::Query(
83     MediaLibraryCommand &cmd, const vector<string> &columns)
84 {
85     return MediaLibraryRdbStore::QueryWithFilter(
86         RdbUtils::ToPredicates(cmd.GetDataSharePred(), AudioColumn::AUDIOS_TABLE), columns);
87 }
88 
Update(MediaLibraryCommand & cmd)89 int32_t MediaLibraryAudioOperations::Update(MediaLibraryCommand &cmd)
90 {
91     switch (cmd.GetApi()) {
92         case MediaLibraryApi::API_10:
93             return UpdateV10(cmd);
94         case MediaLibraryApi::API_OLD:
95             return UpdateV9(cmd);
96         default:
97             MEDIA_ERR_LOG("get api failed");
98             return E_FAIL;
99     }
100 
101     return E_OK;
102 }
103 
104 const static vector<string> AUDIO_COLUMN_VECTOR = {
105     AudioColumn::MEDIA_FILE_PATH,
106     AudioColumn::MEDIA_TIME_PENDING
107 };
108 
Open(MediaLibraryCommand & cmd,const string & mode)109 int32_t MediaLibraryAudioOperations::Open(MediaLibraryCommand &cmd, const string &mode)
110 {
111     string uriString = cmd.GetUriStringWithoutSegment();
112     string pendingStatus = cmd.GetQuerySetParam(MediaColumn::MEDIA_TIME_PENDING);
113 
114     shared_ptr<FileAsset> fileAsset = GetFileAssetByUri(uriString, false, AUDIO_COLUMN_VECTOR, pendingStatus);
115     if (fileAsset == nullptr) {
116         MEDIA_ERR_LOG("Get FileAsset From Uri Failed, uri:%{public}s", uriString.c_str());
117         return E_URI_INVALID;
118     }
119 
120     if (uriString.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
121         return OpenAsset(fileAsset, mode, MediaLibraryApi::API_10);
122     }
123     return OpenAsset(fileAsset, mode, cmd.GetApi());
124 }
125 
Close(MediaLibraryCommand & cmd)126 int32_t MediaLibraryAudioOperations::Close(MediaLibraryCommand &cmd)
127 {
128     const ValuesBucket &values = cmd.GetValueBucket();
129     string uriString;
130     if (!GetStringFromValuesBucket(values, MEDIA_DATA_DB_URI, uriString)) {
131         return E_INVALID_VALUES;
132     }
133     string pendingStatus = cmd.GetQuerySetParam(MediaColumn::MEDIA_TIME_PENDING);
134 
135     shared_ptr<FileAsset> fileAsset = GetFileAssetByUri(uriString, false, AUDIO_COLUMN_VECTOR, pendingStatus);
136     if (fileAsset == nullptr) {
137         MEDIA_ERR_LOG("Get FileAsset From Uri Failed, uri:%{public}s", uriString.c_str());
138         return E_INVALID_URI;
139     }
140 
141     int32_t isSync = 0;
142     int32_t errCode = 0;
143     if (GetInt32FromValuesBucket(cmd.GetValueBucket(), CLOSE_CREATE_THUMB_STATUS, isSync) &&
144         isSync == CREATE_THUMB_SYNC_STATUS) {
145         errCode = CloseAsset(fileAsset, true);
146     } else {
147         errCode = CloseAsset(fileAsset, false);
148     }
149     return errCode;
150 }
151 
CreateV9(MediaLibraryCommand & cmd)152 int32_t MediaLibraryAudioOperations::CreateV9(MediaLibraryCommand& cmd)
153 {
154     FileAsset fileAsset;
155     ValuesBucket &values = cmd.GetValueBucket();
156 
157     string displayName;
158     CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, AudioColumn::MEDIA_NAME, displayName),
159         E_HAS_DB_ERROR);
160     fileAsset.SetDisplayName(displayName);
161 
162     string relativePath;
163     CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, AudioColumn::MEDIA_RELATIVE_PATH, relativePath),
164         E_HAS_DB_ERROR);
165     fileAsset.SetRelativePath(relativePath);
166     MediaFileUtils::FormatRelativePath(relativePath);
167 
168     int32_t mediaType = 0;
169     CHECK_AND_RETURN_RET(GetInt32FromValuesBucket(values, AudioColumn::MEDIA_TYPE, mediaType),
170         E_HAS_DB_ERROR);
171     if (mediaType != MediaType::MEDIA_TYPE_AUDIO) {
172         return E_CHECK_MEDIATYPE_FAIL;
173     }
174     fileAsset.SetMediaType(MediaType::MEDIA_TYPE_AUDIO);
175 
176     int32_t errCode = CheckRelativePathWithType(relativePath, MediaType::MEDIA_TYPE_AUDIO);
177     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to Check RelativePath and Extention, "
178         "relativePath=%{private}s, mediaType=%{public}d", relativePath.c_str(), mediaType);
179     errCode = CheckDisplayNameWithType(displayName, MediaType::MEDIA_TYPE_AUDIO);
180     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to Check Dir and Extention, "
181         "displayName=%{private}s, mediaType=%{public}d", displayName.c_str(), mediaType);
182 
183     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
184     int32_t outRow = -1;
185     std::function<int(void)> func = [&]()->int {
186         errCode = SetAssetPathInCreate(fileAsset, trans);
187         if (errCode != E_OK) {
188             MEDIA_ERR_LOG("Failed to Solve FileAsset Path and Name, displayName=%{private}s", displayName.c_str());
189             return errCode;
190         }
191 
192         outRow = InsertAssetInDb(trans, cmd, fileAsset);
193         if (outRow <= 0) {
194             MEDIA_ERR_LOG("insert file in db failed, error = %{public}d", outRow);
195             return E_HAS_DB_ERROR;
196         }
197         return errCode;
198     };
199     errCode = trans->RetryTrans(func);
200     if (errCode != E_OK) {
201         MEDIA_ERR_LOG("CreateV9: trans retry fail!, ret:%{public}d", errCode);
202         return errCode;
203     }
204     return outRow;
205 }
206 
CreateV10(MediaLibraryCommand & cmd)207 int32_t MediaLibraryAudioOperations::CreateV10(MediaLibraryCommand &cmd)
208 {
209     FileAsset fileAsset;
210     ValuesBucket &values = cmd.GetValueBucket();
211     string displayName;
212     string extention;
213     bool isContains = false;
214     bool isNeedGrant = false;
215     if (GetStringFromValuesBucket(values, AudioColumn::MEDIA_NAME, displayName)) {
216         fileAsset.SetDisplayName(displayName);
217         fileAsset.SetTimePending(UNCREATE_FILE_TIMEPENDING);
218         isContains = true;
219     } else {
220         CHECK_AND_RETURN_RET(GetStringFromValuesBucket(values, ASSET_EXTENTION, extention), E_HAS_DB_ERROR);
221         isNeedGrant = true;
222         fileAsset.SetTimePending(UNOPEN_FILE_COMPONENT_TIMEPENDING);
223         string title;
224         if (GetStringFromValuesBucket(values, AudioColumn::MEDIA_TITLE, title)) {
225             displayName = title + "." + extention;
226             fileAsset.SetDisplayName(displayName);
227             isContains = true;
228         }
229     }
230 
231     int32_t mediaType = 0;
232     CHECK_AND_RETURN_RET(GetInt32FromValuesBucket(values, AudioColumn::MEDIA_TYPE, mediaType), E_HAS_DB_ERROR);
233     CHECK_AND_RETURN_RET(mediaType == MediaType::MEDIA_TYPE_AUDIO, E_CHECK_MEDIATYPE_FAIL);
234     fileAsset.SetMediaType(MediaType::MEDIA_TYPE_AUDIO);
235 
236     // Check rootdir and extention
237     int32_t errCode = CheckWithType(isContains, displayName, extention, MediaType::MEDIA_TYPE_AUDIO);
238     CHECK_AND_RETURN_RET(errCode == E_OK, errCode);
239     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
240     int32_t outRow = -1;
241     std::function<int(void)> func = [&]()->int {
242         CHECK_AND_RETURN_RET((errCode == E_OK), errCode);
243         errCode = isContains ? SetAssetPathInCreate(fileAsset, trans) : SetAssetPath(fileAsset, extention, trans);
244         CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode,
245             "Failed to Solve FileAsset Path and Name, displayName=%{private}s", displayName.c_str());
246 
247         outRow = InsertAssetInDb(trans, cmd, fileAsset);
248         AuditLog auditLog = { true, "USER BEHAVIOR", "ADD", "io", 1, "running", "ok" };
249         HiAudit::GetInstance().Write(auditLog);
250         CHECK_AND_RETURN_RET_LOG(outRow > 0, E_HAS_DB_ERROR, "insert file in db failed, error = %{public}d", outRow);
251         return errCode;
252     };
253     errCode = trans->RetryTrans(func);
254     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "CreateV10: trans retry fail!, ret:%{public}d", errCode);
255     fileAsset.SetId(outRow);
256     string fileUri = CreateExtUriForV10Asset(fileAsset);
257     if (isNeedGrant) {
258         int32_t ret = GrantUriPermission(fileUri, cmd.GetBundleName(), fileAsset.GetPath());
259         CHECK_AND_RETURN_RET(ret == E_OK, ret);
260     }
261     cmd.SetResult(fileUri);
262     return outRow;
263 }
264 
DeleteAudio(const shared_ptr<FileAsset> & fileAsset,MediaLibraryApi api)265 int32_t MediaLibraryAudioOperations::DeleteAudio(const shared_ptr<FileAsset> &fileAsset, MediaLibraryApi api)
266 {
267     string filePath = fileAsset->GetPath();
268     CHECK_AND_RETURN_RET_LOG(!filePath.empty(), E_INVALID_PATH, "get file path failed");
269     bool res = MediaFileUtils::DeleteFile(filePath);
270     CHECK_AND_RETURN_RET_LOG(res, E_HAS_FS_ERROR, "Delete audio file failed, errno: %{public}d", errno);
271 
272     // delete thumbnail
273     int32_t fileId = fileAsset->GetId();
274     InvalidateThumbnail(to_string(fileId), fileAsset->GetMediaType());
275 
276     string displayName = fileAsset->GetDisplayName();
277     // delete file in db
278     MediaLibraryCommand cmd(OperationObject::FILESYSTEM_AUDIO, OperationType::DELETE);
279     cmd.GetAbsRdbPredicates()->EqualTo(AudioColumn::MEDIA_ID, to_string(fileId));
280     int32_t deleteRows = DeleteAssetInDb(cmd);
281     if (deleteRows <= 0) {
282         MEDIA_ERR_LOG("Delete audio in database failed, errCode=%{public}d", deleteRows);
283         return E_HAS_DB_ERROR;
284     }
285 
286     auto watch = MediaLibraryNotify::GetInstance();
287     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
288     string notifyUri = MediaFileUtils::GetUriByExtrConditions(AudioColumn::AUDIO_URI_PREFIX, to_string(fileId),
289         (api == MediaLibraryApi::API_10 ? MediaFileUtils::GetExtraUri(displayName, filePath) : ""));
290 
291     watch->Notify(notifyUri, NotifyType::NOTIFY_REMOVE);
292     return deleteRows;
293 }
294 
UpdateV10(MediaLibraryCommand & cmd)295 int32_t MediaLibraryAudioOperations::UpdateV10(MediaLibraryCommand &cmd)
296 {
297     if (cmd.GetOprnType() == OperationType::UPDATE_PENDING) {
298         return SetPendingStatus(cmd);
299     }
300     vector<string> columns = {
301         AudioColumn::MEDIA_ID,
302         AudioColumn::MEDIA_FILE_PATH,
303         AudioColumn::MEDIA_TYPE,
304         AudioColumn::MEDIA_NAME
305     };
306     shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
307         OperationObject::FILESYSTEM_AUDIO, columns);
308     if (fileAsset == nullptr) {
309         return E_INVALID_VALUES;
310     }
311 
312     // Update if FileAsset.title or FileAsset.displayName is modified
313     bool isNameChanged = false;
314     int32_t errCode = UpdateFileName(cmd, fileAsset, isNameChanged);
315     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Audio Name failed, fileName=%{private}s",
316         fileAsset->GetDisplayName().c_str());
317 
318     int32_t rowId = UpdateFileInDb(cmd);
319     if (rowId < 0) {
320         MEDIA_ERR_LOG("Update Audio In database failed, rowId=%{public}d", rowId);
321         return rowId;
322     }
323 
324     string extraUri = MediaFileUtils::GetExtraUri(fileAsset->GetDisplayName(), fileAsset->GetPath());
325     errCode = SendTrashNotify(cmd, fileAsset->GetId(), extraUri);
326     if (errCode == E_OK) {
327         return rowId;
328     }
329 
330     // Audio has no favorite album, do not send favorite notify
331     auto watch = MediaLibraryNotify::GetInstance();
332     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
333     watch->Notify(MediaFileUtils::GetUriByExtrConditions(AudioColumn::AUDIO_URI_PREFIX, to_string(fileAsset->GetId()),
334         extraUri), NotifyType::NOTIFY_UPDATE);
335     return rowId;
336 }
337 
UpdateV9(MediaLibraryCommand & cmd)338 int32_t MediaLibraryAudioOperations::UpdateV9(MediaLibraryCommand &cmd)
339 {
340     vector<string> columns = {
341         AudioColumn::MEDIA_ID,
342         AudioColumn::MEDIA_FILE_PATH,
343         AudioColumn::MEDIA_TYPE,
344         AudioColumn::MEDIA_NAME,
345         AudioColumn::MEDIA_RELATIVE_PATH
346     };
347     shared_ptr<FileAsset> fileAsset = GetFileAssetFromDb(*(cmd.GetAbsRdbPredicates()),
348         OperationObject::FILESYSTEM_AUDIO, columns);
349     if (fileAsset == nullptr) {
350         return E_INVALID_VALUES;
351     }
352 
353     // Update if FileAsset.title or FileAsset.displayName is modified
354     bool isNameChanged = false;
355     int32_t errCode = UpdateFileName(cmd, fileAsset, isNameChanged);
356     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Audio Name failed, fileName=%{private}s",
357         fileAsset->GetDisplayName().c_str());
358     errCode = UpdateRelativePath(cmd, fileAsset, isNameChanged);
359     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Update Audio RelativePath failed, relativePath=%{private}s",
360         fileAsset->GetRelativePath().c_str());
361     if (isNameChanged) {
362         UpdateVirtualPath(cmd, fileAsset);
363     }
364 
365     int32_t rowId = UpdateFileInDb(cmd);
366     if (rowId < 0) {
367         MEDIA_ERR_LOG("Update Audio In database failed, rowId=%{public}d", rowId);
368         return rowId;
369     }
370 
371     errCode = SendTrashNotify(cmd, fileAsset->GetId());
372     if (errCode == E_OK) {
373         return rowId;
374     }
375 
376     // Audio has no favorite album, do not send favorite notify
377     auto watch = MediaLibraryNotify::GetInstance();
378     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
379     watch->Notify(MediaFileUtils::GetUriByExtrConditions(AudioColumn::AUDIO_URI_PREFIX, to_string(fileAsset->GetId())),
380         NotifyType::NOTIFY_UPDATE);
381     return rowId;
382 }
383 
TrashAging(shared_ptr<int> countPtr)384 int32_t MediaLibraryAudioOperations::TrashAging(shared_ptr<int> countPtr)
385 {
386     auto time = MediaFileUtils::UTCTimeMilliSeconds();
387     RdbPredicates predicates(AudioColumn::AUDIOS_TABLE);
388     predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
389     predicates.And()->LessThanOrEqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(time - AGING_TIME));
390     int32_t deletedRows = DeleteFromDisk(predicates, true);
391     if (deletedRows < 0) {
392         return deletedRows;
393     }
394     if (countPtr != nullptr) {
395         *countPtr = deletedRows;
396     }
397     return E_OK;
398 }
399 
MoveToMusic()400 void MediaLibraryAudioOperations::MoveToMusic()
401 {
402     RdbPredicates predicates(AudioColumn::AUDIOS_TABLE);
403     vector<string> columns = {AudioColumn::MEDIA_NAME, MediaColumn::MEDIA_FILE_PATH};
404     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
405     if (resultSet == nullptr) {
406         MEDIA_ERR_LOG("result is nullptr or count is zero");
407         return;
408     }
409     if (!MediaFileUtils::IsFileExists(MUSIC_DIR)) {
410         MEDIA_INFO_LOG("music dir is not exists!!!");
411         MediaFileUtils::CreateDirectory(MUSIC_DIR);
412     }
413     int32_t num = 0;
414     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
415         string path = MediaLibraryRdbStore::GetString(resultSet, PhotoColumn::MEDIA_FILE_PATH);
416         string localPath = path.replace(0, CLOUD_AUDIO_DIR.length(), LOCAL_AUDIO_DIR);
417         string displayName = MediaLibraryRdbStore::GetString(resultSet, AudioColumn::MEDIA_NAME);
418         if (!MediaFileUtils::ModifyAsset(localPath, MUSIC_DIR + displayName)) {
419             num++;
420         } else {
421             MEDIA_ERR_LOG("move %{private}s to music fail!", displayName.c_str());
422         }
423     }
424     MEDIA_INFO_LOG("%{public}d audios move to music success", num);
425 }
426 } // namespace Media
427 } // namespace OHOS