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