• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #define MLOG_TAG "Scanner"
16 
17 #include "media_scanner_db.h"
18 
19 #include "media_log.h"
20 #include "medialibrary_errno.h"
21 #include "medialibrary_data_manager.h"
22 #include "result_set_utils.h"
23 #include "media_file_utils.h"
24 
25 namespace OHOS {
26 namespace Media {
27 using namespace std;
28 using namespace OHOS::NativeRdb;
29 using namespace OHOS::DataShare;
30 
MediaScannerDb()31 MediaScannerDb::MediaScannerDb() {}
32 
GetDatabaseInstance()33 unique_ptr<MediaScannerDb> MediaScannerDb::GetDatabaseInstance()
34 {
35     unique_ptr<MediaScannerDb> database = make_unique<MediaScannerDb>();
36     return database;
37 }
38 
SetRdbHelper(void)39 void MediaScannerDb::SetRdbHelper(void)
40 {
41 }
42 
InsertMetadata(const Metadata & metadata)43 string MediaScannerDb::InsertMetadata(const Metadata &metadata)
44 {
45     int32_t rowNum(0);
46     DataShareValuesBucket values;
47 
48     MediaType mediaType = metadata.GetFileMediaType();
49     string mediaTypeUri = GetMediaTypeUri(mediaType);
50 
51     values.Put(MEDIA_DATA_DB_URI, mediaTypeUri);
52     values.Put(MEDIA_DATA_DB_FILE_PATH, metadata.GetFilePath());
53     values.Put(MEDIA_DATA_DB_RELATIVE_PATH, metadata.GetRelativePath());
54     values.Put(MEDIA_DATA_DB_MIME_TYPE, metadata.GetFileMimeType());
55     values.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
56     values.Put(MEDIA_DATA_DB_NAME, metadata.GetFileName());
57 
58     values.Put(MEDIA_DATA_DB_SIZE, metadata.GetFileSize());
59     values.Put(MEDIA_DATA_DB_DATE_ADDED, MediaFileUtils::UTCTimeSeconds());
60     values.Put(MEDIA_DATA_DB_DATE_MODIFIED, metadata.GetFileDateModified());
61     values.Put(MEDIA_DATA_DB_TITLE, metadata.GetFileTitle());
62     values.Put(MEDIA_DATA_DB_AUDIO_ALBUM, metadata.GetAlbum());
63     values.Put(MEDIA_DATA_DB_ARTIST, metadata.GetFileArtist());
64 
65     values.Put(MEDIA_DATA_DB_HEIGHT, metadata.GetFileHeight());
66     values.Put(MEDIA_DATA_DB_WIDTH, metadata.GetFileWidth());
67     values.Put(MEDIA_DATA_DB_DURATION, metadata.GetFileDuration());
68     values.Put(MEDIA_DATA_DB_ORIENTATION, metadata.GetOrientation());
69 
70     values.Put(MEDIA_DATA_DB_BUCKET_NAME, metadata.GetAlbumName());
71     values.Put(MEDIA_DATA_DB_PARENT_ID, metadata.GetParentId());
72     values.Put(MEDIA_DATA_DB_BUCKET_ID, metadata.GetParentId());
73 
74     values.Put(MEDIA_DATA_DB_DATE_TAKEN, metadata.GetDateTaken());
75     values.Put(MEDIA_DATA_DB_ORIENTATION, metadata.GetOrientation());
76     values.Put(MEDIA_DATA_DB_LONGITUDE, metadata.GetLongitude());
77     values.Put(MEDIA_DATA_DB_LATITUDE, metadata.GetLatitude());
78 
79     Uri abilityUri(MEDIALIBRARY_DATA_URI);
80     rowNum = MediaLibraryDataManager::GetInstance()->Insert(abilityUri, values);
81     if (rowNum <= 0) {
82         MEDIA_ERR_LOG("MediaDataAbility Insert functionality is failed, return %{public}d", rowNum);
83         return "";
84     }
85 
86     return (!mediaTypeUri.empty() ? (mediaTypeUri + "/" + to_string(rowNum)) : mediaTypeUri);
87 }
88 
BatchInsert(const vector<Metadata> & metadataList)89 vector<string> MediaScannerDb::BatchInsert(const vector<Metadata> &metadataList)
90 {
91     vector<string> insertUriList;
92     for (auto itr : metadataList) {
93         insertUriList.push_back(InsertMetadata(itr));
94     }
95 
96     return insertUriList;
97 }
98 
99 /**
100  * @brief Update single metadata in the media database
101  *
102  * @param metadata The metadata object which has the information about the file
103  * @return string The mediatypeUri corresponding to the given metadata
104  */
UpdateMetadata(const Metadata & metadata)105 string MediaScannerDb::UpdateMetadata(const Metadata &metadata)
106 {
107     int32_t updateCount(0);
108     DataShareValuesBucket values;
109     DataShare::DataSharePredicates predicates;
110     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ?");
111     predicates.SetWhereArgs(vector<string>({ to_string(metadata.GetFileId()) }));
112 
113     MediaType mediaType = metadata.GetFileMediaType();
114     string mediaTypeUri = GetMediaTypeUri(mediaType);
115 
116     values.Put(MEDIA_DATA_DB_URI, mediaTypeUri);
117     values.Put(MEDIA_DATA_DB_FILE_PATH, metadata.GetFilePath());
118     values.Put(MEDIA_DATA_DB_RELATIVE_PATH, metadata.GetRelativePath());
119 
120     values.Put(MEDIA_DATA_DB_MIME_TYPE, metadata.GetFileMimeType());
121     values.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
122     values.Put(MEDIA_DATA_DB_NAME, metadata.GetFileName());
123     values.Put(MEDIA_DATA_DB_TITLE, metadata.GetFileTitle());
124 
125     values.Put(MEDIA_DATA_DB_SIZE, metadata.GetFileSize());
126     values.Put(MEDIA_DATA_DB_DATE_MODIFIED, metadata.GetFileDateModified());
127 
128     values.Put(MEDIA_DATA_DB_AUDIO_ALBUM, metadata.GetAlbum());
129     values.Put(MEDIA_DATA_DB_ARTIST, metadata.GetFileArtist());
130 
131     values.Put(MEDIA_DATA_DB_HEIGHT, metadata.GetFileHeight());
132     values.Put(MEDIA_DATA_DB_WIDTH, metadata.GetFileWidth());
133     values.Put(MEDIA_DATA_DB_ORIENTATION, metadata.GetOrientation());
134     values.Put(MEDIA_DATA_DB_DURATION, metadata.GetFileDuration());
135 
136     values.Put(MEDIA_DATA_DB_BUCKET_NAME, metadata.GetAlbumName());
137     values.Put(MEDIA_DATA_DB_PARENT_ID, metadata.GetParentId());
138     values.Put(MEDIA_DATA_DB_BUCKET_ID, metadata.GetParentId());
139 
140     values.Put(MEDIA_DATA_DB_DATE_TAKEN, metadata.GetDateTaken());
141     values.Put(MEDIA_DATA_DB_ORIENTATION, metadata.GetOrientation());
142     values.Put(MEDIA_DATA_DB_LONGITUDE, metadata.GetLongitude());
143     values.Put(MEDIA_DATA_DB_LATITUDE, metadata.GetLatitude());
144 
145     Uri uri(MEDIALIBRARY_DATA_URI);
146     updateCount = MediaLibraryDataManager::GetInstance()->Update(uri, values, predicates);
147     if (updateCount <= 0) {
148         MEDIA_ERR_LOG("RDBSTORE update failed");
149         return "";
150     }
151 
152     return (!mediaTypeUri.empty() ? (mediaTypeUri + "/" + to_string(metadata.GetFileId())) : mediaTypeUri);
153 }
154 
155 /**
156  * @brief Do a batch update of Metadata list
157  *
158  * @param metadataList The list of metadata to update in the media db
159  * @return int32_t Status of the update operation
160  */
UpdateMetadata(const vector<Metadata> & metadataList)161 int32_t MediaScannerDb::UpdateMetadata(const vector<Metadata> &metadataList)
162 {
163     int32_t status = 0;
164     vector<string> updateUriList;
165     for (auto itr : metadataList) {
166         updateUriList.push_back(UpdateMetadata(itr));
167     }
168 
169     return status;
170 }
171 
172 /**
173  * @brief Deletes particular entry in database based on row id
174  *
175  * @param idList The list of IDs to be deleted from the media db
176  * @return bool Status of the delete operation
177  */
DeleteMetadata(const vector<string> & idList)178 bool MediaScannerDb::DeleteMetadata(const vector<string> &idList)
179 {
180     int32_t deletedCount(0);
181     DataShare::DataSharePredicates predicates;
182 
183     if (idList.size() == 0) {
184         MEDIA_ERR_LOG("to-deleted idList size equals to 0");
185         return false;
186     }
187 
188     std::string builder = " IN (?";
189     for (std::size_t i = 0; i < idList.size() - 1; i++) {
190         builder += ",?";
191     }
192     builder += ")";
193 
194     predicates.SetWhereClause(MEDIA_DATA_DB_ID + builder);
195     predicates.SetWhereArgs(idList);
196 
197     Uri deleteUri(MEDIALIBRARY_DATA_URI);
198 
199     deletedCount = MediaLibraryDataManager::GetInstance()->Delete(deleteUri, predicates);
200     if (deletedCount > 0) {
201         return true;
202     }
203 
204     MEDIA_ERR_LOG("Failed to delete metadata");
205     return false;
206 }
207 
208 /**
209  * @brief Get date modified, id, size and name info for a file
210  *
211  * @param path The file path for which to obtain the latest modification info from the db
212  * @return unique_ptr<Metadata> The metadata object representing the latest info for the given filepath
213  */
GetFileBasicInfo(const string & path,unique_ptr<Metadata> & ptr)214 int32_t MediaScannerDb::GetFileBasicInfo(const string &path, unique_ptr<Metadata> &ptr)
215 {
216     Uri abilityUri(MEDIALIBRARY_DATA_URI);
217 
218     static vector<string> columns = {
219         MEDIA_DATA_DB_ID, MEDIA_DATA_DB_SIZE, MEDIA_DATA_DB_DATE_MODIFIED,
220         MEDIA_DATA_DB_NAME, MEDIA_DATA_DB_RECYCLE_PATH, MEDIA_DATA_DB_ORIENTATION
221     };
222 
223     DataShare::DataSharePredicates predicates;
224     predicates.SetWhereClause(MEDIA_DATA_DB_FILE_PATH + " = ?");
225     predicates.SetWhereArgs(vector<string>({ path }));
226 
227     auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(abilityUri, columns, predicates);
228     if (resultSet == nullptr) {
229         MEDIA_ERR_LOG("return nullptr when query rdb");
230         return E_RDB;
231     }
232 
233     int32_t rowCount = 0;
234     int32_t ret = resultSet->GetRowCount(rowCount);
235     if (ret != NativeRdb::E_OK) {
236         MEDIA_ERR_LOG("failed to get row count");
237         return E_RDB;
238     }
239 
240     if (rowCount == 0) {
241         return E_OK;
242     }
243 
244     ret = resultSet->GoToFirstRow();
245     if (ret != NativeRdb::E_OK) {
246         MEDIA_ERR_LOG("failed to go to first row");
247         return E_RDB;
248     }
249 
250     return FillMetadata(resultSet, ptr);
251 }
252 
253 /**
254  * @brief Get the list of all IDs corresponding to given path
255  *
256  * @param path The path from which to obtain the list of child IDs
257  * @return unordered_map<int32_t, MediaType> The list of IDS along with mediaType information
258  */
GetIdsFromFilePath(const string & path)259 unordered_map<int32_t, MediaType> MediaScannerDb::GetIdsFromFilePath(const string &path)
260 {
261     unordered_map<int32_t, MediaType> idMap = {};
262 
263     vector<string> columns = {};
264     columns.push_back(MEDIA_DATA_DB_ID);
265     columns.push_back(MEDIA_DATA_DB_MEDIA_TYPE);
266     columns.push_back(MEDIA_DATA_DB_RECYCLE_PATH);
267 
268     DataShare::DataSharePredicates predicates;
269     // Append % to end of the path for using LIKE statement
270     vector<string> args= { path.back() != '/' ? path + "/%" : path + "%" };
271     predicates.SetWhereClause(MEDIA_DATA_DB_FILE_PATH + " like ?");
272     predicates.SetWhereArgs(args);
273 
274     Uri queryUri(MEDIALIBRARY_DATA_URI);
275     auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(queryUri, columns, predicates);
276     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, idMap, "No entries found for this path");
277 
278     int32_t id(0);
279     int32_t idIndex(0);
280     int32_t mediaType(0);
281     int32_t mediaTypeIndex(0);
282     std::string recyclePath;
283     int32_t recyclePathIndex(0);
284 
285     resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, idIndex);
286     resultSet->GetColumnIndex(MEDIA_DATA_DB_MEDIA_TYPE, mediaTypeIndex);
287     resultSet->GetColumnIndex(MEDIA_DATA_DB_RECYCLE_PATH, recyclePathIndex);
288 
289     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
290         recyclePath.clear();
291         resultSet->GetString(recyclePathIndex, recyclePath);
292         if (!recyclePath.empty()) {
293             continue;
294         }
295 
296         resultSet->GetInt(idIndex, id);
297         resultSet->GetInt(mediaTypeIndex, mediaType);
298         idMap.emplace(make_pair(id, static_cast<MediaType>(mediaType)));
299     }
300 
301     return idMap;
302 }
303 
GetFileDBUriFromPath(const string & path)304 string MediaScannerDb::GetFileDBUriFromPath(const string &path)
305 {
306     string uri;
307 
308     vector<string> columns = {};
309     columns.push_back(MEDIA_DATA_DB_URI);
310 
311     DataShare::DataSharePredicates predicates;
312     predicates.SetWhereClause(MEDIA_DATA_DB_FILE_PATH + " = ?");
313     predicates.SetWhereArgs(vector<string>({ path }));
314 
315     Uri queryUri(MEDIALIBRARY_DATA_URI);
316     auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(queryUri, columns, predicates);
317     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, uri, "No entries found for this path");
318     if ((resultSet == nullptr) || (resultSet->GoToFirstRow() != NativeRdb::E_OK)) {
319         MEDIA_ERR_LOG("No result found for this path");
320         return uri;
321     }
322 
323     int32_t intValue(0);
324     int32_t columnIndex(0);
325     resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, columnIndex);
326     resultSet->GetInt(columnIndex, intValue);
327     uri = MEDIALIBRARY_DATA_URI + "/" + to_string(intValue);
328     return uri;
329 }
330 
GetIdFromPath(const string & path)331 int32_t MediaScannerDb::GetIdFromPath(const string &path)
332 {
333     int32_t id = UNKNOWN_ID;
334     int32_t columnIndex = -1;
335 
336     DataShare::DataSharePredicates predicates;
337     predicates.SetWhereClause(MEDIA_DATA_DB_FILE_PATH + " = ?");
338     predicates.SetWhereArgs(vector<string>({ path }));
339 
340     Uri uri(MEDIALIBRARY_DATA_URI);
341     vector<string> columns = {MEDIA_DATA_DB_ID};
342     auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(uri, columns, predicates);
343     if ((resultSet == nullptr) || (resultSet->GoToFirstRow() != NativeRdb::E_OK)) {
344         MEDIA_ERR_LOG("No data found for the given path %{private}s", path.c_str());
345         return id;
346     }
347 
348     resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, columnIndex);
349     resultSet->GetInt(columnIndex, id);
350 
351     return id;
352 }
353 
ReadAlbums(const string & path,unordered_map<string,Metadata> & albumMap)354 int32_t MediaScannerDb::ReadAlbums(const string &path, unordered_map<string, Metadata> &albumMap)
355 {
356     DataShare::DataSharePredicates predicates;
357     string queryCmd = MEDIA_DATA_DB_MEDIA_TYPE + " = ? AND " + MEDIA_DATA_DB_FILE_PATH + " like ? ";
358     string queryPath = path.back() != '/' ? path + "/%" : path + "%";
359     vector<string> args= { to_string(MediaType::MEDIA_TYPE_ALBUM), queryPath };
360     predicates.SetWhereClause(queryCmd);
361     predicates.SetWhereArgs(args);
362 
363     Uri uri(MEDIALIBRARY_DATA_URI);
364     vector<string> columns = {MEDIA_DATA_DB_ID, MEDIA_DATA_DB_FILE_PATH, MEDIA_DATA_DB_DATE_MODIFIED};
365     auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(uri, columns, predicates);
366     if (resultSet == nullptr) {
367         MEDIA_ERR_LOG("query %{private}s get nullptr result", path.c_str());
368         return E_RDB;
369     }
370 
371     int32_t intValue(0);
372     string strValue;
373     int64_t dateModified(0);
374 
375     int32_t columnIndexId(0);
376     int32_t columnIndexPath(0);
377     int32_t columnIndexDateModified(0);
378 
379     resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, columnIndexId);
380     resultSet->GetColumnIndex(MEDIA_DATA_DB_FILE_PATH, columnIndexPath);
381     resultSet->GetColumnIndex(MEDIA_DATA_DB_DATE_MODIFIED, columnIndexDateModified);
382 
383     albumMap.clear();
384     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
385         Metadata metadata;
386         resultSet->GetInt(columnIndexId, intValue);
387         metadata.SetFileId(intValue);
388 
389         resultSet->GetString(columnIndexPath, strValue);
390         metadata.SetFilePath(strValue);
391 
392         resultSet->GetLong(columnIndexDateModified, dateModified);
393         metadata.SetFileDateModified(dateModified);
394 
395         albumMap.insert(make_pair(strValue, metadata));
396     }
397 
398     return E_OK;
399 }
400 
InsertAlbum(const Metadata & metadata)401 int32_t MediaScannerDb::InsertAlbum(const Metadata &metadata)
402 {
403     int32_t id = 0;
404 
405     string uri = InsertMetadata(metadata);
406     id = stoi(MediaLibraryDataManagerUtils::GetIdFromUri(uri));
407 
408     return id;
409 }
410 
UpdateAlbum(const Metadata & metadata)411 int32_t MediaScannerDb::UpdateAlbum(const Metadata &metadata)
412 {
413     int32_t id = 0;
414 
415     string uri = UpdateMetadata(metadata);
416     id = stoi(MediaLibraryDataManagerUtils::GetIdFromUri(uri));
417 
418     return id;
419 }
420 
GetMediaTypeUri(MediaType mediaType)421 string MediaScannerDb::GetMediaTypeUri(MediaType mediaType)
422 {
423     switch (mediaType) {
424         case MEDIA_TYPE_AUDIO:
425             return MEDIALIBRARY_AUDIO_URI;
426         case MEDIA_TYPE_VIDEO:
427             return MEDIALIBRARY_VIDEO_URI;
428         case MEDIA_TYPE_IMAGE:
429             return MEDIALIBRARY_IMAGE_URI;
430         case MEDIA_TYPE_FILE:
431         default:
432             return MEDIALIBRARY_FILE_URI;
433     }
434 }
435 
NotifyDatabaseChange(const MediaType mediaType)436 void MediaScannerDb::NotifyDatabaseChange(const MediaType mediaType)
437 {
438     string notifyUri = GetMediaTypeUri(mediaType);
439     Uri uri(notifyUri);
440 
441     MediaLibraryDataManager::GetInstance()->NotifyChange(uri);
442 }
443 
ExtractMetaFromColumn(const shared_ptr<NativeRdb::AbsSharedResultSet> & resultSet,unique_ptr<Metadata> & metadata,const std::string & col)444 void MediaScannerDb::ExtractMetaFromColumn(const shared_ptr<NativeRdb::AbsSharedResultSet> &resultSet,
445                                            unique_ptr<Metadata> &metadata, const std::string &col)
446 {
447     ResultSetDataType dataType = ResultSetDataType::TYPE_NULL;
448     Metadata::MetadataFnPtr requestFunc = nullptr;
449     auto itr = metadata->memberFuncMap_.find(col);
450     if (itr != metadata->memberFuncMap_.end()) {
451         dataType = itr->second.first;
452         requestFunc = itr->second.second;
453     } else {
454         MEDIA_ERR_LOG("invalid column name %{private}s", col.c_str());
455         return;
456     }
457 
458     std::variant<int32_t, std::string, int64_t, double> data =
459         ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::AbsSharedResultSet>>(col, resultSet, dataType);
460 
461     // Use the function pointer from map and pass data to fn ptr
462     if (requestFunc != nullptr) {
463         (metadata.get()->*requestFunc)(data);
464     }
465 }
466 
FillMetadata(const shared_ptr<NativeRdb::AbsSharedResultSet> & resultSet,unique_ptr<Metadata> & ptr)467 int32_t MediaScannerDb::FillMetadata(const shared_ptr<NativeRdb::AbsSharedResultSet> &resultSet,
468     unique_ptr<Metadata> &ptr)
469 {
470     std::vector<std::string> columnNames;
471     int32_t err = resultSet->GetAllColumnNames(columnNames);
472     if (err != NativeRdb::E_OK) {
473         MEDIA_ERR_LOG("failed to get all column names");
474         return E_RDB;
475     }
476 
477     for (const auto &col : columnNames) {
478         ExtractMetaFromColumn(resultSet, ptr, col);
479     }
480 
481     return E_OK;
482 }
483 } // namespace Media
484 } // namespace OHOS
485