• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "media_ani_native_impl.h"
17 
18 #include <string>
19 #include <memory>
20 
21 #include "medialibrary_ani_enum_comm.h"
22 #include "medialibrary_ani_log.h"
23 #include "media_device_column.h"
24 #include "photo_album_column.h"
25 #include "media_file_uri.h"
26 #include "media_file_utils.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_db_const.h"
29 #include "userfile_client.h"
30 #include "medialibrary_tracer.h"
31 
32 using namespace std;
33 using namespace OHOS::DataShare;
34 
35 namespace OHOS {
36 namespace Media {
GetFileAssetsInfo(const std::vector<std::string> & fetchColumns,const DataShare::DataSharePredicates * predicate)37 std::vector<std::unique_ptr<FileAsset>> MediaAniNativeImpl::GetFileAssetsInfo(
38     const std::vector<std::string> &fetchColumns,
39     const DataShare::DataSharePredicates *predicate)
40 {
41     MediaLibraryTracer tracer;
42     tracer.Start("GetFileAssetsInfo Excute");
43 
44     std::vector<std::unique_ptr<FileAsset>> result;
45     std::shared_ptr<MediaLibraryAsyncContext> context = GetAssetsContext(fetchColumns, predicate);
46     if (context == nullptr) {
47         ANI_ERR_LOG("GetAssetsContext failed");
48         return result;
49     }
50 
51     if (!PhotoAccessGetFileAssetsInfoExecute(context, result)) {
52         ANI_ERR_LOG("PhotoAccessGetFileAssetsInfoExecute failed");
53     }
54 
55     return result;
56 }
57 
GetAssetsSync(const std::vector<std::string> & fetchColumns,const DataSharePredicates * predicate)58 std::vector<std::unique_ptr<FileAsset>> MediaAniNativeImpl::GetAssetsSync(
59     const std::vector<std::string> &fetchColumns, const DataSharePredicates *predicate)
60 {
61     MediaLibraryTracer tracer;
62     tracer.Start("GetAssetsSync Excute");
63 
64     std::vector<std::unique_ptr<FileAsset>> result;
65     std::shared_ptr<MediaLibraryAsyncContext> context = GetAssetsContext(fetchColumns, predicate);
66     if (context == nullptr) {
67         ANI_ERR_LOG("GetAssetsContext failed");
68         return result;
69     }
70 
71     if (!PhotoAccessGetAssetsExecuteSync(context, result)) {
72         ANI_ERR_LOG("PhotoAccessGetAssetsExecuteSync failed");
73     }
74 
75     return result;
76 }
77 
GetAssets(const std::vector<std::string> & fetchColumns,const DataSharePredicates * predicate)78 std::unique_ptr<FetchResult<FileAsset>> MediaAniNativeImpl::GetAssets(
79     const std::vector<std::string> &fetchColumns, const DataSharePredicates *predicate)
80 {
81     MediaLibraryTracer tracer;
82     tracer.Start("GetAssets Excute");
83 
84     std::shared_ptr<MediaLibraryAsyncContext> context = GetAssetsContext(fetchColumns, predicate);
85     if (context == nullptr) {
86         ANI_ERR_LOG("GetAssetsContext failed");
87         return nullptr;
88     }
89 
90     if (!PhotoAccessGetAssetsExecute(context)) {
91         ANI_ERR_LOG("PhotoAccessGetAssetsExecute failed");
92         return nullptr;
93     }
94 
95     return std::move(context->fetchFileResult);
96 }
97 
GetAssetsContext(const std::vector<std::string> & fetchColumns,const DataSharePredicates * predicate)98 std::shared_ptr<MediaLibraryAsyncContext> MediaAniNativeImpl::GetAssetsContext(
99     const std::vector<std::string> &fetchColumns, const DataSharePredicates *predicate)
100 {
101     std::shared_ptr<MediaLibraryAsyncContext> context = std::make_shared<MediaLibraryAsyncContext>();
102     context->assetType = TYPE_PHOTO;
103     if (!HandleSpecialPredicate(context, predicate, ASSET_FETCH_OPT)) {
104         ANI_ERR_LOG("HandleSpecialPredicate failed");
105         return nullptr;
106     }
107     if (!GetLocationPredicate(context, predicate)) {
108         ANI_ERR_LOG("GetLocationPredicate failed");
109         return nullptr;
110     }
111 
112     context->fetchColumn = fetchColumns;
113     if (!AddDefaultAssetColumns(context->fetchColumn, PhotoColumn::IsPhotoColumn)) {
114         ANI_ERR_LOG("AddDefaultAssetColumns failed");
115         return nullptr;
116     }
117 
118     auto &predicates = context->predicates;
119     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
120     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
121     predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
122     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
123     predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
124         to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
125 
126     return context;
127 }
128 
HandleSpecialDateTypePredicate(const OperationItem & item,vector<OperationItem> & operations,const FetchOptionType & fetchOptType)129 static bool HandleSpecialDateTypePredicate(const OperationItem &item,
130     vector<OperationItem> &operations, const FetchOptionType &fetchOptType)
131 {
132     constexpr int32_t fieldIdx = 0;
133     constexpr int32_t valueIdx = 1;
134     vector<string>dateTypes = { MEDIA_DATA_DB_DATE_ADDED, MEDIA_DATA_DB_DATE_TRASHED, MEDIA_DATA_DB_DATE_MODIFIED,
135         MEDIA_DATA_DB_DATE_TAKEN};
136     string dateType = item.GetSingle(fieldIdx);
137     auto it = find(dateTypes.begin(), dateTypes.end(), dateType);
138     if (it != dateTypes.end() && item.operation != DataShare::ORDER_BY_ASC &&
139         item.operation != DataShare::ORDER_BY_DESC) {
140         dateType += "_s";
141         operations.push_back({ item.operation, { dateType, static_cast<double>(item.GetSingle(valueIdx)) } });
142         return true;
143     }
144     if (DATE_TRANSITION_MAP.count(dateType) != 0) {
145         dateType = DATE_TRANSITION_MAP.at(dateType);
146         operations.push_back({ item.operation, { dateType, static_cast<double>(item.GetSingle(valueIdx)) } });
147         return true;
148     }
149     return false;
150 }
151 
HandleSpecialPredicate(std::shared_ptr<MediaLibraryAsyncContext> context,const DataSharePredicates * predicate,const FetchOptionType & fetchOptType)152 bool MediaAniNativeImpl::HandleSpecialPredicate(std::shared_ptr<MediaLibraryAsyncContext> context,
153     const DataSharePredicates *predicate, const FetchOptionType &fetchOptType)
154 {
155     constexpr int32_t fieldIdx = 0;
156     constexpr int32_t valueIdx = 1;
157     std::vector<OperationItem> operations;
158     auto &items = predicate->GetOperationList();
159     for (auto &item : items) {
160         if (item.singleParams.empty()) {
161             operations.push_back(item);
162             continue;
163         }
164         if (HandleSpecialDateTypePredicate(item, operations, fetchOptType)) {
165             continue;
166         }
167         // change uri ->file id
168         // get networkid
169         // replace networkid with file id
170         if (static_cast<string>(item.GetSingle(fieldIdx)) == DEVICE_DB_NETWORK_ID) {
171             if (item.operation != DataShare::EQUAL_TO || static_cast<string>(item.GetSingle(valueIdx)).empty()) {
172                 ANI_ERR_LOG("DEVICE_DB_NETWORK_ID predicates not support %{public}d", item.operation);
173                 return false;
174             }
175             context->networkId = static_cast<string>(item.GetSingle(valueIdx));
176             continue;
177         }
178         if (static_cast<string>(item.GetSingle(fieldIdx)) == MEDIA_DATA_DB_URI) {
179             if (item.operation != DataShare::EQUAL_TO) {
180                 ANI_ERR_LOG("MEDIA_DATA_DB_URI predicates not support %{public}d", item.operation);
181                 return false;
182             }
183             string uri = static_cast<string>(item.GetSingle(valueIdx));
184             MediaFileUri::RemoveAllFragment(uri);
185             MediaFileUri fileUri(uri);
186             context->uri = uri;
187             if ((fetchOptType != ALBUM_FETCH_OPT) && (!fileUri.IsApi10())) {
188                 fileUri = MediaFileUri(MediaFileUtils::GetRealUriFromVirtualUri(uri));
189             }
190             context->networkId = fileUri.GetNetworkId();
191             string field = (fetchOptType == ALBUM_FETCH_OPT) ? PhotoAlbumColumns::ALBUM_ID : MEDIA_DATA_DB_ID;
192             operations.push_back({ item.operation, { field, fileUri.GetFileId() } });
193             continue;
194         }
195         if (static_cast<string>(item.GetSingle(fieldIdx)) == PENDING_STATUS) {
196             // do not query pending files below API11
197             continue;
198         }
199         if (LOCATION_PARAM_MAP.find(static_cast<string>(item.GetSingle(fieldIdx))) != LOCATION_PARAM_MAP.end()) {
200             continue;
201         }
202         operations.push_back(item);
203     }
204     context->predicates = DataSharePredicates(move(operations));
205     return true;
206 }
207 
GetLocationPredicate(std::shared_ptr<MediaLibraryAsyncContext> context,const DataSharePredicates * predicate)208 bool MediaAniNativeImpl::GetLocationPredicate(std::shared_ptr<MediaLibraryAsyncContext> context,
209     const DataSharePredicates *predicate)
210 {
211     constexpr int32_t fieldIdx = 0;
212     constexpr int32_t valueIdx = 1;
213     map<string, string> locationMap;
214     auto &items = predicate->GetOperationList();
215     for (auto &item : items) {
216         if (item.singleParams.empty()) {
217             continue;
218         }
219         if (LOCATION_PARAM_MAP.find(static_cast<string>(item.GetSingle(fieldIdx))) != LOCATION_PARAM_MAP.end()) {
220             if (item.operation != DataShare::EQUAL_TO) {
221                 ANI_ERR_LOG("location predicates not support %{public}d", item.operation);
222                 return false;
223             }
224             string param = static_cast<string>(item.GetSingle(fieldIdx));
225             string value = static_cast<string>(item.GetSingle(valueIdx));
226             locationMap.insert(make_pair(param, value));
227             if (param == DIAMETER) {
228                 continue;
229             }
230             if (LOCATION_PARAM_MAP.at(param).second == DataShare::GREATER_THAN_OR_EQUAL_TO) {
231                 context->predicates.GreaterThanOrEqualTo(LOCATION_PARAM_MAP.at(param).first, value);
232                 continue;
233             }
234             if (LOCATION_PARAM_MAP.at(param).second == DataShare::LESS_THAN) {
235                 context->predicates.LessThan(LOCATION_PARAM_MAP.at(param).first, value);
236                 continue;
237             }
238             if (LOCATION_PARAM_MAP.at(param).second == DataShare::EQUAL_TO) {
239                 context->predicates.EqualTo(LOCATION_PARAM_MAP.at(param).first, value);
240                 continue;
241             }
242         }
243     }
244 
245     if (locationMap.count(DIAMETER) == 1 && locationMap.count(START_LATITUDE) == 1
246         && locationMap.count(START_LONGITUDE) == 1) {
247         // 0.5:Used for rounding down
248         string latitudeIndex = "round((latitude - " + locationMap.at(START_LATITUDE) + ") / " +
249             locationMap.at(DIAMETER) + " - 0.5)";
250         string longitudeIndex = "round((longitude - " + locationMap.at(START_LONGITUDE) + ") / " +
251             locationMap.at(DIAMETER) + " - 0.5)";
252         string albumName = LATITUDE + "||'_'||" + LONGITUDE + "||'_'||" + latitudeIndex + "||'_'||" +
253             longitudeIndex + " AS " + ALBUM_NAME;
254         context->fetchColumn.push_back(albumName);
255         string locationGroup = latitudeIndex + "," + longitudeIndex;
256         context->predicates.GroupBy({ locationGroup });
257     }
258     return true;
259 }
260 
AddDefaultAssetColumns(vector<string> & fetchColumn,function<bool (const string & columnName)> isValidColumn,const PhotoAlbumSubType subType)261 bool MediaAniNativeImpl::AddDefaultAssetColumns(vector<string> &fetchColumn,
262     function<bool(const string &columnName)> isValidColumn, const PhotoAlbumSubType subType)
263 {
264     auto validFetchColumns = MediaColumn::DEFAULT_FETCH_COLUMNS;
265     validFetchColumns.insert(PhotoColumn::DEFAULT_FETCH_COLUMNS.begin(), PhotoColumn::DEFAULT_FETCH_COLUMNS.end());
266 
267     switch (subType) {
268         case PhotoAlbumSubType::FAVORITE:
269             validFetchColumns.insert(MediaColumn::MEDIA_IS_FAV);
270             break;
271         case PhotoAlbumSubType::VIDEO:
272             validFetchColumns.insert(MediaColumn::MEDIA_TYPE);
273             break;
274         case PhotoAlbumSubType::HIDDEN:
275             validFetchColumns.insert(MediaColumn::MEDIA_HIDDEN);
276             break;
277         case PhotoAlbumSubType::TRASH:
278             validFetchColumns.insert(MediaColumn::MEDIA_DATE_TRASHED);
279             break;
280         case PhotoAlbumSubType::SCREENSHOT:
281         case PhotoAlbumSubType::CAMERA:
282             validFetchColumns.insert(PhotoColumn::PHOTO_SUBTYPE);
283             break;
284         default:
285             break;
286     }
287     for (const auto &column : fetchColumn) {
288         if (column == PENDING_STATUS) {
289             validFetchColumns.insert(MediaColumn::MEDIA_TIME_PENDING);
290         } else if (isValidColumn(column)) {
291             validFetchColumns.insert(column);
292         } else if (column == MEDIA_DATA_DB_URI) {
293             continue;
294         } else if (DATE_TRANSITION_MAP.count(column) != 0) {
295             validFetchColumns.insert(DATE_TRANSITION_MAP.at(column));
296         } else {
297             ANI_ERR_LOG("error");
298             return false;
299         }
300     }
301     fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
302 
303     return true;
304 }
305 
UriAppendKeyValue(string & uri,const string & key,const string & value)306 static void UriAppendKeyValue(string &uri, const string &key, const string &value)
307 {
308     string uriKey = key + '=';
309     if (uri.find(uriKey) != string::npos) {
310         return;
311     }
312 
313     char queryMark = (uri.find('?') == string::npos) ? '?' : '&';
314     string append = queryMark + key + '=' + value;
315 
316     size_t posJ = uri.find('#');
317     if (posJ == string::npos) {
318         uri += append;
319     } else {
320         uri.insert(posJ, append);
321     }
322 }
323 
PhotoAccessGetAssetsExecuteSync(std::shared_ptr<MediaLibraryAsyncContext> context,std::vector<std::unique_ptr<FileAsset>> & fileAssetArray)324 bool MediaAniNativeImpl::PhotoAccessGetAssetsExecuteSync(std::shared_ptr<MediaLibraryAsyncContext> context,
325     std::vector<std::unique_ptr<FileAsset>>& fileAssetArray)
326 {
327     string queryUri = PAH_QUERY_PHOTO;
328     UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
329 
330     Uri uri(queryUri);
331     int errCode = 0;
332     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates,
333         context->fetchColumn, errCode);
334     if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
335         Uri queryWithUri(context->uri);
336         resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
337     }
338     if (resultSet == nullptr) {
339         ANI_ERR_LOG("resultSet is nullptr");
340         return false;
341     }
342 
343     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
344     if (fetchResult == nullptr) {
345         ANI_ERR_LOG("fetchResult is nullptr");
346         return false;
347     }
348     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
349 
350     auto file = fetchResult->GetFirstObject();
351     while (file != nullptr) {
352         fileAssetArray.push_back(move(file));
353         file = fetchResult->GetNextObject();
354     }
355     return true;
356 }
357 
PhotoAccessGetAssetsExecute(std::shared_ptr<MediaLibraryAsyncContext> context)358 bool MediaAniNativeImpl::PhotoAccessGetAssetsExecute(std::shared_ptr<MediaLibraryAsyncContext> context)
359 {
360     string queryUri = PAH_QUERY_PHOTO;
361     UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
362 
363     Uri uri(queryUri);
364     int errCode = 0;
365     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates,
366         context->fetchColumn, errCode);
367     if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
368         Uri queryWithUri(context->uri);
369         resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
370     }
371     if (resultSet == nullptr) {
372         ANI_ERR_LOG("resultSet is nullptr");
373         return false;
374     }
375 
376     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
377     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
378     return true;
379 }
380 
PhotoAccessGetFileAssetsInfoExecute(std::shared_ptr<MediaLibraryAsyncContext> context,std::vector<std::unique_ptr<FileAsset>> & fileAssetArray)381 bool MediaAniNativeImpl::PhotoAccessGetFileAssetsInfoExecute(std::shared_ptr<MediaLibraryAsyncContext> context,
382     std::vector<std::unique_ptr<FileAsset>>& fileAssetArray)
383 {
384     if (context->assetType != TYPE_PHOTO) {
385         return false;
386     }
387     string queryUri = PAH_QUERY_PHOTO;
388     UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
389 
390     Uri uri(queryUri);
391     shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
392         context->predicates, context->fetchColumn);
393     if (resultSet == nullptr) {
394         ANI_ERR_LOG("QueryRdb failed");
395         return false;
396     }
397 
398     while (!resultSet->GoToNextRow()) {
399         std::unique_ptr<FileAsset> fileAsset = GetNextRowFileAsset(resultSet);
400         if (fileAsset == nullptr) {
401             ANI_ERR_LOG("get fileAsset failed");
402             continue;
403         }
404         fileAssetArray.emplace_back(std::move(fileAsset));
405     }
406     return true;
407 }
408 
GetNextRowFileAsset(shared_ptr<NativeRdb::ResultSet> resultSet)409 std::unique_ptr<FileAsset> MediaAniNativeImpl::GetNextRowFileAsset(shared_ptr<NativeRdb::ResultSet> resultSet)
410 {
411     if (resultSet == nullptr) {
412         ANI_ERR_LOG("resultSet is nullptr");
413         return nullptr;
414     }
415     vector<string> columnNames;
416     resultSet->GetAllColumnNames(columnNames);
417 
418     std::unique_ptr<FileAsset> fileAsset;
419     int32_t index = -1;
420     for (const auto &name : columnNames) {
421         index++;
422 
423         // Check if the column name exists in the type map
424         if (MediaLibraryAniUtils::GetTypeMap().count(name) == 0) {
425             continue;
426         }
427         GetFileAssetField(index, name, resultSet, fileAsset);
428     }
429     string extrUri = MediaFileUtils::GetExtraUri(fileAsset->GetDisplayName(), fileAsset->GetPath(), false);
430     MediaFileUri fileUri(fileAsset->GetMediaType(), to_string(fileAsset->GetId()), "", MEDIA_API_VERSION_V10, extrUri);
431     fileAsset->SetUri(move(fileUri.ToString()));
432 
433     return fileAsset;
434 }
435 
GetFileAssetField(int32_t index,string name,const shared_ptr<NativeRdb::ResultSet> resultSet,std::unique_ptr<FileAsset> & fileAsset)436 void MediaAniNativeImpl::GetFileAssetField(int32_t index, string name, const shared_ptr<NativeRdb::ResultSet> resultSet,
437     std::unique_ptr<FileAsset> &fileAsset)
438 {
439     if (!fileAsset) {
440         ANI_ERR_LOG("fileAsset is null");
441         return;
442     }
443 
444     int status;
445     int integerVal = 0;
446     string stringVal = "";
447     int64_t longVal = 0;
448     double doubleVal = 0.0;
449 
450     const auto& typeMap = MediaLibraryAniUtils::GetTypeMap();
451     auto it = typeMap.find(name);
452     if (it == typeMap.end()) {
453         ANI_ERR_LOG("Unknown field name: %{public}s", name.c_str());
454         return;
455     }
456     auto dataType = it->second;
457 
458     switch (dataType.first) {
459         case TYPE_STRING:
460             status = resultSet->GetString(index, stringVal);
461             ANI_DEBUG_LOG("GetFileAssetField TYPE_STRING: status: %{public}d", status);
462             fileAsset->GetMemberMap().emplace(name, stringVal);
463             break;
464         case TYPE_INT32:
465             status = resultSet->GetInt(index, integerVal);
466             ANI_DEBUG_LOG("GetFileAssetField TYPE_INT32: status: %{public}d", status);
467             fileAsset->GetMemberMap().emplace(name, integerVal);
468             break;
469         case TYPE_INT64:
470             status = resultSet->GetLong(index, longVal);
471             ANI_DEBUG_LOG("GetFileAssetField TYPE_INT64: status: %{public}d", status);
472             fileAsset->GetMemberMap().emplace(name, longVal);
473             break;
474         case TYPE_DOUBLE:
475             status = resultSet->GetDouble(index, doubleVal);
476             ANI_DEBUG_LOG("GetFileAssetField TYPE_DOUBLE: status: %{public}d", status);
477             fileAsset->GetMemberMap().emplace(name, doubleVal);
478             break;
479         default:
480             ANI_ERR_LOG("not match dataType %{public}d", dataType.first);
481             break;
482     }
483 }
484 } // namespace Media
485 } // namespace OHOS