blob: 7ad9f163b8953adcda9b04f19712c5608afcc48d [file] [log] [blame]
Arpit Singhd6d7df72025-03-07 11:14:03 +00001/*
2 * Copyright 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "DisplayTopologyValidator"
18
19#include <android-base/logging.h>
20#include <ftl/enum.h>
21#include <input/DisplayTopologyGraph.h>
22#include <ui/LogicalDisplayId.h>
23
24#include <algorithm>
25
26namespace android {
27
28namespace {
29DisplayTopologyPosition getOppositePosition(DisplayTopologyPosition position) {
30 switch (position) {
31 case DisplayTopologyPosition::LEFT:
32 return DisplayTopologyPosition::RIGHT;
33 case DisplayTopologyPosition::TOP:
34 return DisplayTopologyPosition::BOTTOM;
35 case DisplayTopologyPosition::RIGHT:
36 return DisplayTopologyPosition::LEFT;
37 case DisplayTopologyPosition::BOTTOM:
38 return DisplayTopologyPosition::TOP;
39 }
40}
41
42bool validatePrimaryDisplay(const android::DisplayTopologyGraph& displayTopologyGraph) {
43 return displayTopologyGraph.primaryDisplayId != ui::LogicalDisplayId::INVALID &&
44 displayTopologyGraph.graph.contains(displayTopologyGraph.primaryDisplayId);
45}
46
47bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyGraph) {
48 for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
49 for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : adjacentDisplays) {
50 const auto adjacentGraphIt = displayTopologyGraph.graph.find(adjacentDisplay.displayId);
51 if (adjacentGraphIt == displayTopologyGraph.graph.end()) {
52 LOG(ERROR) << "Missing adjacent display in topology graph: "
53 << adjacentDisplay.displayId << " for source " << sourceDisplay;
54 return false;
55 }
56 const auto reverseEdgeIt =
57 std::find_if(adjacentGraphIt->second.begin(), adjacentGraphIt->second.end(),
58 [sourceDisplay](const DisplayTopologyAdjacentDisplay&
59 reverseAdjacentDisplay) {
60 return sourceDisplay == reverseAdjacentDisplay.displayId;
61 });
62 if (reverseEdgeIt == adjacentGraphIt->second.end()) {
63 LOG(ERROR) << "Missing reverse edge in topology graph for: " << sourceDisplay
64 << " -> " << adjacentDisplay.displayId;
65 return false;
66 }
67 DisplayTopologyPosition expectedPosition =
68 getOppositePosition(adjacentDisplay.position);
69 if (reverseEdgeIt->position != expectedPosition) {
70 LOG(ERROR) << "Unexpected reverse edge for: " << sourceDisplay << " -> "
71 << adjacentDisplay.displayId
72 << " expected position: " << ftl::enum_string(expectedPosition)
73 << " actual " << ftl::enum_string(reverseEdgeIt->position);
74 return false;
75 }
76 if (reverseEdgeIt->offsetDp != -adjacentDisplay.offsetDp) {
77 LOG(ERROR) << "Unexpected reverse edge offset: " << sourceDisplay << " -> "
78 << adjacentDisplay.displayId
79 << " expected offset: " << -adjacentDisplay.offsetDp << " actual "
80 << reverseEdgeIt->offsetDp;
81 return false;
82 }
83 }
84 }
85 return true;
86}
87
88bool validateDensities(const android::DisplayTopologyGraph& displayTopologyGraph) {
89 for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
90 if (!displayTopologyGraph.displaysDensity.contains(sourceDisplay)) {
91 LOG(ERROR) << "Missing density value in topology graph for display: " << sourceDisplay;
92 return false;
93 }
94 }
95 return true;
96}
97
98} // namespace
99
100bool DisplayTopologyGraph::isValid() const {
101 return validatePrimaryDisplay(*this) && validateTopologyGraph(*this) &&
102 validateDensities(*this);
103}
104
105} // namespace android