1/*
2 * Copyright (c) 2024 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 "full_ime_info_manager.h"
17
18#include <algorithm>
19
20#include "common_timer_errors.h"
21#include "ime_info_inquirer.h"
22namespace OHOS {
23namespace MiscServices {
24constexpr uint32_t TIMER_TASK_INTERNAL = 3600000; // updated hourly
25FullImeInfoManager::~FullImeInfoManager()
26{
27    timer_.Unregister(timerId_);
28    timer_.Shutdown(false);
29    fullImeInfos_.clear();
30}
31
32FullImeInfoManager::FullImeInfoManager()
33{
34    uint32_t ret = timer_.Setup();
35    if (ret != Utils::TIMER_ERR_OK) {
36        IMSA_HILOGE("failed to create timer!");
37        return;
38    }
39    timerId_ = timer_.Register([this]() { Init(); }, TIMER_TASK_INTERNAL, false);
40}
41
42FullImeInfoManager &FullImeInfoManager::GetInstance()
43{
44    static FullImeInfoManager instance;
45    return instance;
46}
47
48int32_t FullImeInfoManager::Init()
49{
50    std::vector<std::pair<int32_t, std::vector<FullImeInfo>>> fullImeInfos;
51    auto ret = ImeInfoInquirer::GetInstance().QueryFullImeInfo(fullImeInfos);
52    if (ret != ErrorCode::NO_ERROR) {
53        IMSA_HILOGW("failed to QueryFullImeInfo, ret:%{public}d", ret);
54        return ret;
55    }
56    std::lock_guard<std::mutex> lock(lock_);
57    fullImeInfos_.clear();
58    for (const auto &infos : fullImeInfos) {
59        fullImeInfos_.insert_or_assign(infos.first, infos.second);
60    }
61    return ErrorCode::NO_ERROR;
62}
63
64int32_t FullImeInfoManager::Add(int32_t userId)
65{
66    {
67        std::lock_guard<std::mutex> lock(lock_);
68        auto it = fullImeInfos_.find(userId);
69        if (it != fullImeInfos_.end()) {
70            return ErrorCode::NO_ERROR;
71        }
72    }
73    std::vector<FullImeInfo> infos;
74    auto ret = ImeInfoInquirer::GetInstance().QueryFullImeInfo(userId, infos);
75    if (ret != ErrorCode::NO_ERROR) {
76        IMSA_HILOGE("failed to QueryFullImeInfo, userId:%{public}d, ret:%{public}d", userId, ret);
77        return ret;
78    }
79    std::lock_guard<std::mutex> lock(lock_);
80    fullImeInfos_.insert_or_assign(userId, infos);
81    return ErrorCode::NO_ERROR;
82}
83
84int32_t FullImeInfoManager::Update()
85{
86    auto ret = Init();
87    if (ret != ErrorCode::NO_ERROR) {
88        std::lock_guard<std::mutex> lock(lock_);
89        fullImeInfos_.clear();
90    }
91    return ErrorCode::NO_ERROR;
92}
93
94int32_t FullImeInfoManager::Delete(int32_t userId)
95{
96    std::lock_guard<std::mutex> lock(lock_);
97    fullImeInfos_.erase(userId);
98    return ErrorCode::NO_ERROR;
99}
100
101int32_t FullImeInfoManager::Add(int32_t userId, const std::string &bundleName)
102{
103    FullImeInfo info;
104    auto ret = ImeInfoInquirer::GetInstance().GetFullImeInfo(userId, bundleName, info);
105    if (ret != ErrorCode::NO_ERROR) {
106        IMSA_HILOGE("failed to GetFullImeInfo, userId:%{public}d, bundleName:%{public}s, ret:%{public}d", userId,
107            bundleName.c_str(), ret);
108        return ret;
109    }
110    std::lock_guard<std::mutex> lock(lock_);
111    auto it = fullImeInfos_.find(userId);
112    if (it == fullImeInfos_.end()) {
113        fullImeInfos_.insert({ userId, { info } });
114        return ErrorCode::NO_ERROR;
115    }
116    auto iter = std::find_if(it->second.begin(), it->second.end(),
117        [&bundleName](const FullImeInfo &info) { return bundleName == info.prop.name; });
118    if (iter != it->second.end()) {
119        return ErrorCode::NO_ERROR;
120    }
121    it->second.push_back(info);
122    return ErrorCode::NO_ERROR;
123}
124
125int32_t FullImeInfoManager::Delete(int32_t userId, const std::string &bundleName)
126{
127    std::lock_guard<std::mutex> lock(lock_);
128    auto it = fullImeInfos_.find(userId);
129    if (it == fullImeInfos_.end()) {
130        return ErrorCode::NO_ERROR;
131    }
132    auto iter = std::find_if(it->second.begin(), it->second.end(),
133        [&bundleName](const FullImeInfo &info) { return bundleName == info.prop.name; });
134    if (iter == it->second.end()) {
135        return ErrorCode::NO_ERROR;
136    }
137    it->second.erase(iter);
138    if (it->second.empty()) {
139        fullImeInfos_.erase(it->first);
140    }
141    return ErrorCode::NO_ERROR;
142}
143
144int32_t FullImeInfoManager::Update(int32_t userId, const std::string &bundleName)
145{
146    FullImeInfo info;
147    auto ret = ImeInfoInquirer::GetInstance().GetFullImeInfo(userId, bundleName, info);
148    if (ret != ErrorCode::NO_ERROR) {
149        IMSA_HILOGE("failed to GetFullImeInfo failed, userId:%{public}d, bundleName:%{public}s, ret:%{public}d",
150            userId, bundleName.c_str(), ret);
151        return ErrorCode::ERROR_PACKAGE_MANAGER;
152    }
153    std::lock_guard<std::mutex> lock(lock_);
154    auto it = fullImeInfos_.find(userId);
155    if (it == fullImeInfos_.end()) {
156        fullImeInfos_.insert({ userId, { info } });
157        return ErrorCode::NO_ERROR;
158    }
159    auto iter = std::find_if(it->second.begin(), it->second.end(),
160        [&bundleName](const FullImeInfo &info) { return bundleName == info.prop.name; });
161    if (iter != it->second.end()) {
162        it->second.erase(iter);
163    }
164    it->second.push_back(info);
165    return ErrorCode::NO_ERROR;
166}
167
168std::vector<FullImeInfo> FullImeInfoManager::Get(int32_t userId)
169{
170    std::lock_guard<std::mutex> lock(lock_);
171    auto it = fullImeInfos_.find(userId);
172    if (it == fullImeInfos_.end()) {
173        return {};
174    }
175    return it->second;
176}
177
178bool FullImeInfoManager::Get(const std::string &bundleName, int32_t userId, FullImeInfo &fullImeInfo)
179{
180    std::lock_guard<std::mutex> lock(lock_);
181    auto it = fullImeInfos_.find(userId);
182    if (it == fullImeInfos_.end()) {
183        IMSA_HILOGD("user %{public}d info", userId);
184        return false;
185    }
186    auto iter = std::find_if(it->second.begin(), it->second.end(),
187        [&bundleName](const FullImeInfo &info) { return bundleName == info.prop.name; });
188    if (iter == it->second.end()) {
189        IMSA_HILOGD("ime: %{public}s not in cache", bundleName.c_str());
190        return false;
191    }
192    fullImeInfo = *iter;
193    return true;
194}
195
196bool FullImeInfoManager::Has(int32_t userId, const std::string &bundleName)
197{
198    std::lock_guard<std::mutex> lock(lock_);
199    auto it = fullImeInfos_.find(userId);
200    if (it == fullImeInfos_.end()) {
201        return false;
202    }
203    auto iter = std::find_if(it->second.begin(), it->second.end(),
204        [&bundleName](const FullImeInfo &info) { return bundleName == info.prop.name; });
205    return iter != it->second.end();
206}
207
208std::string FullImeInfoManager::Get(int32_t userId, uint32_t tokenId)
209{
210    std::lock_guard<std::mutex> lock(lock_);
211    auto it = fullImeInfos_.find(userId);
212    if (it == fullImeInfos_.end()) {
213        return "";
214    }
215    auto iter = std::find_if(
216        it->second.begin(), it->second.end(), [&tokenId](const FullImeInfo &info) { return tokenId == info.tokenId; });
217    if (iter == it->second.end()) {
218        return "";
219    }
220    return (*iter).prop.name;
221}
222} // namespace MiscServices
223} // namespace OHOS