blob: 6607bc797202b51cbeb952305baa38f3a65772bd [file] [log] [blame]
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +01001/*
2 * Copyright 2024 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#include "RotaryEncoderInputMapper.h"
18
19#include <list>
20#include <string>
21#include <tuple>
22#include <variant>
23
24#include <android-base/logging.h>
Biswarup Palba27d1d2024-07-09 19:57:33 +000025#include <android_companion_virtualdevice_flags.h>
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +010026#include <gtest/gtest.h>
27#include <input/DisplayViewport.h>
28#include <linux/input-event-codes.h>
29#include <linux/input.h>
30#include <utils/Timers.h>
31
32#include "InputMapperTest.h"
33#include "InputReaderBase.h"
34#include "InterfaceMocks.h"
35#include "NotifyArgs.h"
36#include "TestEventMatchers.h"
37#include "ui/Rotation.h"
38
39#define TAG "RotaryEncoderInputMapper_test"
40
41namespace android {
42
43using testing::AllOf;
44using testing::Return;
45using testing::VariantWith;
46constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
47constexpr ui::LogicalDisplayId SECONDARY_DISPLAY_ID = ui::LogicalDisplayId{DISPLAY_ID.val() + 1};
48constexpr int32_t DISPLAY_WIDTH = 480;
49constexpr int32_t DISPLAY_HEIGHT = 800;
50
51namespace {
52
53DisplayViewport createViewport() {
54 DisplayViewport v;
55 v.orientation = ui::Rotation::Rotation0;
56 v.logicalRight = DISPLAY_HEIGHT;
57 v.logicalBottom = DISPLAY_WIDTH;
58 v.physicalRight = DISPLAY_HEIGHT;
59 v.physicalBottom = DISPLAY_WIDTH;
60 v.deviceWidth = DISPLAY_HEIGHT;
61 v.deviceHeight = DISPLAY_WIDTH;
62 v.isActive = true;
63 return v;
64}
65
66DisplayViewport createPrimaryViewport() {
67 DisplayViewport v = createViewport();
68 v.displayId = DISPLAY_ID;
69 v.uniqueId = "local:1";
70 return v;
71}
72
73DisplayViewport createSecondaryViewport() {
74 DisplayViewport v = createViewport();
75 v.displayId = SECONDARY_DISPLAY_ID;
76 v.uniqueId = "local:2";
77 v.type = ViewportType::EXTERNAL;
78 return v;
79}
80
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +010081} // namespace
82
Biswarup Palba27d1d2024-07-09 19:57:33 +000083namespace vd_flags = android::companion::virtualdevice::flags;
84
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +010085/**
86 * Unit tests for RotaryEncoderInputMapper.
87 */
88class RotaryEncoderInputMapperTest : public InputMapperUnitTest {
89protected:
90 void SetUp() override { SetUpWithBus(BUS_USB); }
91 void SetUpWithBus(int bus) override {
92 InputMapperUnitTest::SetUpWithBus(bus);
93
94 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL))
95 .WillRepeatedly(Return(true));
96 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL))
97 .WillRepeatedly(Return(false));
Biswarup Pal8ff5e5e2024-06-15 12:58:20 +000098 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
99 .WillRepeatedly(Return(false));
100 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES))
101 .WillRepeatedly(Return(false));
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +0100102 }
103};
104
105TEST_F(RotaryEncoderInputMapperTest, ConfigureDisplayIdWithAssociatedViewport) {
106 DisplayViewport primaryViewport = createPrimaryViewport();
107 DisplayViewport secondaryViewport = createSecondaryViewport();
108 mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
109
110 // Set up the secondary display as the associated viewport of the mapper.
Harry Cutts0b613dc2024-07-25 19:33:48 +0000111 EXPECT_CALL((*mDevice), getAssociatedViewport).WillRepeatedly(Return(secondaryViewport));
112 mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +0100113
114 std::list<NotifyArgs> args;
115 // Ensure input events are generated for the secondary display.
116 args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
117 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
118 EXPECT_THAT(args,
119 ElementsAre(VariantWith<NotifyMotionArgs>(
120 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
121 WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
122 WithDisplayId(SECONDARY_DISPLAY_ID)))));
123}
124
125TEST_F(RotaryEncoderInputMapperTest, ConfigureDisplayIdNoAssociatedViewport) {
126 // Set up the default display.
127 mFakePolicy->clearViewports();
128 mFakePolicy->addDisplayViewport(createPrimaryViewport());
129
130 // Set up the mapper with no associated viewport.
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +0100131 mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
132
133 // Ensure input events are generated without display ID
134 std::list<NotifyArgs> args;
135 args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
136 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
137 EXPECT_THAT(args,
138 ElementsAre(VariantWith<NotifyMotionArgs>(
139 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
140 WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
141 WithDisplayId(ui::LogicalDisplayId::INVALID)))));
142}
143
Biswarup Palba27d1d2024-07-09 19:57:33 +0000144TEST_F(RotaryEncoderInputMapperTest, ProcessRegularScroll) {
Biswarup Palba27d1d2024-07-09 19:57:33 +0000145 mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
146
147 std::list<NotifyArgs> args;
148 args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
149 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
150
151 EXPECT_THAT(args,
152 ElementsAre(VariantWith<NotifyMotionArgs>(
153 AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
154 WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(1.0f)))));
155}
156
157TEST_F(RotaryEncoderInputMapperTest, ProcessHighResScroll) {
158 vd_flags::high_resolution_scroll(true);
159 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
160 .WillRepeatedly(Return(true));
Biswarup Palba27d1d2024-07-09 19:57:33 +0000161 mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
162
163 std::list<NotifyArgs> args;
164 args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
165 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
166
167 EXPECT_THAT(args,
168 ElementsAre(VariantWith<NotifyMotionArgs>(
169 AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
170 WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f)))));
171}
172
173TEST_F(RotaryEncoderInputMapperTest, HighResScrollIgnoresRegularScroll) {
174 vd_flags::high_resolution_scroll(true);
175 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES))
176 .WillRepeatedly(Return(true));
Biswarup Palba27d1d2024-07-09 19:57:33 +0000177 mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
178
179 std::list<NotifyArgs> args;
180 args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60);
181 args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
182 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
183
184 EXPECT_THAT(args,
185 ElementsAre(VariantWith<NotifyMotionArgs>(
186 AllOf(WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
187 WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f)))));
188}
189
Vladimir Komsiyskidd438e22024-02-13 11:47:54 +0100190} // namespace android