Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea6f56d6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make topology validator a static function" into main

parents b2d8f7e2 5f18ceb8
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <android-base/result.h>
#include <ftl/enum.h>
#include <ui/LogicalDisplayId.h>

@@ -58,8 +59,23 @@ struct DisplayTopologyGraph {
    std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> graph;
    std::unordered_map<ui::LogicalDisplayId, int> displaysDensity;

    bool isValid() const;
    DisplayTopologyGraph() = default;
    std::string dump() const;

    // Builds the topology graph from components.
    // Returns error if a valid graph cannot be built from the supplied components.
    static base::Result<const DisplayTopologyGraph> create(
            ui::LogicalDisplayId primaryDisplay,
            std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&&
                    adjacencyGraph,
            std::unordered_map<ui::LogicalDisplayId, int>&& displaysDensityMap);

private:
    DisplayTopologyGraph(
            ui::LogicalDisplayId primaryDisplay,
            std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&&
                    adjacencyGraph,
            std::unordered_map<ui::LogicalDisplayId, int>&& displaysDensityMap);
};

} // namespace android
+70 −24
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <com_android_input_flags.h>
#include <ftl/enum.h>
#include <input/DisplayTopologyGraph.h>
#include <input/PrintTools.h>
@@ -27,6 +28,8 @@

#define INDENT "  "

namespace input_flags = com::android::input::flags;

