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 "medialibrary_facard_operations.h"
17
18 #include <memory>
19 #include <mutex>
20 #include <string>
21 #include "abs_shared_result_set.h"
22
23 #include "media_column.h"
24 #include "media_file_uri.h"
25 #include "media_file_utils.h"
26 #include "media_log.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_object_utils.h"
29 #include "medialibrary_rdbstore.h"
30 #include "rdb_predicates.h"
31 #include "result_set_utils.h"
32 #include "value_object.h"
33 #include "values_bucket.h"
34 #include "datashare_helper.h"
35 #include "medialibrary_data_manager.h"
36 #include "media_facard_photos_column.h"
37 #include "result_set_utils.h"
38 #include "ability_manager_client.h"
39 #include "application_context.h"
40 #include "resource_type.h"
41 #include "ffrt.h"
42 #include "ffrt_inner.h"
43
44 using namespace OHOS::DataShare;
45 using ChangeType = OHOS::DataShare::DataShareObserver::ChangeType;
46 using namespace std;
47 using namespace OHOS::NativeRdb;
48
49 namespace OHOS {
50 namespace Media {
51 std::mutex MediaLibraryFaCardOperations::mutex_;
52 const string MEDIA_LIBRARY_PROXY_URI = "datashareproxy://com.ohos.medialibrary.medialibrarydata";
53 static std::map<std::string, std::vector<std::shared_ptr<CardAssetUriObserver>>> formAssetObserversMap;
54 const string CLOUD_SYNC_PROXY_URI = "datashareproxy://com.huawei.hmos.clouddrive/sync_switch";
55 static std::map<std::string, std::vector<sptr<FaCloudSyncSwitchObserver>>> formCloudSyncObserversMap;
56 static std::map<ChangeType, int> changeTypeMap = {
57 { ChangeType::INSERT, 0 },
58 { ChangeType::DELETE, 1 },
59 { ChangeType::UPDATE, 2 },
60 { ChangeType::OTHER, 3 },
61 { ChangeType::INVAILD, 4 },
62 };
63
64 bool CardAssetUriObserver::isTaskPosted = false;
65 std::mutex CardAssetUriObserver::mtx;
66 std::unordered_set<
67 CardAssetUriObserver::AssetChangeInfo,
68 CardAssetUriObserver::AssetChangeInfoHash> CardAssetUriObserver::assetChanges;
69
70 bool FaCloudSyncSwitchObserver::isTaskPosted = false;
71 std::mutex FaCloudSyncSwitchObserver::mtx;
72 std::unordered_set<
73 FaCloudSyncSwitchObserver::CloudSyncChangeInfo,
74 FaCloudSyncSwitchObserver::CloudSyncChangeInfoHash> FaCloudSyncSwitchObserver::cloudSyncChanges;
75 // LCOV_EXCL_START
GetUris()76 std::map<std::string, std::vector<std::string>> MediaLibraryFaCardOperations::GetUris()
77 {
78 lock_guard<mutex> lock(mutex_);
79 MediaLibraryCommand queryFaCardCmd(OperationObject::TAB_FACARD_PHOTO, OperationType::QUERY);
80 std::map<std::string, std::vector<std::string>> resultMap;
81 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
82 if (uniStore == nullptr) {
83 MEDIA_ERR_LOG("UniStore is nullptr");
84 return resultMap;
85 }
86 vector<string> columns = {
87 TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI,
88 TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID
89 };
90 auto queryResult = uniStore->Query(queryFaCardCmd, columns);
91 if (queryResult == nullptr) {
92 MEDIA_ERR_LOG("Failed to query assetUris!");
93 return resultMap;
94 }
95 while (queryResult->GoToNextRow() == NativeRdb::E_OK) {
96 string assetUri = GetStringVal(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, queryResult);
97 string formId = GetStringVal(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, queryResult);
98 resultMap[formId].push_back(assetUri);
99 }
100 return resultMap;
101 }
102
GetStringObject(MediaLibraryCommand & cmd,const string & columnName)103 static string GetStringObject(MediaLibraryCommand &cmd, const string &columnName)
104 {
105 ValueObject valueObject;
106 ValuesBucket values = cmd.GetValueBucket();
107 string value;
108 if (values.GetObject(columnName, valueObject)) {
109 valueObject.GetString(value);
110 return value;
111 }
112 return "";
113 }
114
PostAssetChangeTask()115 void CardAssetUriObserver::PostAssetChangeTask()
116 {
117 if (!CardAssetUriObserver::isTaskPosted) {
118 CardAssetUriObserver::isTaskPosted = true;
119 thread([]() {
120 MEDIA_DEBUG_LOG("CardAssetUriObserver task start");
121 const int DELAY_MILLISECONDS = 2000;
122 this_thread::sleep_for(chrono::milliseconds(DELAY_MILLISECONDS));
123 std::lock_guard<std::mutex> lock(CardAssetUriObserver::mtx);
124 std::vector<std::string> assetChangeUris;
125 std::vector<int> assetChangeTypes;
126 for (const auto& change : CardAssetUriObserver::assetChanges) {
127 assetChangeUris.push_back(change.assetChangeUri);
128 MEDIA_DEBUG_LOG("change.assetChangeUri = %{public}s", change.assetChangeUri.c_str());
129 assetChangeTypes.push_back(change.assetChangeType);
130 MEDIA_DEBUG_LOG("change.assetChangeType = %{public}d", change.assetChangeType);
131 }
132 AAFwk::Want want;
133 want.SetElementName("com.huawei.hmos.photos", "FACardServiceAbility");
134 want.SetParam("assetChangeUris", assetChangeUris);
135 want.SetParam("assetChangeTypes", assetChangeTypes);
136 int32_t userId = -1;
137 auto result = AAFwk::AbilityManagerClient::GetInstance()->StartExtensionAbility(
138 want, nullptr, userId, AppExecFwk::ExtensionAbilityType::SERVICE);
139 CardAssetUriObserver::assetChanges.clear();
140 CardAssetUriObserver::isTaskPosted = false;
141 MEDIA_DEBUG_LOG("CardAssetUriObserver task end");
142 }).detach();
143 }
144 }
145
PostAssetChangeTask()146 void FaCloudSyncSwitchObserver::PostAssetChangeTask()
147 {
148 if (!FaCloudSyncSwitchObserver::isTaskPosted) {
149 FaCloudSyncSwitchObserver::isTaskPosted = true;
150 thread([]() {
151 MEDIA_INFO_LOG("FaCloudSyncSwitchObserver task start");
152 const int DELAY_MILLISECONDS = 2000;
153 this_thread::sleep_for(chrono::milliseconds(DELAY_MILLISECONDS));
154 std::lock_guard<std::mutex> lock(FaCloudSyncSwitchObserver::mtx);
155 std::vector<std::string> assetChangeUris;
156 std::vector<int> assetChangeTypes;
157 for (const auto& change : FaCloudSyncSwitchObserver::cloudSyncChanges) {
158 assetChangeUris.push_back(change.cloudSyncChangeUri);
159 assetChangeTypes.push_back(change.cloudSyncChangeType);
160 MEDIA_INFO_LOG("change.assetChangeUri = %{public}s, change.assetChangeType = %{public}d",
161 change.cloudSyncChangeUri.c_str(), change.cloudSyncChangeType);
162 }
163 AAFwk::Want want;
164 want.SetElementName("com.huawei.hmos.photos", "FACardServiceAbility");
165 want.SetParam("assetChangeUris", assetChangeUris);
166 want.SetParam("assetChangeTypes", assetChangeTypes);
167 int32_t userId = -1;
168 auto result = AAFwk::AbilityManagerClient::GetInstance()->StartExtensionAbility(
169 want, nullptr, userId, AppExecFwk::ExtensionAbilityType::SERVICE);
170 FaCloudSyncSwitchObserver::cloudSyncChanges.clear();
171 FaCloudSyncSwitchObserver::isTaskPosted = false;
172 MEDIA_INFO_LOG("FaCloudSyncSwitchObserver task end");
173 }).detach();
174 }
175 }
176
OnChange(const ChangeInfo & changeInfo)177 void CardAssetUriObserver::OnChange(const ChangeInfo &changeInfo)
178 {
179 if (changeTypeMap.find(changeInfo.changeType_) != changeTypeMap.end()) {
180 std::lock_guard<std::mutex> lock(CardAssetUriObserver::mtx);
181 MEDIA_DEBUG_LOG("OnChange assetChangeUri = %{public}s", assetChangeUri.c_str());
182 MEDIA_DEBUG_LOG("OnChange assetChangeType = %{public}d", static_cast<int>(changeInfo.changeType_));
183 CardAssetUriObserver::assetChanges.insert(
184 AssetChangeInfo(assetChangeUri, static_cast<int>(changeInfo.changeType_)));
185
186 PostAssetChangeTask();
187 }
188 }
189
OnChange()190 void FaCloudSyncSwitchObserver::OnChange()
191 {
192 std::lock_guard<std::mutex> lock(FaCloudSyncSwitchObserver::mtx);
193 const int CLOUD_SYNC_TYPE = 3;
194 MEDIA_INFO_LOG("OnChange assetChangeUri = %{public}s, assetChangeType = %{public}d", cloudSyncChangeUri.c_str(),
195 static_cast<int>(CLOUD_SYNC_TYPE));
196 FaCloudSyncSwitchObserver::cloudSyncChanges.insert(
197 CloudSyncChangeInfo(cloudSyncChangeUri, static_cast<int>(CLOUD_SYNC_TYPE)));
198
199 PostAssetChangeTask();
200 }
201
RegisterObserver(const std::string & formId,const std::string & registerUri)202 void MediaLibraryFaCardOperations::RegisterObserver(const std::string &formId, const std::string ®isterUri)
203 {
204 if (formId.empty() || registerUri.empty()) {
205 MEDIA_ERR_LOG("parameter is null");
206 return;
207 }
208 const std::string ASSET_URI_PREFIX = "file://media/";
209 const std::string CLOUD_SYNC_SWITCH_URI_PREFIX = "datashareproxy://";
210 MEDIA_INFO_LOG("registerUri = %{public}s", registerUri.c_str());
211
212 std::shared_ptr<DataShare::DataShareObserver> observer;
213 sptr<FaCloudSyncSwitchObserver> cloudSyncObserver;
214 if (registerUri.find(ASSET_URI_PREFIX) == 0) {
215 auto cardAssetUriObserver = std::make_shared<CardAssetUriObserver>(registerUri);
216 if (cardAssetUriObserver == nullptr) {
217 return;
218 }
219 MEDIA_DEBUG_LOG("cardAssetUriObserver->uri = %{public}s", cardAssetUriObserver->assetChangeUri.c_str());
220 formAssetObserversMap[formId].push_back(cardAssetUriObserver);
221 observer = std::static_pointer_cast<DataShare::DataShareObserver>(cardAssetUriObserver);
222 } else if (registerUri.find(CLOUD_SYNC_SWITCH_URI_PREFIX) == 0) {
223 sptr<FaCloudSyncSwitchObserver> cloudSwitchObserver(new (std::nothrow) FaCloudSyncSwitchObserver(registerUri));
224 if (cloudSwitchObserver == nullptr) {
225 return;
226 }
227 MEDIA_INFO_LOG("FaCloudSyncuri = %{public}s", cloudSwitchObserver->cloudSyncChangeUri.c_str());
228 formCloudSyncObserversMap[formId].push_back(cloudSwitchObserver);
229 cloudSyncObserver = cloudSwitchObserver;
230 } else {
231 MEDIA_ERR_LOG("registerUri is inValid");
232 return;
233 }
234 Uri notifyUri(registerUri);
235 CreateOptions options;
236 options.enabled_ = true;
237 shared_ptr<DataShare::DataShareHelper> dataShareHelper;
238 if (registerUri.find(ASSET_URI_PREFIX) == 0) {
239 dataShareHelper = DataShare::DataShareHelper::Creator(MEDIA_LIBRARY_PROXY_URI, options);
240 if (dataShareHelper == nullptr || observer == nullptr) {
241 MEDIA_ERR_LOG("dataShareHelper is nullptr");
242 return;
243 }
244 dataShareHelper->RegisterObserverExt(notifyUri, observer, true);
245 } else if (registerUri.find(CLOUD_SYNC_SWITCH_URI_PREFIX) == 0) {
246 dataShareHelper = DataShare::DataShareHelper::Creator(CLOUD_SYNC_PROXY_URI, options);
247 if (dataShareHelper == nullptr || cloudSyncObserver == nullptr) {
248 MEDIA_ERR_LOG("dataShareHelper is nullptr");
249 return;
250 }
251 dataShareHelper->RegisterObserver(notifyUri, cloudSyncObserver);
252 }
253 }
254
UnregisterObserver(const std::string & formId)255 void MediaLibraryFaCardOperations::UnregisterObserver(const std::string &formId)
256 {
257 if (formId.empty() || formAssetObserversMap.empty()) {
258 MEDIA_ERR_LOG("parameter is null");
259 return;
260 }
261 CreateOptions options;
262 options.enabled_ = true;
263 shared_ptr<DataShare::DataShareHelper> dataShareHelper;
264 dataShareHelper = DataShare::DataShareHelper::Creator(MEDIA_LIBRARY_PROXY_URI, options);
265 if (dataShareHelper == nullptr) {
266 MEDIA_ERR_LOG("dataShareHelper is nullptr");
267 return;
268 }
269 auto itAsset = formAssetObserversMap.find(formId);
270 if (itAsset == formAssetObserversMap.end()) {
271 MEDIA_ERR_LOG("No formAssetObservers found for formId: %{public}s", formId.c_str());
272 return;
273 }
274 const std::vector<std::shared_ptr<CardAssetUriObserver>>& formAssetObservers = itAsset->second;
275 if (formAssetObservers.empty()) {
276 MEDIA_ERR_LOG("formAssetObservers is null");
277 return;
278 }
279 for (const auto& observer : formAssetObservers) {
280 if (!observer || observer->assetChangeUri.empty()) {
281 MEDIA_ERR_LOG("observer->assetChangeUri is null");
282 return;
283 }
284 Uri notifyUri(observer->assetChangeUri);
285 dataShareHelper->UnregisterObserverExt(notifyUri,
286 std::static_pointer_cast<DataShare::DataShareObserver>(observer));
287 }
288 formAssetObserversMap.erase(formId);
289 if (formCloudSyncObserversMap.empty()) {
290 MEDIA_ERR_LOG("formCloudSyncObserversMap is null");
291 return;
292 }
293 dataShareHelper = DataShare::DataShareHelper::Creator(CLOUD_SYNC_PROXY_URI, options);
294 if (dataShareHelper == nullptr) {
295 MEDIA_ERR_LOG("dataShareHelper is nullptr");
296 return;
297 }
298 auto cloudItAsset = formCloudSyncObserversMap.find(formId);
299 if (cloudItAsset == formCloudSyncObserversMap.end()) {
300 MEDIA_ERR_LOG("No formCloudSyncObserversMap found for formId: %{public}s", formId.c_str());
301 return;
302 }
303 const std::vector<sptr<FaCloudSyncSwitchObserver>>& formCloudSyncObservers = cloudItAsset->second;
304 if (formCloudSyncObservers.empty()) {
305 MEDIA_ERR_LOG("formCloudSyncObservers is null");
306 return;
307 }
308 for (const auto& observer : formCloudSyncObservers) {
309 if (!observer || observer->cloudSyncChangeUri.empty()) {
310 MEDIA_ERR_LOG("observer->cloudSyncChangeUri is null");
311 return;
312 }
313 Uri notifyUri(observer->cloudSyncChangeUri);
314 dataShareHelper->UnregisterObserver(notifyUri, observer);
315 }
316 formCloudSyncObserversMap.erase(formId);
317 }
318
HandleStoreGalleryFormOperation(MediaLibraryCommand & cmd)319 int32_t MediaLibraryFaCardOperations::HandleStoreGalleryFormOperation(MediaLibraryCommand &cmd)
320 {
321 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
322 if (rdbStore == nullptr) {
323 return E_HAS_DB_ERROR;
324 }
325 int64_t outRowId = -1;
326 lock_guard<mutex> lock(mutex_);
327 int32_t errCode = rdbStore->Insert(cmd, outRowId);
328 if (errCode != NativeRdb::E_OK || outRowId < 0) {
329 MEDIA_ERR_LOG("Insert into db failed, errCode = %{public}d", errCode);
330 return E_HAS_DB_ERROR;
331 }
332 string formId = GetStringObject(cmd, TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID);
333 MEDIA_DEBUG_LOG("formId = %{public}s", formId.c_str());
334 string assetRegisterUri = GetStringObject(cmd, TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI);
335 MEDIA_DEBUG_LOG("assetRegisterUri = %{public}s", assetRegisterUri.c_str());
336 MediaLibraryFaCardOperations::RegisterObserver(formId, assetRegisterUri);
337 return static_cast<int32_t>(outRowId);
338 }
339
HandleRemoveGalleryFormOperation(NativeRdb::RdbPredicates & rdbPredicate)340 int32_t MediaLibraryFaCardOperations::HandleRemoveGalleryFormOperation(NativeRdb::RdbPredicates &rdbPredicate)
341 {
342 lock_guard<mutex> lock(mutex_);
343 string formId = rdbPredicate.GetWhereArgs()[0];
344 MediaLibraryFaCardOperations::UnregisterObserver(formId);
345 return MediaLibraryRdbStore::Delete(rdbPredicate);
346 }
347
InitRegisterObserver()348 void MediaLibraryFaCardOperations::InitRegisterObserver()
349 {
350 MEDIA_INFO_LOG("enter InitRegisterObserver");
351 const int INIT_NUM = 0;
352 const int END_NUM = 10;
353 const int DELAY_NUM = 100;
354 int cnt = INIT_NUM;
355 std::map<std::string, std::vector<std::string>> urisMap = MediaLibraryFaCardOperations::GetUris();
356 for (const auto& pair : urisMap) {
357 const std::string& formId = pair.first;
358 MEDIA_DEBUG_LOG("InitRegisterObserver formId = %{public}s", formId.c_str());
359 const std::vector<std::string>& uris = pair.second;
360 MEDIA_DEBUG_LOG("InitRegisterObserver uris.size = %{public}zu", uris.size());
361 for (const std::string& uri : uris) {
362 MediaLibraryFaCardOperations::RegisterObserver(formId, uri);
363 MEDIA_DEBUG_LOG("InitRegisterObserver uri = %{public}s", uri.c_str());
364 cnt ++;
365 if (cnt == END_NUM) {
366 cnt = INIT_NUM;
367 std::this_thread::sleep_for(std::chrono::milliseconds(DELAY_NUM));
368 }
369 }
370 }
371 }
372
InitFaCard()373 void MediaLibraryFaCardOperations::InitFaCard()
374 {
375 ffrt::submit([]() { MediaLibraryFaCardOperations::InitRegisterObserver(); });
376 }
377 // LCOV_EXCL_STOP
378 } // namespace Media
379 } // namespace OHOS