1 /*
2 * Copyright (C) 2019 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 <binder/Binder.h>
18 #include <binder/Parcel.h>
19 #include <gtest/gtest.h>
20 #include <input/InputDevice.h>
21 #include <input/KeyLayoutMap.h>
22 #include <input/Keyboard.h>
23 #include "android-base/file.h"
24
25 namespace android {
26
27 // --- InputDeviceIdentifierTest ---
28
TEST(InputDeviceIdentifierTest,getCanonicalName)29 TEST(InputDeviceIdentifierTest, getCanonicalName) {
30 InputDeviceIdentifier identifier;
31 identifier.name = "test device";
32 ASSERT_EQ(std::string("test_device"), identifier.getCanonicalName());
33
34 identifier.name = "deviceName-123 version_C!";
35 ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName());
36 }
37
38 class InputDeviceKeyMapTest : public testing::Test {
39 protected:
loadKeyLayout(const char * name)40 void loadKeyLayout(const char* name) {
41 std::string path =
42 getInputDeviceConfigurationFilePathByName(name,
43 InputDeviceConfigurationFileType::
44 KEY_LAYOUT);
45 ASSERT_FALSE(path.empty());
46 base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
47 ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << path;
48 mKeyMap.keyLayoutMap = std::move(*ret);
49 mKeyMap.keyLayoutFile = path;
50 }
51
loadKeyCharacterMap(const char * name)52 void loadKeyCharacterMap(const char* name) {
53 InputDeviceIdentifier identifier;
54 identifier.name = name;
55 std::string path =
56 getInputDeviceConfigurationFilePathByName(identifier.getCanonicalName(),
57 InputDeviceConfigurationFileType::
58 KEY_CHARACTER_MAP);
59 ASSERT_FALSE(path.empty()) << "KeyCharacterMap for " << name << " not found";
60 base::Result<std::shared_ptr<KeyCharacterMap>> ret =
61 KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
62 ASSERT_TRUE(ret.ok()) << "Cannot load KeyCharacterMap at " << path;
63 mKeyMap.keyCharacterMap = *ret;
64 mKeyMap.keyCharacterMapFile = path;
65 }
66
SetUp()67 void SetUp() override {
68 loadKeyLayout("Generic");
69 loadKeyCharacterMap("Generic");
70 }
71
72 KeyMap mKeyMap;
73 };
74
TEST_F(InputDeviceKeyMapTest,keyCharacterMapParcelingTest)75 TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) {
76 Parcel parcel;
77 mKeyMap.keyCharacterMap->writeToParcel(&parcel);
78 parcel.setDataPosition(0);
79 std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel);
80 // Verify the key character map is the same as original
81 ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
82 }
83
TEST_F(InputDeviceKeyMapTest,keyCharacterMapWithOverlayParcelingTest)84 TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) {
85 Parcel parcel;
86 std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
87 base::Result<std::shared_ptr<KeyCharacterMap>> overlay =
88 KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY);
89 ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath;
90 mKeyMap.keyCharacterMap->combine(*overlay->get());
91 mKeyMap.keyCharacterMap->writeToParcel(&parcel);
92 parcel.setDataPosition(0);
93 std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel);
94 ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
95 }
96
TEST_F(InputDeviceKeyMapTest,keyCharacteMapApplyMultipleOverlaysTest)97 TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) {
98 std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm";
99 std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm";
100 std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
101 base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay =
102 KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY);
103 ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath;
104 base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay =
105 KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY);
106 ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath;
107 base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay =
108 KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY);
109 ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath;
110
111 // Apply the French overlay
112 mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
113 // Copy the result for later
114 std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap =
115 std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap);
116
117 // Apply the English overlay
118 mKeyMap.keyCharacterMap->combine(*englishOverlay->get());
119 // Verify that the result is different from the French overlay result
120 ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
121
122 // Apply the German overlay
123 mKeyMap.keyCharacterMap->combine(*germanOverlay->get());
124 // Verify that the result is different from the French overlay result
125 ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
126
127 // Apply the French overlay
128 mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
129 // Verify that the result is the same like after applying it initially
130 ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
131 }
132
TEST(InputDeviceKeyLayoutTest,DoesNotLoadWhenRequiredKernelConfigIsMissing)133 TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
134 std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_fake_config.kl";
135 base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
136 ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
137 // We assert error message here because it's used by 'validatekeymaps' tool
138 ASSERT_EQ("Missing kernel config", ret.error().message());
139 }
140
TEST(InputDeviceKeyLayoutTest,LoadsWhenRequiredKernelConfigIsPresent)141 TEST(InputDeviceKeyLayoutTest, LoadsWhenRequiredKernelConfigIsPresent) {
142 std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_real_config.kl";
143 base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
144 ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << klPath;
145 const std::shared_ptr<KeyLayoutMap>& map = *ret;
146 ASSERT_NE(nullptr, map) << "Map should be valid because CONFIG_UHID should always be present";
147 }
148
149 } // namespace android
150