1 /*
2 * Copyright (c) 2022 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 #include "input_display_bind_helper.h"
16
17 #include <fstream>
18 #include <iostream>
19 #include <list>
20 #include <sstream>
21
22 #include "mmi_log.h"
23 #include "util.h"
24
25 namespace OHOS {
26 namespace MMI {
27 namespace {
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "InputDisplayBindHelper" };
29 }
30 class BindInfo {
31 public:
GetInputDeviceId() const32 int32_t GetInputDeviceId() const
33 {
34 return inputDeviceId_;
35 }
GetInputDeviceName() const36 std::string GetInputDeviceName() const
37 {
38 return inputDeviceName_;
39 }
GetDisplayId() const40 int32_t GetDisplayId() const
41 {
42 return displayId_;
43 }
GetDisplayName() const44 std::string GetDisplayName() const
45 {
46 return displayName_;
47 }
IsUnbind() const48 bool IsUnbind() const
49 {
50 return ((inputDeviceId_ == -1) || (displayId_ == -1));
51 }
InputDeviceNotBind() const52 bool InputDeviceNotBind() const
53 {
54 return (inputDeviceId_ == -1);
55 }
DisplayNotBind() const56 bool DisplayNotBind() const
57 {
58 return (displayId_ == -1);
59 }
60 bool AddInputDevice(int32_t deviceId, const std::string &deviceName);
61 void RemoveInputDevice();
62 bool AddDisplay(int32_t id, const std::string &name);
63 void RemoveDisplay();
64 std::string GetDesc() const;
65 friend bool operator < (const BindInfo &l, const BindInfo &r);
66 friend std::ostream &operator << (std::ostream &os, const BindInfo &r);
67 friend std::istream &operator >> (std::istream &is, BindInfo &r);
68
69 private:
70 int32_t inputDeviceId_{ -1 };
71 std::string inputDeviceName_;
72 int32_t displayId_{ -1 };
73 std::string displayName_;
74 };
75
76 class BindInfos {
77 public:
78 bool Add(const BindInfo &info);
79 void UnbindInputDevice(int32_t deviceId);
80 void UnbindDisplay(int32_t displayId);
81 BindInfo GetUnbindInputDevice(const std::string &displayName);
82 BindInfo GetUnbindDisplay(const std::string &inputDeviceName);
83 std::string GetDisplayNameByInputDevice(const std::string &name) const;
84 int32_t GetBindDisplayIdByInputDevice(int32_t inputDeviceId) const;
85 std::string GetBindDisplayNameByInputDevice(int32_t inputDeviceId) const;
86 std::string GetInputDeviceByDisplayName(const std::string &name) const;
87 std::string GetDesc() const;
GetInfos() const88 const std::list<BindInfo> &GetInfos() const
89 {
90 return infos_;
91 }
92 friend std::ostream &operator << (std::ostream &os, const BindInfos &r);
93 friend std::istream &operator >> (std::istream &is, BindInfos &r);
94
95 private:
96 BindInfo GetUnbindInputDevice();
97 BindInfo GetUnbindInfo();
98 BindInfo GetUnbindDisplay();
99 std::list<BindInfo> infos_;
100 };
101
AddInputDevice(int32_t deviceId,const std::string & deviceName)102 bool BindInfo::AddInputDevice(int32_t deviceId, const std::string &deviceName)
103 {
104 if ((inputDeviceId_ != -1) || !inputDeviceName_.empty()) {
105 return false;
106 }
107 inputDeviceId_ = deviceId;
108 inputDeviceName_ = deviceName;
109 return true;
110 }
111
RemoveInputDevice()112 void BindInfo::RemoveInputDevice()
113 {
114 inputDeviceId_ = -1;
115 inputDeviceName_.clear();
116 }
AddDisplay(int32_t id,const std::string & name)117 bool BindInfo::AddDisplay(int32_t id, const std::string &name)
118 {
119 if ((displayId_ != -1) || !displayName_.empty()) {
120 return false;
121 }
122 displayId_ = id;
123 displayName_ = name;
124 return true;
125 }
RemoveDisplay()126 void BindInfo::RemoveDisplay()
127 {
128 displayId_ = -1;
129 displayName_.clear();
130 }
GetDesc() const131 std::string BindInfo::GetDesc() const
132 {
133 std::ostringstream oss;
134 oss << "InputDevice(id:" << inputDeviceId_ << ",name:" << inputDeviceName_ << "),Display(id:" << displayId_ <<
135 ",name:" << displayName_ << ")";
136 return oss.str();
137 }
138
operator <(const BindInfo & l,const BindInfo & r)139 bool operator < (const BindInfo &l, const BindInfo &r)
140 {
141 if (l.inputDeviceId_ != r.inputDeviceId_) {
142 return (l.inputDeviceId_ < r.inputDeviceId_);
143 }
144 return (l.displayId_ < r.displayId_);
145 }
146
operator <<(std::ostream & os,const BindInfo & r)147 std::ostream &operator << (std::ostream &os, const BindInfo &r)
148 {
149 os << r.inputDeviceName_ << "<=>" << r.displayName_ << std::endl;
150 return os;
151 }
152
operator >>(std::istream & is,BindInfo & r)153 std::istream &operator >> (std::istream &is, BindInfo &r)
154 {
155 std::string line;
156 std::getline(is, line);
157 const std::string delim = "<=>";
158 std::string::size_type pos = line.find(delim);
159 if (pos == std::string::npos) {
160 return is;
161 }
162 r.inputDeviceName_ = line.substr(0, pos);
163 r.displayName_ = line.substr(pos + delim.length());
164 r.inputDeviceId_ = 0;
165 r.displayId_ = 0;
166 return is;
167 }
168
GetDesc() const169 std::string BindInfos::GetDesc() const
170 {
171 int32_t index = 0;
172 std::ostringstream oss;
173 for (const auto &info : infos_) {
174 oss << "index:" << index << "," << info.GetDesc() << std::endl;
175 }
176 return oss.str();
177 }
178
GetBindDisplayIdByInputDevice(int32_t inputDeviceId) const179 int32_t BindInfos::GetBindDisplayIdByInputDevice(int32_t inputDeviceId) const
180 {
181 for (const auto &item : infos_) {
182 if (item.GetInputDeviceId() == inputDeviceId) {
183 if (!item.IsUnbind()) {
184 return item.GetDisplayId();
185 }
186 }
187 }
188 return -1;
189 }
190
GetBindDisplayNameByInputDevice(int32_t inputDeviceId) const191 std::string BindInfos::GetBindDisplayNameByInputDevice(int32_t inputDeviceId) const
192 {
193 for (const auto &item : infos_) {
194 if (item.GetInputDeviceId() == inputDeviceId) {
195 if (!item.IsUnbind()) {
196 return item.GetDisplayName();
197 }
198 }
199 }
200 return "";
201 }
202
GetDisplayNameByInputDevice(const std::string & name) const203 std::string BindInfos::GetDisplayNameByInputDevice(const std::string &name) const
204 {
205 for (const auto &item : infos_) {
206 if (item.GetInputDeviceName() == name) {
207 return item.GetDisplayName();
208 }
209 }
210 return "";
211 }
212
GetInputDeviceByDisplayName(const std::string & name) const213 std::string BindInfos::GetInputDeviceByDisplayName(const std::string &name) const
214 {
215 for (const auto &item : infos_) {
216 if (item.GetDisplayName() == name) {
217 return item.GetInputDeviceName();
218 }
219 }
220 return "";
221 }
222
Add(const BindInfo & info)223 bool BindInfos::Add(const BindInfo &info)
224 {
225 auto it = infos_.begin();
226 for (; it != infos_.end(); ++it) {
227 if (info < *it) {
228 break;
229 }
230 }
231 auto it2 = infos_.emplace(it, std::move(info));
232 if (it2 == infos_.end()) {
233 MMI_HILOGE("Duplicate %{public}s", info.GetDesc().c_str());
234 }
235 return true;
236 }
237
UnbindInputDevice(int32_t deviceId)238 void BindInfos::UnbindInputDevice(int32_t deviceId)
239 {
240 auto it = infos_.begin();
241 for (; it != infos_.end(); ++it) {
242 if (it->GetInputDeviceId() == deviceId) {
243 it->RemoveInputDevice();
244 if (it->IsUnbind()) {
245 infos_.erase(it);
246 }
247 return;
248 }
249 }
250 }
251
UnbindDisplay(int32_t displayId)252 void BindInfos::UnbindDisplay(int32_t displayId)
253 {
254 auto it = infos_.begin();
255 for (; it != infos_.end(); ++it) {
256 if (it->GetDisplayId() == displayId) {
257 it->RemoveDisplay();
258 if (it->IsUnbind()) {
259 infos_.erase(it);
260 }
261 return;
262 }
263 }
264 }
265
GetUnbindInfo()266 BindInfo BindInfos::GetUnbindInfo()
267 {
268 auto it = infos_.begin();
269 while (it != infos_.end()) {
270 if (it->IsUnbind()) {
271 auto info = std::move(*it);
272 infos_.erase(it);
273 return info;
274 }
275 ++it;
276 }
277 return BindInfo();
278 }
279
GetUnbindInputDevice(const std::string & displayName)280 BindInfo BindInfos::GetUnbindInputDevice(const std::string &displayName)
281 {
282 auto it = infos_.begin();
283 while (it != infos_.end()) {
284 if (it->InputDeviceNotBind()) {
285 if (it->GetDisplayName() == displayName) {
286 auto info = std::move(*it);
287 infos_.erase(it);
288 return info;
289 }
290 }
291 ++it;
292 }
293 return BindInfo();
294 }
295
GetUnbindDisplay()296 BindInfo BindInfos::GetUnbindDisplay()
297 {
298 auto it = infos_.begin();
299 while (it != infos_.end()) {
300 if (it->DisplayNotBind()) {
301 auto info = std::move(*it);
302 infos_.erase(it);
303 return info;
304 }
305 ++it;
306 }
307 return BindInfo();
308 }
309
GetUnbindDisplay(const std::string & inputDeviceName)310 BindInfo BindInfos::GetUnbindDisplay(const std::string &inputDeviceName)
311 {
312 auto it = infos_.begin();
313 while (it != infos_.end()) {
314 if (it->DisplayNotBind()) {
315 if (it->GetInputDeviceName() == inputDeviceName) {
316 auto info = std::move(*it);
317 infos_.erase(it);
318 return info;
319 }
320 }
321 ++it;
322 }
323 return GetUnbindDisplay();
324 }
325
operator <<(std::ostream & os,const BindInfos & r)326 std::ostream &operator << (std::ostream &os, const BindInfos &r)
327 {
328 const auto &infos = r.GetInfos();
329 for (const auto &info : infos) {
330 if (!info.IsUnbind()) {
331 os << info;
332 }
333 }
334 return os;
335 }
336
operator >>(std::istream & is,BindInfos & r)337 std::istream &operator >> (std::istream &is, BindInfos &r)
338 {
339 while (!is.eof()) {
340 BindInfo info;
341 is >> info;
342 if (info.IsUnbind()) {
343 break;
344 }
345 r.Add(info);
346 }
347 return is;
348 }
349
InputDisplayBindHelper(const std::string bindCfgFile)350 InputDisplayBindHelper::InputDisplayBindHelper(const std::string bindCfgFile)
351 : fileName_(bindCfgFile), infos_(std::make_shared<BindInfos>()), configFileInfos_(std::make_shared<BindInfos>())
352 {}
353
GetBindDisplayNameByInputDevice(int32_t inputDeviceId) const354 std::string InputDisplayBindHelper::GetBindDisplayNameByInputDevice(int32_t inputDeviceId) const
355 {
356 CALL_DEBUG_ENTER;
357 if (infos_ == nullptr) {
358 return {};
359 }
360 return infos_->GetBindDisplayNameByInputDevice(inputDeviceId);
361 }
362
AddInputDevice(int32_t id,const std::string & name)363 void InputDisplayBindHelper::AddInputDevice(int32_t id, const std::string &name)
364 {
365 CALL_DEBUG_ENTER;
366 MMI_HILOGD("Param: id:%{public}d, name:%{public}s", id, name.c_str());
367 auto displayName = configFileInfos_->GetDisplayNameByInputDevice(name);
368 BindInfo info = infos_->GetUnbindInputDevice(displayName);
369 info.AddInputDevice(id, name);
370 infos_->Add(info);
371 Store();
372 }
373
RemoveInputDevice(int32_t id)374 void InputDisplayBindHelper::RemoveInputDevice(int32_t id)
375 {
376 CALL_DEBUG_ENTER;
377 MMI_HILOGD("Param: id:%{public}d", id);
378 infos_->UnbindInputDevice(id);
379 }
380
IsDisplayAdd(int32_t id,const std::string & name)381 bool InputDisplayBindHelper::IsDisplayAdd(int32_t id, const std::string &name)
382 {
383 const auto &infos = infos_->GetInfos();
384 for (const auto &info : infos) {
385 if ((info.GetDisplayName() == name) && (info.GetDisplayId() == id)) {
386 return true;
387 }
388 }
389 return false;
390 }
391
GetDisplayIdNames() const392 std::set<std::pair<int32_t, std::string>> InputDisplayBindHelper::GetDisplayIdNames() const
393 {
394 CALL_DEBUG_ENTER;
395 std::set<std::pair<int32_t, std::string>> idNames;
396 const auto &infos = infos_->GetInfos();
397 for (const auto &info : infos) {
398 if (info.GetDisplayId() != -1) {
399 idNames.insert(std::make_pair(info.GetDisplayId(), info.GetDisplayName()));
400 }
401 }
402 return idNames;
403 }
404
AddDisplay(int32_t id,const std::string & name)405 void InputDisplayBindHelper::AddDisplay(int32_t id, const std::string &name)
406 {
407 CALL_DEBUG_ENTER;
408 MMI_HILOGD("Param: id:%{public}d, name:%{public}s", id, name.c_str());
409 auto inputDeviceName = configFileInfos_->GetInputDeviceByDisplayName(name);
410 BindInfo info = infos_->GetUnbindDisplay(inputDeviceName);
411 info.AddDisplay(id, name);
412 infos_->Add(info);
413 Store();
414 }
415
RemoveDisplay(int32_t id)416 void InputDisplayBindHelper::RemoveDisplay(int32_t id)
417 {
418 CALL_DEBUG_ENTER;
419 MMI_HILOGD("Param: id:%{public}d", id);
420 infos_->UnbindDisplay(id);
421 }
422
Store()423 void InputDisplayBindHelper::Store()
424 {
425 CALL_DEBUG_ENTER;
426 if (infos_ == nullptr) {
427 return;
428 }
429 char *canonicalPath = realpath(fileName_.c_str(), nullptr);
430 if (canonicalPath == nullptr) {
431 MMI_HILOGE("file name is empty");
432 return;
433 }
434 if (!IsValidJsonPath(canonicalPath)) {
435 MMI_HILOGE("file path is invalid");
436 return;
437 }
438 std::ofstream ofs(canonicalPath, std::ios::trunc | std::ios::out | std::ios_base::binary);
439 if (!ofs) {
440 MMI_HILOGE("Open file fail.%{public}s, errno:%{public}d", canonicalPath, errno);
441 return;
442 }
443 ofs << *infos_;
444 ofs.close();
445 free(canonicalPath);
446 canonicalPath = nullptr;
447 }
448
GetDisplayBindInfo(DisplayBindInfos & infos)449 int32_t InputDisplayBindHelper::GetDisplayBindInfo(DisplayBindInfos &infos)
450 {
451 CALL_DEBUG_ENTER;
452 if (infos_ == nullptr) {
453 MMI_HILOGE("Infos_ is nullptr");
454 return RET_ERR;
455 }
456 for (const auto &item : infos_->GetInfos()) {
457 infos.push_back({
458 .inputDeviceId = item.GetInputDeviceId(),
459 .inputDeviceName = item.GetInputDeviceName(),
460 .displayId = item.GetDisplayId(),
461 .displayName = item.GetDisplayName(),
462 });
463 }
464 return RET_OK;
465 }
466
SetDisplayBind(int32_t deviceId,int32_t displayId,std::string & msg)467 int32_t InputDisplayBindHelper::SetDisplayBind(int32_t deviceId, int32_t displayId, std::string &msg)
468 {
469 CALL_DEBUG_ENTER;
470 MMI_HILOGD("Param: deviceId:%{public}d, displayId:%{public}d", deviceId, displayId);
471 if ((deviceId == -1) || (displayId == -1)) {
472 msg = "The deviceId or displayId is invalid";
473 MMI_HILOGE("%s", msg.c_str());
474 return RET_ERR;
475 }
476 if (infos_ == nullptr) {
477 msg = "Infos_ is nullptr";
478 MMI_HILOGE("%s", msg.c_str());
479 return RET_ERR;
480 }
481
482 BindInfo bindByDevice;
483 BindInfo bindByDisplay;
484 for (const auto &item : infos_->GetInfos()) {
485 if (item.GetInputDeviceId() == deviceId) {
486 bindByDevice = item;
487 }
488 if (item.GetDisplayId() == displayId) {
489 bindByDisplay = item;
490 }
491 }
492 if (bindByDevice.GetInputDeviceId() == -1) {
493 msg = "The deviceId is invalid";
494 MMI_HILOGE("%s", msg.c_str());
495 return RET_ERR;
496 }
497 if (bindByDisplay.GetDisplayId() == -1) {
498 msg = "The displayId is invalid";
499 MMI_HILOGE("%s", msg.c_str());
500 return RET_ERR;
501 }
502
503 if (infos_->GetBindDisplayIdByInputDevice(deviceId) == displayId) {
504 msg = "The input device and display has alread bind";
505 MMI_HILOGE("%s", msg.c_str());
506 return RET_ERR;
507 }
508
509 infos_->UnbindInputDevice(bindByDevice.GetInputDeviceId());
510 infos_->UnbindInputDevice(bindByDisplay.GetInputDeviceId());
511 infos_->UnbindDisplay(bindByDevice.GetDisplayId());
512 infos_->UnbindDisplay(bindByDisplay.GetDisplayId());
513
514 BindInfo info1;
515 info1.AddInputDevice(bindByDevice.GetInputDeviceId(), bindByDevice.GetInputDeviceName());
516 info1.AddDisplay(bindByDisplay.GetDisplayId(), bindByDisplay.GetDisplayName());
517 infos_->Add(info1);
518
519 if ((bindByDevice.GetDisplayId() != -1) && (bindByDisplay.GetInputDeviceId() != -1)) {
520 MMI_HILOGD("Both display id and input device id are invalid");
521 BindInfo info2;
522 info2.AddInputDevice(bindByDisplay.GetInputDeviceId(), bindByDisplay.GetInputDeviceName());
523 info2.AddDisplay(bindByDevice.GetDisplayId(), bindByDevice.GetDisplayName());
524 infos_->Add(info2);
525 return RET_OK;
526 }
527
528 if (bindByDevice.GetDisplayId() != -1) {
529 MMI_HILOGD("The display id is invalid");
530 AddDisplay(bindByDevice.GetDisplayId(), bindByDevice.GetDisplayName());
531 return RET_OK;
532 }
533
534 if (bindByDisplay.GetInputDeviceId() != -1) {
535 MMI_HILOGD("The input device id is invalid");
536 AddInputDevice(bindByDisplay.GetInputDeviceId(), bindByDisplay.GetInputDeviceName());
537 return RET_OK;
538 }
539
540 msg = "Can not reach here";
541 return RET_ERR;
542 }
543
Load()544 void InputDisplayBindHelper::Load()
545 {
546 CALL_DEBUG_ENTER;
547 char *canonicalPath = realpath(fileName_.c_str(), nullptr);
548 if (canonicalPath == nullptr) {
549 MMI_HILOGE("file name is empty");
550 return;
551 }
552 if (!IsValidJsonPath(canonicalPath)) {
553 MMI_HILOGE("file path is invalid");
554 return;
555 }
556 std::ifstream ifs(canonicalPath);
557 MMI_HILOGEK("Open file end:%{public}s", canonicalPath);
558 if (!ifs) {
559 MMI_HILOGE("Open file fail.%{public}s, errno:%{public}d", canonicalPath, errno);
560 return;
561 }
562 ifs >> *configFileInfos_;
563 ifs.close();
564 free(canonicalPath);
565 canonicalPath = nullptr;
566 }
567
Dumps() const568 std::string InputDisplayBindHelper::Dumps() const
569 {
570 CALL_DEBUG_ENTER;
571 if (infos_ == nullptr) {
572 return {};
573 }
574 std::ostringstream oss;
575 oss << *infos_;
576 return oss.str();
577 }
578 } // namespace MMI
579 } // namespace OHOS