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