namespace android {

namespace {
@@ -44,16 +47,19 @@ DisplayTopologyPosition getOppositePosition(DisplayTopologyPosition position) {
    }
}

bool validatePrimaryDisplay(const android::DisplayTopologyGraph& displayTopologyGraph) {
    return displayTopologyGraph.primaryDisplayId != ui::LogicalDisplayId::INVALID &&
            displayTopologyGraph.graph.contains(displayTopologyGraph.primaryDisplayId);
bool validatePrimaryDisplay(ui::LogicalDisplayId primaryDisplayId,
                            const std::unordered_map<ui::LogicalDisplayId, int>& displaysDensity) {
    return primaryDisplayId != ui::LogicalDisplayId::INVALID &&
            displaysDensity.contains(primaryDisplayId);
}

bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyGraph) {
    for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
bool validateTopologyGraph(
        const std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&
                graph) {
    for (const auto& [sourceDisplay, adjacentDisplays] : graph) {
        for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : adjacentDisplays) {
            const auto adjacentGraphIt = displayTopologyGraph.graph.find(adjacentDisplay.displayId);
            if (adjacentGraphIt == displayTopologyGraph.graph.end()) {
            const auto adjacentGraphIt = graph.find(adjacentDisplay.displayId);
            if (adjacentGraphIt == graph.end()) {
                LOG(ERROR) << "Missing adjacent display in topology graph: "
                           << adjacentDisplay.displayId << " for source " << sourceDisplay;
                return false;
@@ -90,9 +96,11 @@ bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyG
    return true;
}

bool validateDensities(const android::DisplayTopologyGraph& displayTopologyGraph) {
    for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
        if (!displayTopologyGraph.displaysDensity.contains(sourceDisplay)) {
bool validateDensities(const std::unordered_map<ui::LogicalDisplayId,
                                                std::vector<DisplayTopologyAdjacentDisplay>>& graph,
                       const std::unordered_map<ui::LogicalDisplayId, int>& displaysDensity) {
    for (const auto& [sourceDisplay, adjacentDisplays] : graph) {
        if (!displaysDensity.contains(sourceDisplay)) {
            LOG(ERROR) << "Missing density value in topology graph for display: " << sourceDisplay;
            return false;
        }
@@ -113,22 +121,23 @@ std::string adjacentDisplayVectorToString(
    return dumpVector(adjacentDisplays, adjacentDisplayToString);
}

} // namespace

std::string DisplayTopologyAdjacentDisplay::dump() const {
    std::string dump;
    dump += base::StringPrintf("DisplayTopologyAdjacentDisplay: {displayId: %d, position: %s, "
                               "offsetDp: %f}",
                               displayId.val(), ftl::enum_string(position).c_str(), offsetDp);
    return dump;
bool areTopologyGraphComponentsValid(
        ui::LogicalDisplayId primaryDisplayId,
        const std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&
                graph,
        const std::unordered_map<ui::LogicalDisplayId, int>& displaysDensity) {
    if (!input_flags::enable_display_topology_validation()) {
        return true;
    }

bool DisplayTopologyGraph::isValid() const {
    return validatePrimaryDisplay(*this) && validateTopologyGraph(*this) &&
            validateDensities(*this);
    return validatePrimaryDisplay(primaryDisplayId, displaysDensity) &&
            validateTopologyGraph(graph) && validateDensities(graph, displaysDensity);
}

std::string DisplayTopologyGraph::dump() const {
std::string dumpTopologyGraphComponents(
        ui::LogicalDisplayId primaryDisplayId,
        const std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&
                graph,
        const std::unordered_map<ui::LogicalDisplayId, int>& displaysDensity) {
    std::string dump;
    dump += base::StringPrintf("PrimaryDisplayId: %d\n", primaryDisplayId.val());
    dump += base::StringPrintf("TopologyGraph:\n");
@@ -141,4 +150,41 @@ std::string DisplayTopologyGraph::dump() const {
    return dump;
}

} // namespace

std::string DisplayTopologyAdjacentDisplay::dump() const {
    std::string dump;
    dump += base::StringPrintf("DisplayTopologyAdjacentDisplay: {displayId: %d, position: %s, "
                               "offsetDp: %f}",
                               displayId.val(), ftl::enum_string(position).c_str(), offsetDp);
    return dump;
}

DisplayTopologyGraph::DisplayTopologyGraph(
        ui::LogicalDisplayId primaryDisplay,
        std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&&
                adjacencyGraph,
        std::unordered_map<ui::LogicalDisplayId, int>&& displaysDensityMap)
      : primaryDisplayId(primaryDisplay),
        graph(std::move(adjacencyGraph)),
        displaysDensity(std::move(displaysDensityMap)) {}

std::string DisplayTopologyGraph::dump() const {
    return dumpTopologyGraphComponents(primaryDisplayId, graph, displaysDensity);
}

base::Result<const DisplayTopologyGraph> DisplayTopologyGraph::create(
        ui::LogicalDisplayId primaryDisplay,
        std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>&&
                adjacencyGraph,
        std::unordered_map<ui::LogicalDisplayId, int>&& displaysDensityMap) {
    if (areTopologyGraphComponentsValid(primaryDisplay, adjacencyGraph, displaysDensityMap)) {
        return DisplayTopologyGraph(primaryDisplay, std::move(adjacencyGraph),
                                    std::move(displaysDensityMap));
    }
    return base::Error() << "Invalid display topology components: "
                         << dumpTopologyGraphComponents(primaryDisplay, adjacencyGraph,
                                                        displaysDensityMap);
}

} // namespace android
+72 −52
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 * limitations under the License.
 */

#include <com_android_input_flags.h>
#include <gtest/gtest.h>
#include <input/DisplayTopologyGraph.h>

@@ -21,6 +22,8 @@
#include <string_view>
#include <tuple>

#include "ScopedFlagOverride.h"

namespace android {

namespace {
@@ -31,87 +34,104 @@ constexpr int DENSITY_MEDIUM = 160;

} // namespace

using DisplayTopologyAdjacentDisplayMap =
        std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>;
using DisplayTopologyDisplaysDensityMapVector = std::unordered_map<ui::LogicalDisplayId, int>;
using DisplayTopologyGraphTestFixtureParam =
        std::tuple<std::string_view /*name*/, DisplayTopologyGraph, bool /*isValid*/>;
        std::tuple<std::string_view /*name*/, ui::LogicalDisplayId /*primaryDisplayId*/,
                   DisplayTopologyAdjacentDisplayMap, DisplayTopologyDisplaysDensityMapVector,
                   bool /*isValid*/>;

class DisplayTopologyGraphTestFixture
      : public testing::Test,
        public testing::WithParamInterface<DisplayTopologyGraphTestFixtureParam> {};

TEST_P(DisplayTopologyGraphTestFixture, DisplayTopologyGraphTest) {
    const auto& [_, displayTopology, isValid] = GetParam();
    EXPECT_EQ(isValid, displayTopology.isValid());
    SCOPED_FLAG_OVERRIDE(enable_display_topology_validation, true);
    auto [_, primaryDisplayId, graph, displaysDensity, isValid] = GetParam();
    auto result = DisplayTopologyGraph::create(primaryDisplayId, std::move(graph),
                                               std::move(displaysDensity));
    EXPECT_EQ(isValid, result.ok());
}

INSTANTIATE_TEST_SUITE_P(
        DisplayTopologyGraphTest, DisplayTopologyGraphTestFixture,
        testing::Values(
                std::make_tuple(
                        "InvalidPrimaryDisplay",
                        DisplayTopologyGraph{.primaryDisplayId = ui::LogicalDisplayId::INVALID,
                                             .graph = {},
                                             .displaysDensity = {}},
                std::make_tuple("InvalidPrimaryDisplay",
                                /*primaryDisplayId=*/ui::LogicalDisplayId::INVALID,
                                /*graph=*/DisplayTopologyAdjacentDisplayMap{},
                                /*displaysDensity=*/DisplayTopologyDisplaysDensityMapVector{},
                                false),
                std::make_tuple("PrimaryDisplayNotInGraph",
                                DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                                     .graph = {},
                                                     .displaysDensity = {}},
                                /*primaryDisplayId=*/DISPLAY_ID_1,
                                /*graph=*/DisplayTopologyAdjacentDisplayMap{},
                                /*displaysDensity=*/DisplayTopologyDisplaysDensityMapVector{},
                                false),
                std::make_tuple("DisplayDensityMissing",
                                DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                                     .graph = {{DISPLAY_ID_1, {}}},
                                                     .displaysDensity = {}},
                                /*primaryDisplayId=*/DISPLAY_ID_1,
                                /*graph=*/DisplayTopologyAdjacentDisplayMap{{DISPLAY_ID_1, {}}},
                                /*displaysDensity=*/DisplayTopologyDisplaysDensityMapVector{},
                                false),
                std::make_tuple("ValidSingleDisplayTopology",
                                DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                                     .graph = {{DISPLAY_ID_1, {}}},
                                                     .displaysDensity = {{DISPLAY_ID_1,
                                                                          DENSITY_MEDIUM}}},
                                /*primaryDisplayId=*/DISPLAY_ID_1,
                                /*graph=*/DisplayTopologyAdjacentDisplayMap{{DISPLAY_ID_1, {}}},
                                /*displaysDensity=*/
                                DisplayTopologyDisplaysDensityMapVector{
                                        {DISPLAY_ID_1, DENSITY_MEDIUM}},
                                true),
                std::make_tuple(
                        "MissingReverseEdge",
                        DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                             .graph = {{DISPLAY_ID_1,
                                                        {{DISPLAY_ID_2,
                                                          DisplayTopologyPosition::TOP, 0}}}},
                                             .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                 {DISPLAY_ID_2, DENSITY_MEDIUM}}},
                        /*primaryDisplayId=*/DISPLAY_ID_1,
                        /*graph=*/
                        DisplayTopologyAdjacentDisplayMap{
                                {DISPLAY_ID_1, {{DISPLAY_ID_2, DisplayTopologyPosition::TOP, 0}}}},
                        /*displaysDensity=*/
                        DisplayTopologyDisplaysDensityMapVector{{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                {DISPLAY_ID_2, DENSITY_MEDIUM}},
                        false),
                std::make_tuple(
                        "IncorrectReverseEdgeDirection",
                        DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                             .graph = {{DISPLAY_ID_1,
                        /*primaryDisplayId=*/DISPLAY_ID_1,
                        /*graph=*/
                        DisplayTopologyAdjacentDisplayMap{{DISPLAY_ID_1,
                                                           {{DISPLAY_ID_2,
                                                             DisplayTopologyPosition::TOP, 0}}},
                                                          {DISPLAY_ID_2,
                                                           {{DISPLAY_ID_1,
                                                             DisplayTopologyPosition::TOP, 0}}}},
                                             .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                 {DISPLAY_ID_2, DENSITY_MEDIUM}}},
                        /*displaysDensity=*/
                        DisplayTopologyDisplaysDensityMapVector{{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                {DISPLAY_ID_2, DENSITY_MEDIUM}},
                        false),
                std::make_tuple(
                        "IncorrectReverseEdgeOffset",
                        DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                             .graph = {{DISPLAY_ID_1,
                        /*primaryDisplayId=*/DISPLAY_ID_1,
                        /*graph=*/
                        DisplayTopologyAdjacentDisplayMap{{DISPLAY_ID_1,
                                                           {{DISPLAY_ID_2,
                                                             DisplayTopologyPosition::TOP, 10}}},
                                                          {DISPLAY_ID_2,
                                                           {{DISPLAY_ID_1,
                                                          DisplayTopologyPosition::BOTTOM, 20}}}},
                                             .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                 {DISPLAY_ID_2, DENSITY_MEDIUM}}},
                                                             DisplayTopologyPosition::BOTTOM,
                                                             20}}}},
                        /*displaysDensity=*/
                        DisplayTopologyDisplaysDensityMapVector{{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                {DISPLAY_ID_2, DENSITY_MEDIUM}},
                        false),
                std::make_tuple(
                        "ValidMultiDisplayTopology",
                        DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
                                             .graph = {{DISPLAY_ID_1,
                        /*primaryDisplayId=*/DISPLAY_ID_1,
                        /*graph=*/
                        DisplayTopologyAdjacentDisplayMap{{DISPLAY_ID_1,
                                                           {{DISPLAY_ID_2,
                                                             DisplayTopologyPosition::TOP, 10}}},
                                                          {DISPLAY_ID_2,
                                                           {{DISPLAY_ID_1,
                                                          DisplayTopologyPosition::BOTTOM, -10}}}},
                                             .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                 {DISPLAY_ID_2, DENSITY_MEDIUM}}},
                                                             DisplayTopologyPosition::BOTTOM,
                                                             -10}}}},
                        /*displaysDensity=*/
                        DisplayTopologyDisplaysDensityMapVector{{DISPLAY_ID_1, DENSITY_MEDIUM},
                                                                {DISPLAY_ID_2, DENSITY_MEDIUM}},
                        true)),
        [](const testing::TestParamInfo<DisplayTopologyGraphTestFixtureParam>& p) {
            return std::string{std::get<0>(p.param)};
+12 −8
Original line number Diff line number Diff line
@@ -15493,14 +15493,18 @@ INSTANTIATE_TEST_SUITE_P(WithAndWithoutTransfer, TransferOrDontTransferFixture,
class InputDispatcherConnectedDisplayTest : public InputDispatcherDragTests {
    constexpr static int DENSITY_MEDIUM = 160;
    const DisplayTopologyGraph
            mTopology{.primaryDisplayId = DISPLAY_ID,
                      .graph = {{DISPLAY_ID,
                                 {{SECOND_DISPLAY_ID, DisplayTopologyPosition::TOP, 0.0f}}},
    const DisplayTopologyGraph mTopology =
            DisplayTopologyGraph::create(/*primaryDisplayId=*/DISPLAY_ID,
                                         /*adjacencyGraph=*/
                                         {{DISPLAY_ID,
                                           {{SECOND_DISPLAY_ID, DisplayTopologyPosition::TOP,
                                             0.0f}}},
                                          {SECOND_DISPLAY_ID,
                                           {{DISPLAY_ID, DisplayTopologyPosition::BOTTOM, 0.0f}}}},
                      .displaysDensity = {{DISPLAY_ID, DENSITY_MEDIUM},
                                          {SECOND_DISPLAY_ID, DENSITY_MEDIUM}}};
                                         /*displaysDensity=*/
                                         {{DISPLAY_ID, DENSITY_MEDIUM},
                                          {SECOND_DISPLAY_ID, DENSITY_MEDIUM}})
                    .value();
protected:
    void SetUp() override {
+47 −24
Original line number Diff line number Diff line
@@ -150,9 +150,11 @@ protected:
            // setDefaultMouseDisplayId without topology.
            // For this reason in tests we mock this behavior by creating topology with a single
            // display.
            mChoreographer.setDisplayTopology({.primaryDisplayId = displayId,
                                               .graph{{displayId, {}}},
                                               .displaysDensity = {{displayId, DENSITY_MEDIUM}}});
            mChoreographer.setDisplayTopology(
                    DisplayTopologyGraph::create(/*primaryDisplayId=*/displayId,
                                                 /*adjacencyGraph=*/{},
                                                 /*displaysDensity=*/{{displayId, DENSITY_MEDIUM}})
                            .value());
        } else {
            mChoreographer.setDefaultMouseDisplayId(displayId);
        }
@@ -2784,24 +2786,42 @@ protected:
            createViewport(DISPLAY_HIGH_DENSITY_ID, /*width*/ 200, /*height*/ 200, ui::ROTATION_0),
    };

    DisplayTopologyGraph
            mTopology{DISPLAY_CENTER_ID,
    DisplayTopologyGraph mTopology =
            DisplayTopologyGraph::
                    create(/*primaryDisplay=*/DISPLAY_CENTER_ID,
                           /*adjacencyGraph=*/
                           {{DISPLAY_CENTER_ID,
                             {{DISPLAY_TOP_ID, DisplayTopologyPosition::TOP, 50.0f},
                         // Place a high density display on the left of DISPLAY_TOP_ID with 25 dp
                         // gap
                              // Place a high density display on the left of DISPLAY_TOP_ID with
                              // 25 dp gap
                              {DISPLAY_HIGH_DENSITY_ID, DisplayTopologyPosition::TOP, -75.0f},
                              {DISPLAY_RIGHT_ID, DisplayTopologyPosition::RIGHT, 10.0f},
                              {DISPLAY_BOTTOM_ID, DisplayTopologyPosition::BOTTOM, 10.0f},
                              {DISPLAY_LEFT_ID, DisplayTopologyPosition::LEFT, 10.0f},
                         {DISPLAY_TOP_RIGHT_CORNER_ID, DisplayTopologyPosition::RIGHT, -90.0f}}}},
                              {DISPLAY_TOP_RIGHT_CORNER_ID, DisplayTopologyPosition::RIGHT,
                               -90.0f}}},
                            // Reverse edges
                            {DISPLAY_TOP_ID,
                             {{DISPLAY_CENTER_ID, DisplayTopologyPosition::BOTTOM, -50.0f}}},
                            {DISPLAY_HIGH_DENSITY_ID,
                             {{DISPLAY_CENTER_ID, DisplayTopologyPosition::BOTTOM, 75.0f}}},
                            {DISPLAY_RIGHT_ID,
                             {{DISPLAY_CENTER_ID, DisplayTopologyPosition::LEFT, -10.0f}}},
                            {DISPLAY_BOTTOM_ID,
                             {{DISPLAY_CENTER_ID, DisplayTopologyPosition::TOP, -10.0f}}},
                            {DISPLAY_LEFT_ID,
                             {{DISPLAY_CENTER_ID, DisplayTopologyPosition::RIGHT, -10.0f}}},
                            {DISPLAY_TOP_RIGHT_CORNER_ID,
                             {{DISPLAY_CENTER_ID, DisplayTopologyPosition::LEFT, 90.0f}}}},
                           /*displaysDensityMap=*/
                           {{DISPLAY_CENTER_ID, DENSITY_MEDIUM},
                            {DISPLAY_TOP_ID, DENSITY_MEDIUM},
                            {DISPLAY_RIGHT_ID, DENSITY_MEDIUM},
                            {DISPLAY_BOTTOM_ID, DENSITY_MEDIUM},
                            {DISPLAY_LEFT_ID, DENSITY_MEDIUM},
                            {DISPLAY_TOP_RIGHT_CORNER_ID, DENSITY_MEDIUM},
                       {DISPLAY_HIGH_DENSITY_ID, DENSITY_HIGH}}};
                            {DISPLAY_HIGH_DENSITY_ID, DENSITY_HIGH}})
                            .value();
};

TEST_P(PointerChoreographerDisplayTopologyCursorTestFixture,
@@ -2955,7 +2975,6 @@ protected:

        std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>
                topologyGraph;
        topologyGraph[primaryDisplayId] = {};

        std::unordered_map<ui::LogicalDisplayId, int> displaysDensity;
        displaysDensity[primaryDisplayId] = DENSITY_MEDIUM;
@@ -2969,9 +2988,13 @@ protected:
                                                        .offsetDp = 0.0f});

            displaysDensity[adjacentDisplayId] = DENSITY_MEDIUM;
            previousDisplay = adjacentDisplayId;
        }

        mChoreographer.setDisplayTopology({primaryDisplayId, topologyGraph, displaysDensity});
        mChoreographer.setDisplayTopology(DisplayTopologyGraph::create(primaryDisplayId,
                                                                       std::move(topologyGraph),
                                                                       std::move(displaysDensity))
                                                  .value());
    }
};

@@ -3028,7 +3051,7 @@ TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,

    // Change the primary display to the third display
    setDisplayTopologyWithDisplays(/*primaryDisplayId=*/THIRD_DISPLAY_ID, /*adjacentDisplays=*/
                                   {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID});
                                   {SECOND_DISPLAY_ID, FIRST_DISPLAY_ID});

    assertPointerControllerNotCreated();
    pc->assertViewportSet(SECOND_DISPLAY_ID);