/* * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "vcard_manager.h" #include "telephony_errors.h" #include "telephony_log_wrapper.h" #include "vcard_constant.h" #include "vcard_encoder.h" #include "vcard_file_utils.h" #include "vcard_rdb_helper.h" #include "vcard_utils.h" namespace OHOS { namespace Telephony { VCardManager::VCardManager() { listener_ = std::make_shared(); } std::vector> &VCardManager::DecodeListener::GetContacts() { return contacts_; } void VCardManager::DecodeListener::OnStarted() { contacts_.clear(); } void VCardManager::DecodeListener::OnEnded() { TELEPHONY_LOGI("OnEnded contact size %{public}d", static_cast(contacts_.size())); VCardDecoder::Close(); } void VCardManager::DecodeListener::OnOneContactStarted() { currentContact_ = std::make_shared(); } void VCardManager::DecodeListener::OnOneContactEnded() { TELEPHONY_LOGI("OnOneContactEnded index %{public}d", static_cast(contacts_.size())); contacts_.push_back(currentContact_); currentContact_ = nullptr; } void VCardManager::DecodeListener::OnRawDataCreated(std::shared_ptr rawData) { if (rawData == nullptr || currentContact_ == nullptr) { return; } int32_t errorCode = TELEPHONY_SUCCESS; currentContact_->AddRawData(rawData, errorCode); } int32_t VCardManager::ImportLock( const std::string &path, std::shared_ptr dataShareHelper, int32_t accountId) { std::lock_guard lock(mutex_); if (dataShareHelper == nullptr) { TELEPHONY_LOGE("DataShareHelper is nullptr"); return TELEPHONY_ERR_LOCAL_PTR_NULL; } SetDataHelper(dataShareHelper); int32_t errorCode = Import(path, accountId); Release(); TELEPHONY_LOGI("ImportLock errorCode : %{public}d finish", errorCode); return errorCode; } int32_t VCardManager::Import(const std::string &path, int32_t accountId) { int32_t errorCode = TELEPHONY_SUCCESS; Decode(path, errorCode); if (errorCode != TELEPHONY_SUCCESS) { TELEPHONY_LOGE("Failed to decode"); return errorCode; } BatchInsertContactDbAbility(accountId, errorCode); if (errorCode != TELEPHONY_SUCCESS) { TELEPHONY_LOGE("Failed to insert ability"); return errorCode; } TELEPHONY_LOGI("Import size %{public}d success", static_cast(listener_->GetContacts().size())); return errorCode; } void VCardManager::Decode(const std::string &path, int32_t &errorCode) { std::shared_ptr decoder = VCardDecoder::Create(path, errorCode); if (decoder == nullptr || errorCode != TELEPHONY_SUCCESS) { TELEPHONY_LOGE("Failed to get decoder"); return; } decoder->AddVCardDecodeListener(listener_); decoder->Decode(errorCode); if (errorCode != TELEPHONY_SUCCESS) { TELEPHONY_LOGE("Failed to decode"); } } void VCardManager::InsertContactDbAbility(int32_t accountId, int32_t &errorCode) { if (listener_ == nullptr) { errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL; return; } if (listener_->GetContacts().size() == 0) { errorCode = TELEPHONY_ERR_VCARD_FILE_INVALID; return; } for (std::shared_ptr contact : listener_->GetContacts()) { auto rawId = InsertRawContact(accountId, contact); if (rawId <= 0) { TELEPHONY_LOGE("Failed to insert raw contact"); errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL; continue; } if (InsertContactData(rawId, contact) == TELEPHONY_ERROR) { TELEPHONY_LOGE("Insert contactData failed"); errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL; } } } void VCardManager::BatchInsertContactDbAbility(int32_t accountId, int32_t &errorCode) { if (listener_ == nullptr) { errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL; return; } if (listener_->GetContacts().size() < BATCH_INSERT_MAX_SIZE) { TELEPHONY_LOGI("contactData < BATCH_INSERT_MAX_SIZE"); InsertContactDbAbility(accountId, errorCode); return; } if (listener_->GetContacts().size() == 0) { errorCode = TELEPHONY_ERR_VCARD_FILE_INVALID; return; } std::vector>> splitList = SplitContactsVector(listener_->GetContacts(), BATCH_INSERT_MAX_SIZE); TELEPHONY_LOGI( "contactData > BATCH_INSERT_MAX_SIZE, split List size %{public}d", static_cast(splitList.size())); for (std::vector> list : splitList) { TELEPHONY_LOGI("List size %{public}d", static_cast(list.size())); std::vector rawIds; BatchInsertRawContact(accountId, list.size(), rawIds, errorCode, list); if (errorCode == TELEPHONY_ERROR) { TELEPHONY_LOGE("Failed to batch insert raw contact"); continue; } BatchInsertContactData(rawIds, list, errorCode); if (errorCode == TELEPHONY_ERROR) { TELEPHONY_LOGE("Failed to batch insert contactData"); continue; } } } void VCardManager::BatchInsertRawContact( int32_t accountId, uint32_t size, std::vector &rawIds, int32_t &errorCode, const std::vector> &contactList) { int32_t rawContactMaxId = VCardRdbHelper::GetInstance().QueryRawContactMaxId(static_cast(size)); std::vector rawContactValues; for (uint32_t i = 0; i < size; i++) { OHOS::DataShare::DataShareValuesBucket valuesBucket; auto contact = contactList[i]; contact->BuildRawContactDataDisplayName(valuesBucket); std::string uid = contact->GetUid(); if (!uid.empty()) { valuesBucket.Put(RawContact::UUID, uid); } valuesBucket.Put(RawContact::ACCOUNT_ID, accountId); int32_t newRawId = rawContactMaxId + static_cast(i) + 1; valuesBucket.Put(RawContact::ID, newRawId); rawContactValues.push_back(valuesBucket); rawIds.push_back(newRawId); } VCardRdbHelper::GetInstance().BatchInsertRawContact(rawContactValues); } void VCardManager::BatchInsertContactData( std::vector &rawIds, const std::vector> &contactList, int32_t &errorCode) { std::vector contactDataValues; for (size_t i = 0; i < rawIds.size(); i++) { int32_t rawId = rawIds[i]; TELEPHONY_LOGI("rawId %{public}d", rawId); std::shared_ptr contact = contactList[i]; if (contact == nullptr) { errorCode = TELEPHONY_ERROR; TELEPHONY_LOGE("contact is nullptr"); continue; } contact->BuildContactData(rawId, contactDataValues); if (contactDataValues.empty()) { TELEPHONY_LOGE("no contactData insert"); errorCode = TELEPHONY_ERROR; } } int ret = VCardRdbHelper::GetInstance().BatchInsertContactData(contactDataValues); if (ret == TELEPHONY_ERROR) { TELEPHONY_LOGE("batch insert contactDatat failed"); errorCode = TELEPHONY_ERROR; } } std::vector>> VCardManager::SplitContactsVector( std::vector> list, size_t step) { std::vector>> result; if (step >= list.size()) { result.push_back(list); } else { std::vector>::iterator curPtr = list.begin(); std::vector>::iterator endPtr = list.end(); std::vector>::iterator end; while (curPtr < endPtr) { end = static_cast(endPtr - curPtr) > step ? (step + curPtr) : endPtr; step = static_cast(endPtr - curPtr) > step ? step : static_cast(endPtr - curPtr); result.push_back(std::vector>(curPtr, end)); curPtr += step; } } return result; } int32_t VCardManager::InsertRawContact(int32_t accountId, std::shared_ptr contact) { OHOS::DataShare::DataShareValuesBucket valuesBucket; valuesBucket.Put(RawContact::ACCOUNT_ID, accountId); contact->BuildRawContactDataDisplayName(valuesBucket); std::string uid = contact->GetUid(); if (!uid.empty()) { valuesBucket.Put(RawContact::UUID, uid); } return VCardRdbHelper::GetInstance().InsertRawContact(valuesBucket); } bool VCardManager::IsContactsIdExit(int32_t accountId) { std::vector columns; OHOS::DataShare::DataSharePredicates predicates; predicates.EqualTo(Contact::ID, std::to_string(accountId)); auto resultSet = VCardRdbHelper::GetInstance().QueryContact(columns, predicates); if (resultSet == nullptr) { return false; } bool result = (resultSet->GoToFirstRow() == DataShare::E_OK); resultSet->Close(); return result; } bool VCardManager::IsAccountIdExit(int32_t accountId) { std::vector columns; OHOS::DataShare::DataSharePredicates predicates; predicates.EqualTo(Account::ID, std::to_string(accountId)); auto resultSet = VCardRdbHelper::GetInstance().QueryAccount(columns, predicates); if (resultSet == nullptr) { return false; } bool result = (resultSet->GoToFirstRow() == DataShare::E_OK); resultSet->Close(); return result; } int32_t VCardManager::InsertContactData(int32_t rawId, std::shared_ptr contact) { if (contact == nullptr) { return TELEPHONY_ERROR; } std::vector contactDataValues; contact->BuildContactData(rawId, contactDataValues); if (contactDataValues.empty()) { TELEPHONY_LOGI("no data insert"); return TELEPHONY_ERROR; } int ret = VCardRdbHelper::GetInstance().InsertContactData(contactDataValues); if (ret == TELEPHONY_ERROR) { TELEPHONY_LOGE("insert failed"); return TELEPHONY_ERROR; } return TELEPHONY_SUCCESS; } bool VCardManager::ParameterTypeAndCharsetCheck(int32_t cardType, std::string charset, int32_t &errorCode) { if (cardType < VERSION_21_NUM || cardType > VERSION_40_NUM) { errorCode = TELEPHONY_ERR_ARGUMENT_INVALID; return false; } if (!charset.empty() && !VCardUtils::EqualsIgnoreCase(DEFAULT_CHARSET, charset)) { errorCode = TELEPHONY_ERR_ARGUMENT_INVALID; return false; } errorCode = TELEPHONY_SUCCESS; return true; } int32_t VCardManager::ExportLock(std::string &path, std::shared_ptr dataShareHelper, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset) { std::lock_guard lock(mutex_); if (dataShareHelper == nullptr) { TELEPHONY_LOGE("DataShareHelper is nullptr"); return TELEPHONY_ERR_LOCAL_PTR_NULL; } SetDataHelper(dataShareHelper); int32_t errorCode = Export(path, predicates, cardType, charset); Release(); TELEPHONY_LOGI("ExportLock errorCode : %{public}d finish", errorCode); return errorCode; } int32_t VCardManager::Export( std::string &path, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset) { int32_t errorCode = TELEPHONY_SUCCESS; if (!ParameterTypeAndCharsetCheck(cardType, charset, errorCode)) { return errorCode; } std::vector columns; auto resultSet = VCardRdbHelper::GetInstance().QueryContact(columns, predicates); if (resultSet == nullptr) { TELEPHONY_LOGE("QueryContact failed"); return TELEPHONY_ERR_LOCAL_PTR_NULL; } std::string result = ""; result = ConstructVCardString(resultSet, cardType, charset, errorCode); if (errorCode != TELEPHONY_SUCCESS) { TELEPHONY_LOGE("Export data failed"); return errorCode; } if (path.empty()) { std::string fileName = VCardUtils::CreateFileName(); path = VCARD_EXPORT_FILE_PATH + fileName; } else { path = path + VCardUtils::CreateFileName(); } if (!result.empty()) { VCardUtils::SaveFile(result, path); } else { return TELEPHONY_ERROR; } return TELEPHONY_SUCCESS; } int32_t VCardManager::ExportToStr( std::string &str, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset) { std::vector columns; auto resultSet = VCardRdbHelper::GetInstance().QueryContact(columns, predicates); if (resultSet == nullptr) { TELEPHONY_LOGE("QueryContact failed"); return TELEPHONY_ERR_LOCAL_PTR_NULL; } int32_t errorCode = TELEPHONY_SUCCESS; str = ConstructVCardString(resultSet, cardType, charset, errorCode); if (errorCode != TELEPHONY_SUCCESS) { TELEPHONY_LOGE("Export data failed"); return errorCode; } return TELEPHONY_SUCCESS; } std::string VCardManager::ConstructVCardString( std::shared_ptr &resultSet, int32_t cardType, const std::string &charset, int32_t &errorCode) { int32_t resultSetNum = resultSet->GoToFirstRow(); if (resultSetNum != TELEPHONY_SUCCESS) { errorCode = resultSetNum; return ""; } std::string result = ""; VCardEncoder encoder { cardType, charset }; int32_t contactCount = 0; std::vector contactIdList; std::vector> contactIdLists; while (resultSetNum == 0) { int32_t index = 0; int32_t contactId = 0; resultSet->GetColumnIndex(Contact::ID, index); resultSet->GetInt(index, contactId); contactIdList.push_back(contactId); resultSetNum = resultSet->GoToNextRow(); contactCount++; if (contactCount % BATCH_INSERT_MAX_SIZE == 0) { TELEPHONY_LOGI("pushBack contactid : %{public}d", contactId); contactIdLists.push_back(contactIdList); contactIdList.clear(); } } contactIdLists.push_back(contactIdList); TELEPHONY_LOGI("before contstructVCard, contactIdList size : %{public}d", (int32_t)contactIdLists.size()); resultSet->Close(); result += encoder.ContructVCard(contactIdLists, errorCode); return result; } void VCardManager::SetDataHelper(std::shared_ptr dataShareHelper) { VCardRdbHelper::GetInstance().SetDataHelper(dataShareHelper); } VCardManager &VCardManager::GetInstance() { static VCardManager instance; return instance; } void VCardManager::Release() { VCardRdbHelper::GetInstance().Release(); if (listener_ != nullptr) { listener_->GetContacts().clear(); } } } // namespace Telephony } // namespace OHOS