|  | /* | 
|  | * Copyright (C) 2019 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include <binder/Binder.h> | 
|  | #include <binder/Parcel.h> | 
|  | #include <gtest/gtest.h> | 
|  | #include <input/InputDevice.h> | 
|  | #include <input/KeyLayoutMap.h> | 
|  | #include <input/Keyboard.h> | 
|  | #include "android-base/file.h" | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | // --- InputDeviceIdentifierTest --- | 
|  |  | 
|  | TEST(InputDeviceIdentifierTest, getCanonicalName) { | 
|  | InputDeviceIdentifier identifier; | 
|  | identifier.name = "test device"; | 
|  | ASSERT_EQ(std::string("test_device"), identifier.getCanonicalName()); | 
|  |  | 
|  | identifier.name = "deviceName-123 version_C!"; | 
|  | ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName()); | 
|  | } | 
|  |  | 
|  | class InputDeviceKeyMapTest : public testing::Test { | 
|  | protected: | 
|  | void loadKeyLayout(const char* name) { | 
|  | std::string path = | 
|  | getInputDeviceConfigurationFilePathByName(name, | 
|  | InputDeviceConfigurationFileType:: | 
|  | KEY_LAYOUT); | 
|  | ASSERT_FALSE(path.empty()); | 
|  | base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path); | 
|  | ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << path; | 
|  | mKeyMap.keyLayoutMap = std::move(*ret); | 
|  | mKeyMap.keyLayoutFile = path; | 
|  | } | 
|  |  | 
|  | void loadKeyCharacterMap(const char* name) { | 
|  | InputDeviceIdentifier identifier; | 
|  | identifier.name = name; | 
|  | std::string path = | 
|  | getInputDeviceConfigurationFilePathByName(identifier.getCanonicalName(), | 
|  | InputDeviceConfigurationFileType:: | 
|  | KEY_CHARACTER_MAP); | 
|  | ASSERT_FALSE(path.empty()) << "KeyCharacterMap for " << name << " not found"; | 
|  | base::Result<std::shared_ptr<KeyCharacterMap>> ret = | 
|  | KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE); | 
|  | ASSERT_TRUE(ret.ok()) << "Cannot load KeyCharacterMap at " << path; | 
|  | mKeyMap.keyCharacterMap = *ret; | 
|  | mKeyMap.keyCharacterMapFile = path; | 
|  | } | 
|  |  | 
|  | void SetUp() override { | 
|  | #if !defined(__ANDROID__) | 
|  | GTEST_SKIP() << "b/253299089 Generic files are currently read directly from device."; | 
|  | #endif | 
|  | loadKeyLayout("Generic"); | 
|  | loadKeyCharacterMap("Generic"); | 
|  | } | 
|  |  | 
|  | KeyMap mKeyMap; | 
|  | }; | 
|  |  | 
|  | TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) { | 
|  | Parcel parcel; | 
|  | mKeyMap.keyCharacterMap->writeToParcel(&parcel); | 
|  | parcel.setDataPosition(0); | 
|  | std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel); | 
|  | // Verify the key character map is the same as original | 
|  | ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); | 
|  | } | 
|  |  | 
|  | TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) { | 
|  | Parcel parcel; | 
|  | std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; | 
|  | base::Result<std::shared_ptr<KeyCharacterMap>> overlay = | 
|  | KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY); | 
|  | ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath; | 
|  | mKeyMap.keyCharacterMap->combine(*overlay->get()); | 
|  | mKeyMap.keyCharacterMap->writeToParcel(&parcel); | 
|  | parcel.setDataPosition(0); | 
|  | std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel); | 
|  | ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); | 
|  | } | 
|  |  | 
|  | TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) { | 
|  | std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm"; | 
|  | std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm"; | 
|  | std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; | 
|  | base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay = | 
|  | KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY); | 
|  | ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath; | 
|  | base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay = | 
|  | KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY); | 
|  | ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath; | 
|  | base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay = | 
|  | KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY); | 
|  | ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath; | 
|  |  | 
|  | // Apply the French overlay | 
|  | mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); | 
|  | // Copy the result for later | 
|  | std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap = | 
|  | std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap); | 
|  |  | 
|  | // Apply the English overlay | 
|  | mKeyMap.keyCharacterMap->combine(*englishOverlay->get()); | 
|  | // Verify that the result is different from the French overlay result | 
|  | ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); | 
|  |  | 
|  | // Apply the German overlay | 
|  | mKeyMap.keyCharacterMap->combine(*germanOverlay->get()); | 
|  | // Verify that the result is different from the French overlay result | 
|  | ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); | 
|  |  | 
|  | // Apply the French overlay | 
|  | mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); | 
|  | // Verify that the result is the same like after applying it initially | 
|  | ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); | 
|  | } | 
|  |  | 
|  | TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadAxisLabel) { | 
|  | std::string klPath = base::GetExecutableDirectory() + "/data/bad_axis_label.kl"; | 
|  |  | 
|  | base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath); | 
|  | ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; | 
|  | } | 
|  |  | 
|  | TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadLedLabel) { | 
|  | std::string klPath = base::GetExecutableDirectory() + "/data/bad_led_label.kl"; | 
|  |  | 
|  | base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath); | 
|  | ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; | 
|  | } | 
|  |  | 
|  | TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) { | 
|  | #if !defined(__ANDROID__) | 
|  | GTEST_SKIP() << "Can't check kernel configs on host"; | 
|  | #endif | 
|  | std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_fake_config.kl"; | 
|  | base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath); | 
|  | ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; | 
|  | // We assert error message here because it's used by 'validatekeymaps' tool | 
|  | ASSERT_EQ("Missing kernel config", ret.error().message()); | 
|  | } | 
|  |  | 
|  | TEST(InputDeviceKeyLayoutTest, LoadsWhenRequiredKernelConfigIsPresent) { | 
|  | #if !defined(__ANDROID__) | 
|  | GTEST_SKIP() << "Can't check kernel configs on host"; | 
|  | #endif | 
|  | std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_real_config.kl"; | 
|  | base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath); | 
|  | ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << klPath; | 
|  | const std::shared_ptr<KeyLayoutMap>& map = *ret; | 
|  | ASSERT_NE(nullptr, map) << "Map should be valid because CONFIG_UHID should always be present"; | 
|  | } | 
|  |  | 
|  | } // namespace android |