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 "poi_info_manager.h"
17
18 #include "location_log.h"
19 #include "common_utils.h"
20 #ifdef MOVEMENT_CLIENT_ENABLE
21 #include "locator_msdp_monitor_manager.h"
22 #endif
23
24 namespace OHOS {
25 namespace Location {
26
27 static constexpr int STILL_POI_EXPIRED_TIME = 30 * 60 * 1000; // Unit ms
28 static constexpr int POI_EXPIRED_TIME = 25 * 1000; // Unit ms
29 static constexpr int MAX_UTC_TIME_SIZE = 16;
30 static constexpr int MAX_POI_ARRAY_SIZE = 20;
31
GetInstance()32 PoiInfoManager* PoiInfoManager::GetInstance()
33 {
34 static PoiInfoManager data;
35 return &data;
36 }
37
PoiInfoManager()38 PoiInfoManager::PoiInfoManager() {}
39
~PoiInfoManager()40 PoiInfoManager::~PoiInfoManager() {}
41
UpdateCachedPoiInfo(const std::unique_ptr<Location> & location)42 void PoiInfoManager::UpdateCachedPoiInfo(const std::unique_ptr<Location>& location)
43 {
44 std::map<std::string, std::string> additionMap = location->GetAdditionsMap();
45 if (additionMap["poiInfos"] != "") {
46 std::string poiInfos = std::string("poiInfos:") + additionMap["poiInfos"];
47 uint64_t poiInfoTime = GetPoiInfoTime(poiInfos);
48 SetLatestPoiInfo(poiInfos);
49 SetLatestPoiInfoTime(poiInfoTime);
50 }
51 }
52
ClearPoiInfos(const std::unique_ptr<Location> & finalLocation)53 void PoiInfoManager::ClearPoiInfos(const std::unique_ptr<Location>& finalLocation)
54 {
55 std::vector<std::string> additions;
56 for (auto& str : finalLocation->GetAdditions()) {
57 if (str.find("poiInfos") != std::string::npos) {
58 continue;
59 }
60 additions.push_back(str);
61 }
62 finalLocation->SetAdditions(additions, false);
63 finalLocation->SetAdditionSize(finalLocation->GetAdditions().size());
64 return;
65 }
66
UpdateLocationPoiInfo(const std::unique_ptr<Location> & finalLocation)67 void PoiInfoManager::UpdateLocationPoiInfo(const std::unique_ptr<Location>& finalLocation)
68 {
69 std::map<std::string, std::string> additionMap = finalLocation->GetAdditionsMap();
70 std::string poiInfos = additionMap["poiInfos"];
71 uint64_t poiInfoTime = GetPoiInfoTime(poiInfos);
72 if (poiInfos != "") {
73 if (IsPoiInfoValid(poiInfos, poiInfoTime)) {
74 PoiInfo poiInfo = ParsePoiInfoFromStr(poiInfos);
75 finalLocation->SetPoiInfo(poiInfo);
76 return;
77 } else {
78 LBSLOGI(REPORT_MANAGER, "PoiInfos Expied");
79 ClearPoiInfos(finalLocation);
80 }
81 }
82 std::string latestPoiInfos = GetLatestPoiInfo();
83 uint64_t latestPoiInfoTime = GetLatestPoiInfoTime();
84 if (!IsPoiInfoValid(latestPoiInfos, latestPoiInfoTime)) {
85 std::unique_lock<std::mutex> lock(latestPoiInfoMutex_);
86 latestPoiInfoStruct_ = {0};
87 return;
88 }
89 AddCachedPoiInfoToLocation(finalLocation);
90 }
91
AddCachedPoiInfoToLocation(const std::unique_ptr<Location> & finalLocation)92 void PoiInfoManager::AddCachedPoiInfoToLocation(const std::unique_ptr<Location>& finalLocation)
93 {
94 LBSLOGI(REPORT_MANAGER, "Add Latest PoiInfos");
95 std::string poiInfos = GetLatestPoiInfo();
96 std::vector<std::string> addition = finalLocation->GetAdditions();
97 addition.push_back(poiInfos);
98 finalLocation->SetAdditions(addition, false);
99 finalLocation->SetAdditionSize(finalLocation->GetAdditions().size());
100 std::string poiKey = "poiInfos:";
101 std::size_t pos = poiInfos.find(poiKey);
102 if (pos != std::string::npos) {
103 std::string result = poiInfos.substr(pos + poiKey.size());
104 PoiInfo poiInfo = ParsePoiInfoFromStr(result);
105 finalLocation->SetPoiInfo(poiInfo);
106 } else {
107 LBSLOGE(REPORT_MANAGER, "Not Found poiInfos");
108 }
109 }
110
IsPoiInfoValid(std::string poiInfos,uint64_t poiInfoTime)111 bool PoiInfoManager::IsPoiInfoValid(std::string poiInfos, uint64_t poiInfoTime)
112 {
113 uint64_t curTimeStamp = CommonUtils::GetCurrentTimeMilSec();
114 uint64_t enterStillTime = 0;
115 bool isInStillState = false;
116 #ifdef MOVEMENT_CLIENT_ENABLE
117 isInStillState = LocatorMsdpMonitorManager::GetInstance()->GetStillMovementState();
118 enterStillTime = LocatorMsdpMonitorManager::GetInstance()->GetEnterStillTime();
119 #endif
120 if (isInStillState && poiInfoTime > enterStillTime && curTimeStamp - poiInfoTime < STILL_POI_EXPIRED_TIME) {
121 return true;
122 }
123 if (curTimeStamp - poiInfoTime < POI_EXPIRED_TIME) {
124 return true;
125 }
126 return false;
127 }
128
GetLatestPoiInfo()129 std::string PoiInfoManager::GetLatestPoiInfo()
130 {
131 std::unique_lock<std::mutex> lock(latestPoiInfoMutex_);
132 return latestPoiInfoStruct_.latestPoiInfos;
133 }
134
SetLatestPoiInfo(std::string poiInfo)135 void PoiInfoManager::SetLatestPoiInfo(std::string poiInfo)
136 {
137 std::unique_lock<std::mutex> lock(latestPoiInfoMutex_);
138 latestPoiInfoStruct_.latestPoiInfos = poiInfo;
139 }
140
GetLatestPoiInfoTime()141 uint64_t PoiInfoManager::GetLatestPoiInfoTime()
142 {
143 std::unique_lock<std::mutex> lock(latestPoiInfoMutex_);
144 return latestPoiInfoStruct_.poiInfosTime;
145 }
146
SetLatestPoiInfoTime(uint64_t poiInfoTime)147 void PoiInfoManager::SetLatestPoiInfoTime(uint64_t poiInfoTime)
148 {
149 std::unique_lock<std::mutex> lock(latestPoiInfoMutex_);
150 latestPoiInfoStruct_.poiInfosTime = poiInfoTime;
151 }
152
GetPoiInfoTime(const std::string & poiInfos)153 uint64_t PoiInfoManager::GetPoiInfoTime(const std::string& poiInfos)
154 {
155 std::string key = "\"time\":";
156 size_t pos = poiInfos.find(key);
157 if (pos != std::string::npos) {
158 pos += key.length();
159 std::string number;
160 for (; pos < poiInfos.length() && isdigit(poiInfos[pos]); ++pos) {
161 number += poiInfos[pos];
162 }
163 if (CommonUtils::IsValidForStoull(number, MAX_UTC_TIME_SIZE)) {
164 return std::stoull(number);
165 }
166 }
167 return 0;
168 }
169
ParsePoiInfo(cJSON * poiJson)170 Poi PoiInfoManager::ParsePoiInfo(cJSON* poiJson)
171 {
172 Poi poi;
173 cJSON *item = cJSON_GetObjectItem(poiJson, "id");
174 poi.id = (item && cJSON_IsString(item)) ? item->valuestring : "";
175 item = cJSON_GetObjectItem(poiJson, "confidence");
176 poi.confidence = (item && cJSON_IsNumber(item)) ? item->valuedouble : 0.0;
177 item = cJSON_GetObjectItem(poiJson, "name");
178 poi.name = (item && cJSON_IsString(item)) ? item->valuestring : "";
179 item = cJSON_GetObjectItem(poiJson, "lat");
180 poi.latitude = (item && cJSON_IsNumber(item)) ? item->valuedouble : 0.0;
181 item = cJSON_GetObjectItem(poiJson, "lon");
182 poi.longitude = (item && cJSON_IsNumber(item)) ? item->valuedouble : 0.0;
183 item = cJSON_GetObjectItem(poiJson, "administrativeArea");
184 poi.administrativeArea = (item && cJSON_IsString(item)) ? item->valuestring : "";
185 item = cJSON_GetObjectItem(poiJson, "subAdministrativeArea");
186 poi.subAdministrativeArea = (item && cJSON_IsString(item)) ? item->valuestring : "";
187 item = cJSON_GetObjectItem(poiJson, "locality");
188 poi.locality = (item && cJSON_IsString(item)) ? item->valuestring : "";
189 item = cJSON_GetObjectItem(poiJson, "subLocality");
190 poi.subLocality = (item && cJSON_IsString(item)) ? item->valuestring : "";
191 item = cJSON_GetObjectItem(poiJson, "address");
192 poi.address = (item && cJSON_IsString(item)) ? item->valuestring : "";
193 return poi;
194 }
195
ParsePoiInfoFromStr(const std::string & jsonString)196 PoiInfo PoiInfoManager::ParsePoiInfoFromStr(const std::string& jsonString)
197 {
198 PoiInfo poiInfo;
199 cJSON* cJsonObj = cJSON_Parse(jsonString.c_str());
200 if (!cJsonObj) {
201 LBSLOGI(REPORT_MANAGER, "Poi cJson Parse Failed");
202 return poiInfo;
203 }
204 cJSON* item = cJSON_GetObjectItem(cJsonObj, "time");
205 poiInfo.timestamp = (item && cJSON_IsNumber(item)) ? static_cast<uint64_t>(item->valuedouble) : 0;
206 cJSON* poisArray = cJSON_GetObjectItem(cJsonObj, "pois");
207 if (poisArray && cJSON_IsArray(poisArray)) {
208 int arraySize = cJSON_GetArraySize(poisArray);
209 if (arraySize > MAX_POI_ARRAY_SIZE) {
210 arraySize = MAX_POI_ARRAY_SIZE;
211 }
212 for (int i = 0; i < arraySize; ++i) {
213 cJSON* poiJson = cJSON_GetArrayItem(poisArray, i);
214 if (poiJson) {
215 poiInfo.poiArray.push_back(ParsePoiInfo(poiJson));
216 }
217 }
218 }
219 cJSON_Delete(cJsonObj);
220 return poiInfo;
221 }
222
223 } // namespace OHOS
224 } // namespace Location