From d0729e1ec2498d3c1dd780063085d352f3436423 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 5 Dec 2018 16:46:06 -0800 Subject: Remove unused function The function is unused. Remove it. Bug: none Test: presubmit only Change-Id: If5af47bbdb119b106021ea79da0bd4b06ea27548 --- include/input/Input.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index aa42db8ea8..a8c386e47e 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -328,8 +328,6 @@ struct PointerCoords { float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); - void scale(float globalScale); - // Scale the pointer coordinates according to a global scale and a // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. -- cgit v1.2.3-59-g8ed1b From 7fed43d17aa7c6d8ff4d7a179d53ee7dc9f26d89 Mon Sep 17 00:00:00 2001 From: gfan Date: Tue, 6 Apr 2021 18:50:06 -0700 Subject: Fix ndk native reference documentation link errors/warnings Trivial changes, no functionality impact. Bug: 183002717 Test: build ndk with 'm ndk' works Change-Id: I1ee646f28500ad5769abdddd4e9780a1915fd528 --- include/android/bitmap.h | 1 + include/android/choreographer.h | 5 +++++ include/android/font.h | 6 +++--- include/android/font_matcher.h | 14 +++++++------- libs/nativewindow/include/android/native_window.h | 5 +++++ 5 files changed, 21 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/android/bitmap.h b/include/android/bitmap.h index a70dffd756..6704a1ddf2 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -241,6 +241,7 @@ typedef struct AHardwareBuffer AHardwareBuffer; * * Available since API level 30. * + * @param env Handle to the JNI environment pointer. * @param bitmap Handle to an android.graphics.Bitmap. * @param outBuffer On success, is set to a pointer to the * {@link AHardwareBuffer} associated with bitmap. This acquires diff --git a/include/android/choreographer.h b/include/android/choreographer.h index cc5420e239..b743f491e4 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -32,6 +32,11 @@ __BEGIN_DECLS struct AChoreographer; +/** + * Opaque type that provides access to an AChoreographer object. + * + * A pointer can be obtained using {@link AChoreographer_getInstance()}. + */ typedef struct AChoreographer AChoreographer; /** diff --git a/include/android/font.h b/include/android/font.h index a172618829..8a3a474f25 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -189,7 +189,7 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU * Available since API level 29. * * \param font a font object. Passing NULL is not allowed. - * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. + * \return a positive integer less than or equal to {@link AFONT_WEIGHT_MAX} is returned. */ uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); @@ -241,7 +241,7 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); * In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag * and AFont_getAxisValue will return following values. * \code{.cpp} - * AFont* font = AFontIterator_next(ite); + * AFont* font = ASystemFontIterator_next(ite); * * // Returns the number of axes * AFont_getAxisCount(font); // Returns 2 @@ -289,7 +289,7 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or - * equal to {@link ASYstemFont_getAxisCount} is not allwed. + * equal to {@link AFont_getAxisCount} is not allowed. * \return a float value for the given font variation setting. */ float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex) diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index 49e478c2f3..4417422687 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -36,7 +36,7 @@ * // Simple font query for the ASCII character. * std::vector text = { 'A' }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a valid font file. * AFontMatcher_destroy(matcher); * @@ -44,17 +44,17 @@ * std::vector text = { 0x9AA8 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); * AFontMatcher_setLocales(matcher, "zh-CN,ja-JP"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Simplified Chinese font. * AFontMatcher_setLocales(matcher, "ja-JP,zh-CN"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Japanese font. * AFontMatcher_destroy(matcher); * * // Querying font for text/color emoji * std::vector text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 8 and the font will points a color emoji font. * AFontMatcher_destroy(matcher); * @@ -62,7 +62,7 @@ * // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character. * std::vector text = { 0x05D0, 0x0E01 }; * AFontMatcher* matcher = AFontMatcher_create("sans-serif"); - * ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); + * AFont* font = AFontMatcher_match(text.data(), text.length(), &runLength); * // runLength will be 1 and the font will points a Hebrew font. * AFontMatcher_destroy(matcher); * \endcode @@ -146,7 +146,7 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); /** * Set font style to matcher. * - * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} + * If this function is not called, the matcher performs with {@link AFONT_WEIGHT_NORMAL} * with non-italic style. * * Available since API level 29. @@ -206,7 +206,7 @@ void AFontMatcher_setFamilyVariant( * \param textLength a length of the given text buffer. This must not be zero. * \param runLengthOut if not null, the font run length will be filled. * \return a font to be used for given text and params. You need to release the returned font by - * ASystemFont_close when it is no longer needed. + * AFont_close when it is no longer needed. */ AFont* _Nonnull AFontMatcher_match( const AFontMatcher* _Nonnull matcher, diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 50e9d53604..61b3f94aab 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -157,6 +157,7 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. * + * \param window pointer to an ANativeWindow object. * \param width width of the buffers in pixels. * \param height height of the buffers in pixels. * \param format one of the AHardwareBuffer_Format constants. @@ -191,6 +192,7 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); * * Available since API level 26. * + * \param window pointer to an ANativeWindow object. * \param transform combination of {@link ANativeWindowTransform} flags * \return 0 for success, or -EINVAL if \p transform is invalid */ @@ -208,6 +210,7 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * * Available since API level 28. * + * \param window pointer to an ANativeWindow object. * \param dataSpace data space of all buffers queued after this call. * \return 0 for success, -EINVAL if window is invalid or the dataspace is not * supported. @@ -306,6 +309,8 @@ enum ANativeWindow_ChangeFrameRateStrategy { * valid refresh rate for this device's display - e.g., it's fine to pass 30fps * to a device that can only run the display at 60fps. * + * \param window pointer to an ANativeWindow object. + * * \param compatibility The frame rate compatibility of this window. The * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. -- cgit v1.2.3-59-g8ed1b From dda9bbadaf7aedf4cc5938ab131147a7bd05ce63 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 3 Feb 2021 18:56:00 -0800 Subject: FTL: Add SmallMap mutators Add try_emplace, try_replace, emplace_or_replace, and erase. Rename getters so that `find` returns an iterator like standard containers. Bug: 185536303 Test: ftl_test Change-Id: I095bb800c6bd786b9fceaf632aa06b2d6cdadb71 --- include/ftl/small_map.h | 132 +++++++++++++++++++----- include/ftl/small_vector.h | 2 +- libs/ftl/small_map_test.cpp | 243 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 340 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 84c15ebdca..bcaba82934 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -28,7 +29,10 @@ namespace android::ftl { // Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are // stored in contiguous storage for cache efficiency. The map is allocated statically until its size -// exceeds N, at which point mappings are relocated to dynamic memory. +// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has +// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place +// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator, +// but immutable getters that can optionally transform the value. // // SmallMap unconditionally allocates on the heap. // @@ -43,16 +47,19 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); -// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u); +// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); // -// const auto opt = map.find(-1); +// const auto opt = map.get(-1); // assert(opt); // // std::string& ref = *opt; // assert(ref.empty()); // ref = "xyz"; // -// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc"))); +// map.emplace_or_replace(0, "vanilla", 2u, 3u); +// assert(map.dynamic()); +// +// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); // template class SmallMap final { @@ -80,12 +87,7 @@ class SmallMap final { // The syntax for listing pairs is as follows: // // ftl::SmallMap map = ftl::init::map(123, "abc")(-1)(42, 3u, '?'); - // // static_assert(std::is_same_v>); - // assert(map.size() == 3u); - // assert(map.contains(-1) && map.find(-1)->get().empty()); - // assert(map.contains(42) && map.find(42)->get() == "???"); - // assert(map.contains(123) && map.find(123)->get() == "abc"); // // The types of the key and value are deduced if the first pair contains exactly two arguments: // @@ -95,7 +97,7 @@ class SmallMap final { template SmallMap(InitializerList, Types...>&& list) : map_(std::move(list)) { - // TODO: Enforce unique keys. + deduplicate(); } size_type max_size() const { return map_.max_size(); } @@ -115,27 +117,27 @@ class SmallMap final { // Returns whether a mapping exists for the given key. bool contains(const key_type& key) const { - return find(key, [](const mapped_type&) {}); + return get(key, [](const mapped_type&) {}); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); // - // const auto opt = map.find('c'); + // const auto opt = map.get('c'); // assert(opt == 'C'); // // char d = 'd'; - // const auto ref = map.find('d').value_or(std::ref(d)); + // const auto ref = map.get('d').value_or(std::ref(d)); // ref.get() = 'D'; // assert(d == 'D'); // - auto find(const key_type& key) const -> std::optional> { - return find(key, [](const mapped_type& v) { return std::cref(v); }); + auto get(const key_type& key) const -> std::optional> { + return get(key, [](const mapped_type& v) { return std::cref(v); }); } - auto find(const key_type& key) -> std::optional> { - return find(key, [](mapped_type& v) { return std::ref(v); }); + auto get(const key_type& key) -> std::optional> { + return get(key, [](mapped_type& v) { return std::ref(v); }); } // Returns the result R of a unary operation F on (a constant or mutable reference to) the value @@ -144,11 +146,11 @@ class SmallMap final { // // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); // - // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z'); - // assert(map.find('c', [](char& c) { c = std::toupper(c); })); + // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); + // assert(map.get('c', [](char& c) { c = std::toupper(c); })); // template > - auto find(const key_type& key, F f) const + auto get(const key_type& key, F f) const -> std::conditional_t, bool, std::optional> { for (auto& [k, v] : *this) { if (k == key) { @@ -165,12 +167,96 @@ class SmallMap final { } template - auto find(const key_type& key, F f) { - return std::as_const(*this).find( + auto get(const key_type& key, F f) { + return std::as_const(*this).get( key, [&f](const mapped_type& v) { return f(const_cast(v)); }); } + // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. + const_iterator find(const key_type& key) const { return const_cast(*this).find(key); } + iterator find(const key_type& key) { return find(key, begin()); } + + // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping, + // and whether the mapping was inserted. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. + // + template + std::pair try_emplace(const key_type& key, Args&&... args) { + if (const auto it = find(key); it != end()) { + return {it, false}; + } + + auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return {&ref, true}; + } + + // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator + // otherwise. + // + // The value is replaced via move constructor, so type V does not need to define copy/move + // assignment, e.g. its data members may be const. + // + // The arguments may directly or indirectly refer to the mapping being replaced. + // + // Iterators to the replaced mapping point to its replacement, and others remain valid. + // + template + iterator try_replace(const key_type& key, Args&&... args) { + const auto it = find(key); + if (it == end()) return it; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return it; + } + + // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or + // false on replace. + // + // The value is emplaced and replaced via move constructor, so type V does not need to define + // copy/move assignment, e.g. its data members may be const. + // + // On emplace, if the map reaches its static or dynamic capacity, then all iterators are + // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators + // to the replaced mapping point to its replacement, and others remain valid. + // + template + std::pair emplace_or_replace(const key_type& key, Args&&... args) { + const auto [it, ok] = try_emplace(key, std::forward(args)...); + if (ok) return {it, ok}; + map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return {it, ok}; + } + + // Removes a mapping if it exists, and returns whether it did. + // + // The last() and end() iterators, as well as those to the erased mapping, are invalidated. + // + bool erase(const key_type& key) { return erase(key, begin()); } + private: + iterator find(const key_type& key, iterator first) { + return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; }); + } + + bool erase(const key_type& key, iterator first) { + const auto it = find(key, first); + if (it == end()) return false; + map_.unstable_erase(it); + return true; + } + + void deduplicate() { + for (auto it = begin(); it != end();) { + if (const auto key = it->first; ++it != end()) { + while (erase(key, it)); + } + } + } + Map map_; }; @@ -186,7 +272,7 @@ bool operator==(const SmallMap& lhs, const SmallMap& rhs) { for (const auto& [k, v] : lhs) { const auto& lv = v; - if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { + if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { return false; } } diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index cb0ae359eb..0341435813 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -348,7 +348,7 @@ class SmallVector final : ArrayTraits, using Impl::pop_back; void unstable_erase(iterator it) { - if (it != last()) std::iter_swap(it, last()); + if (it != last()) replace(it, std::move(back())); pop_back(); } diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp index 323b9f91e7..2e81022f38 100644 --- a/libs/ftl/small_map_test.cpp +++ b/libs/ftl/small_map_test.cpp @@ -18,6 +18,9 @@ #include #include +#include + +using namespace std::string_literals; namespace android::test { @@ -35,16 +38,19 @@ TEST(SmallMap, Example) { EXPECT_TRUE(map.contains(123)); - EXPECT_EQ(map.find(42, [](const std::string& s) { return s.size(); }), 3u); + EXPECT_EQ(map.get(42, [](const std::string& s) { return s.size(); }), 3u); - const auto opt = map.find(-1); + const auto opt = map.get(-1); ASSERT_TRUE(opt); std::string& ref = *opt; EXPECT_TRUE(ref.empty()); ref = "xyz"; - EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc"))); + map.emplace_or_replace(0, "vanilla", 2u, 3u); + EXPECT_TRUE(map.dynamic()); + + EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); } TEST(SmallMap, Construct) { @@ -90,42 +96,253 @@ TEST(SmallMap, Construct) { } } +TEST(SmallMap, UniqueKeys) { + { + // Duplicate mappings are discarded. + const SmallMap map = ftl::init::map(1)(2)(3)(2)(3)(1)(3)(2)(1); + + EXPECT_EQ(map.size(), 3u); + EXPECT_EQ(map.max_size(), 9u); + + using Map = decltype(map); + EXPECT_EQ(map, Map(ftl::init::map(1, 0.f)(2, 0.f)(3, 0.f))); + } + { + // Duplicate mappings may be reordered. + const SmallMap map = ftl::init::map('a', 'A')( + 'b', 'B')('b')('b')('c', 'C')('a')('d')('c')('e', 'E')('d', 'D')('a')('f', 'F'); + + EXPECT_EQ(map.size(), 6u); + EXPECT_EQ(map.max_size(), 12u); + + using Map = decltype(map); + EXPECT_EQ(map, Map(ftl::init::map('a', 'A')('b', 'B')('c', 'C')('d', 'D')('e', 'E')('f', 'F'))); + } +} + TEST(SmallMap, Find) { { // Constant reference. - const ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); + const SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); - const auto opt = map.find('b'); + const auto opt = map.get('b'); EXPECT_EQ(opt, 'B'); const char d = 'D'; - const auto ref = map.find('d').value_or(std::cref(d)); + const auto ref = map.get('d').value_or(std::cref(d)); EXPECT_EQ(ref.get(), 'D'); } { // Mutable reference. - ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); + SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); - const auto opt = map.find('c'); + const auto opt = map.get('c'); EXPECT_EQ(opt, 'C'); char d = 'd'; - const auto ref = map.find('d').value_or(std::ref(d)); + const auto ref = map.get('d').value_or(std::ref(d)); ref.get() = 'D'; EXPECT_EQ(d, 'D'); } { // Constant unary operation. - const ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - EXPECT_EQ(map.find('c', [](char c) { return std::toupper(c); }), 'Z'); + const SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); + EXPECT_EQ(map.get('c', [](char c) { return std::toupper(c); }), 'Z'); } { // Mutable unary operation. - ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - EXPECT_TRUE(map.find('c', [](char& c) { c = std::toupper(c); })); + SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); + EXPECT_TRUE(map.get('c', [](char& c) { c = std::toupper(c); })); EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x'))); } } +TEST(SmallMap, TryEmplace) { + SmallMap map; + using Pair = decltype(map)::value_type; + + { + const auto [it, ok] = map.try_emplace(123, "abc"); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(123, "abc"s)); + } + { + const auto [it, ok] = map.try_emplace(42, 3u, '?'); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(42, "???"s)); + } + { + const auto [it, ok] = map.try_emplace(-1); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(-1, std::string())); + EXPECT_FALSE(map.dynamic()); + } + { + // Insertion fails if mapping exists. + const auto [it, ok] = map.try_emplace(42, "!!!"); + EXPECT_FALSE(ok); + EXPECT_EQ(*it, Pair(42, "???")); + EXPECT_FALSE(map.dynamic()); + } + { + // Insertion at capacity promotes the map. + const auto [it, ok] = map.try_emplace(999, "xyz"); + ASSERT_TRUE(ok); + EXPECT_EQ(*it, Pair(999, "xyz")); + EXPECT_TRUE(map.dynamic()); + } + + EXPECT_EQ(map, SmallMap(ftl::init::map(-1, ""s)(42, "???"s)(123, "abc"s)(999, "xyz"s))); +} + +namespace { + +// The mapped type does not require a copy/move assignment operator. +struct String { + template + String(Args... args) : str(args...) {} + const std::string str; + + bool operator==(const String& other) const { return other.str == str; } +}; + +} // namespace + +TEST(SmallMap, TryReplace) { + SmallMap map = ftl::init::map(1, "a")(2, "B"); + using Pair = decltype(map)::value_type; + + { + // Replacing fails unless mapping exists. + const auto it = map.try_replace(3, "c"); + EXPECT_EQ(it, map.end()); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); + ASSERT_TRUE(ref); + + // Construct std::string from one character. + const auto it = map.try_replace(2, 1u, static_cast(std::tolower(*ref))); + ASSERT_NE(it, map.end()); + EXPECT_EQ(*it, Pair(2, "b")); + } + + EXPECT_FALSE(map.dynamic()); + EXPECT_TRUE(map.try_emplace(3, "abc").second); + EXPECT_TRUE(map.try_emplace(4, "d").second); + EXPECT_TRUE(map.dynamic()); + + { + // Replacing fails unless mapping exists. + const auto it = map.try_replace(5, "e"); + EXPECT_EQ(it, map.end()); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(3); + ASSERT_TRUE(ref); + + // Construct std::string from substring. + const auto it = map.try_replace(3, ref->get().str, 2u, 1u); + ASSERT_NE(it, map.end()); + EXPECT_EQ(*it, Pair(3, "c")); + } + + EXPECT_EQ(map, SmallMap(ftl::init::map(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s))); +} + +TEST(SmallMap, EmplaceOrReplace) { + SmallMap map = ftl::init::map(1, "a")(2, "B"); + using Pair = decltype(map)::value_type; + + { + // New mapping is emplaced. + const auto [it, emplace] = map.emplace_or_replace(3, "c"); + EXPECT_TRUE(emplace); + EXPECT_EQ(*it, Pair(3, "c")); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); + ASSERT_TRUE(ref); + + // Construct std::string from one character. + const auto [it, emplace] = map.emplace_or_replace(2, 1u, static_cast(std::tolower(*ref))); + EXPECT_FALSE(emplace); + EXPECT_EQ(*it, Pair(2, "b")); + } + + EXPECT_FALSE(map.dynamic()); + EXPECT_FALSE(map.emplace_or_replace(3, "abc").second); // Replace. + EXPECT_TRUE(map.emplace_or_replace(4, "d").second); // Emplace. + EXPECT_TRUE(map.dynamic()); + + { + // New mapping is emplaced. + const auto [it, emplace] = map.emplace_or_replace(5, "e"); + EXPECT_TRUE(emplace); + EXPECT_EQ(*it, Pair(5, "e")); + } + { + // Replacement arguments can refer to the replaced mapping. + const auto ref = map.get(3); + ASSERT_TRUE(ref); + + // Construct std::string from substring. + const auto [it, emplace] = map.emplace_or_replace(3, ref->get().str, 2u, 1u); + EXPECT_FALSE(emplace); + EXPECT_EQ(*it, Pair(3, "c")); + } + + EXPECT_EQ(map, SmallMap(ftl::init::map(5, "e"s)(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s))); +} + +TEST(SmallMap, Erase) { + { + SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3')(4, '4'); + EXPECT_FALSE(map.dynamic()); + + EXPECT_FALSE(map.erase(0)); // Key not found. + + EXPECT_TRUE(map.erase(2)); + EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(1)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(4)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3'))); + + EXPECT_TRUE(map.erase(3)); + EXPECT_FALSE(map.erase(3)); // Key not found. + + EXPECT_TRUE(map.empty()); + EXPECT_FALSE(map.dynamic()); + } + { + SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3'); + map.try_emplace(4, '4'); + EXPECT_TRUE(map.dynamic()); + + EXPECT_FALSE(map.erase(0)); // Key not found. + + EXPECT_TRUE(map.erase(2)); + EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(1)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')(4, '4'))); + + EXPECT_TRUE(map.erase(4)); + EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3'))); + + EXPECT_TRUE(map.erase(3)); + EXPECT_FALSE(map.erase(3)); // Key not found. + + EXPECT_TRUE(map.empty()); + EXPECT_TRUE(map.dynamic()); + } +} + } // namespace android::test -- cgit v1.2.3-59-g8ed1b From 4188ffdbcf068eced5b64f77e96da96ee64de7e2 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sun, 7 Feb 2021 22:15:44 -0800 Subject: FTL: Add to_chars Wrap std::to_chars for a slightly faster alternative to std::to_string with optional radix. The upcoming ftl/{enum.h,flags.h} imported from IF will use the binary/ hex options, while SF will stringify display IDs for trace labels using the non-allocating version. Bug: 185536303 Test: ftl_test Change-Id: I587622763303d2baeb844e52eff55ce8f0bcbf1e --- include/ftl/string.h | 101 +++++++++++++++++++++++++ libs/ftl/Android.bp | 1 + libs/ftl/string_test.cpp | 187 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 include/ftl/string.h create mode 100644 libs/ftl/string_test.cpp (limited to 'include') diff --git a/include/ftl/string.h b/include/ftl/string.h new file mode 100644 index 0000000000..2d96b06a2f --- /dev/null +++ b/include/ftl/string.h @@ -0,0 +1,101 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace android::ftl { + +enum class Radix { kBin = 2, kDec = 10, kHex = 16 }; + +template +struct to_chars_length { + static_assert(std::is_integral_v); + // Maximum binary digits, plus minus sign and radix prefix. + static constexpr std::size_t value = std::numeric_limits>::digits + 3; +}; + +template +constexpr std::size_t to_chars_length_v = to_chars_length::value; + +template +using to_chars_buffer_t = char[to_chars_length_v]; + +// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with +// optional radix. See also ftl::to_string below. +// +// ftl::to_chars_buffer_t<> buffer; +// +// assert(ftl::to_chars(buffer, 123u) == "123"); +// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a"); +// +template +std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) { + static_assert(N >= to_chars_length_v); + + auto begin = buffer + 2; + const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast(radix)); + assert(err == std::errc()); + + if (radix == Radix::kDec) { + // TODO: Replace with {begin, end} in C++20. + return {begin, static_cast(end - begin)}; + } + + const auto prefix = radix == Radix::kBin ? 'b' : 'x'; + if constexpr (std::is_unsigned_v) { + buffer[0] = '0'; + buffer[1] = prefix; + } else { + if (*begin == '-') { + *buffer = '-'; + } else { + --begin; + } + + *begin-- = prefix; + *begin = '0'; + } + + // TODO: Replace with {buffer, end} in C++20. + return {buffer, static_cast(end - buffer)}; +} + +// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix. +// +// assert(ftl::to_string(123u) == "123"); +// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010"); +// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe"); +// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a"); +// +template +inline std::string to_string(T v, Radix radix = Radix::kDec) { + to_chars_buffer_t buffer; + return std::string(to_chars(buffer, v, radix)); +} + +std::string to_string(bool) = delete; +std::string to_string(bool, Radix) = delete; + +} // namespace android::ftl diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 97626bec7d..4226e32ee7 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -18,6 +18,7 @@ cc_test { "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", + "string_test.cpp", ], cflags: [ "-Wall", diff --git a/libs/ftl/string_test.cpp b/libs/ftl/string_test.cpp new file mode 100644 index 0000000000..f3d85c8319 --- /dev/null +++ b/libs/ftl/string_test.cpp @@ -0,0 +1,187 @@ +/* + * Copyright 2021 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 +#include + +#include +#include +#include +#include +#include +#include + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(String, ToChars) { + ftl::to_chars_buffer_t<> buffer; + + EXPECT_EQ(ftl::to_chars(buffer, 123u), "123"); + EXPECT_EQ(ftl::to_chars(buffer, -42, ftl::Radix::kBin), "-0b101010"); + EXPECT_EQ(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex), "0xcafe"); + EXPECT_EQ(ftl::to_chars(buffer, '*', ftl::Radix::kHex), "0x2a"); +} + +namespace { + +template +void ToCharsTest() { + constexpr auto kRadix = F::kRadix; + + using Limits = std::numeric_limits; + constexpr auto kMin = Limits::min(); + constexpr auto kMax = Limits::max(); + constexpr auto kNeg = static_cast(-42); + constexpr auto kPos = static_cast(123); + + ftl::to_chars_buffer_t buffer; + + EXPECT_EQ(ftl::to_chars(buffer, kMin, kRadix), F{}(kMin)); + EXPECT_EQ(ftl::to_chars(buffer, kMax, kRadix), F{}(kMax)); + EXPECT_EQ(ftl::to_chars(buffer, kNeg, kRadix), F{}(kNeg)); + EXPECT_EQ(ftl::to_chars(buffer, kPos, kRadix), F{}(kPos)); +} + +template +struct Types {}; + +template +struct ToCharsTests; + +template +struct ToCharsTests> { + static void test() { + ToCharsTest(); + ToCharsTests>::test(); + } +}; + +template +struct ToCharsTests> { + static void test() {} +}; + +template > +U to_unsigned(std::ostream& stream, T v) { + if (std::is_same_v) return v; + + if (v < 0) { + stream << '-'; + return std::numeric_limits::max() - static_cast(v) + 1; + } else { + return static_cast(v); + } +} + +struct Bin { + static constexpr auto kRadix = ftl::Radix::kBin; + + template + std::string operator()(T v) const { + std::ostringstream stream; + auto u = to_unsigned(stream, v); + stream << "0b"; + + if (u == 0) { + stream << 0; + } else { + std::ostringstream digits; + do { + digits << (u & 1); + } while (u >>= 1); + + const auto str = digits.str(); + std::copy(str.rbegin(), str.rend(), std::ostream_iterator(stream)); + } + + return stream.str(); + } +}; + +struct Dec { + static constexpr auto kRadix = ftl::Radix::kDec; + + template + std::string operator()(T v) const { + return std::to_string(v); + } +}; + +struct Hex { + static constexpr auto kRadix = ftl::Radix::kHex; + + template + std::string operator()(T v) const { + std::ostringstream stream; + const auto u = to_unsigned(stream, v); + stream << "0x" << std::hex << std::nouppercase; + stream << (sizeof(T) == 1 ? static_cast(u) : u); + return stream.str(); + } +}; + +using IntegerTypes = + Types; + +} // namespace + +TEST(String, ToCharsBin) { + ToCharsTests::test(); + + { + const std::uint8_t x = 0b1111'1111; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kBin), "0b11111111"); + } + { + const std::int16_t x = -0b1000'0000'0000'0000; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kBin), "-0b1000000000000000"); + } +} + +TEST(String, ToCharsDec) { + ToCharsTests::test(); + + { + const std::uint32_t x = UINT32_MAX; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x), "4294967295"); + } + { + const std::int32_t x = INT32_MIN; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x), "-2147483648"); + } +} + +TEST(String, ToCharsHex) { + ToCharsTests::test(); + + { + const std::uint16_t x = 0xfade; + ftl::to_chars_buffer_t buffer; + EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kHex), "0xfade"); + } + { + ftl::to_chars_buffer_t<> buffer; + EXPECT_EQ(ftl::to_chars(buffer, INT64_MIN, ftl::Radix::kHex), "-0x8000000000000000"); + } +} + +} // namespace android::test -- cgit v1.2.3-59-g8ed1b From 9f5e5dbcb31032fc729501805ed548d80abad115 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 25 May 2021 12:52:24 -0700 Subject: FTL: Add cast safety checker Add a function to check cast safety, to be used by a saturating cast that (among other uses) will replace ui::Size::clamp, which invokes the undefined behavior of signed overflow when casting INT32_MAX to float and back. Bug: 185536303 Test: ftl_test Change-Id: I412a1d72de7235b73ea3dd3f194d0da178ce5eb2 --- include/ftl/cast.h | 84 +++++++++++++++++++ include/ftl/details/cast.h | 57 +++++++++++++ libs/ftl/Android.bp | 1 + libs/ftl/cast_test.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 342 insertions(+) create mode 100644 include/ftl/cast.h create mode 100644 include/ftl/details/cast.h create mode 100644 libs/ftl/cast_test.cpp (limited to 'include') diff --git a/include/ftl/cast.h b/include/ftl/cast.h new file mode 100644 index 0000000000..ff1b58ad56 --- /dev/null +++ b/include/ftl/cast.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include +#include + +#include + +namespace android::ftl { + +enum class CastSafety { kSafe, kUnderflow, kOverflow }; + +// Returns whether static_cast(v) is safe, or would result in underflow or overflow. +// +// static_assert(ftl::cast_safety(-1) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety(128u) == ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety(-.1f) == ftl::CastSafety::kUnderflow); +// static_assert(ftl::cast_safety(static_cast(INT32_MAX)) == +// ftl::CastSafety::kOverflow); +// +// static_assert(ftl::cast_safety(-DBL_MAX) == ftl::CastSafety::kUnderflow); +// +template +constexpr CastSafety cast_safety(T v) { + static_assert(std::is_arithmetic_v); + static_assert(std::is_arithmetic_v); + + constexpr bool kFromSigned = std::is_signed_v; + constexpr bool kToSigned = std::is_signed_v; + + using details::max_exponent; + + // If the R range contains the T range, then casting is always safe. + if constexpr ((kFromSigned == kToSigned && max_exponent >= max_exponent) || + (!kFromSigned && kToSigned && max_exponent > max_exponent)) { + return CastSafety::kSafe; + } + + using C = std::common_type_t; + + if constexpr (kFromSigned) { + using L = details::safe_limits; + + if constexpr (kToSigned) { + // Signed to signed. + if (v < L::lowest()) return CastSafety::kUnderflow; + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } else { + // Signed to unsigned. + if (v < 0) return CastSafety::kUnderflow; + return static_cast(v) <= static_cast(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } + } else { + using L = std::numeric_limits; + + if constexpr (kToSigned) { + // Unsigned to signed. + return static_cast(v) <= static_cast(L::max()) ? CastSafety::kSafe + : CastSafety::kOverflow; + } else { + // Unsigned to unsigned. + return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow; + } + } +} + +} // namespace android::ftl diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h new file mode 100644 index 0000000000..87b9f1e20a --- /dev/null +++ b/include/ftl/details/cast.h @@ -0,0 +1,57 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include +#include + +namespace android::ftl::details { + +// Exponent whose power of 2 is the (exclusive) upper bound of T. +template > +constexpr int max_exponent = std::is_floating_point_v ? L::max_exponent : L::digits; + +// Extension of std::numeric_limits that reduces the maximum for integral types T such that it +// has an exact representation for floating-point types F. For example, the maximum int32_t value +// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot +// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is +// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the +// minimum is representable. +template +struct safe_limits : std::numeric_limits { + static constexpr T max() { + using Base = std::numeric_limits; + + if constexpr (std::is_integral_v && std::is_floating_point_v) { + // Assume the mantissa is 24 bits for float, or 53 bits for double. + using Float = std::numeric_limits; + static_assert(Float::is_iec559); + + // If the integer is wider than the mantissa, clear the excess bits of precision. + constexpr int kShift = Base::digits - Float::digits; + if constexpr (kShift > 0) { + using U = std::make_unsigned_t; + constexpr U kOne = static_cast(1); + return static_cast(Base::max()) & ~((kOne << kShift) - kOne); + } + } + + return Base::max(); + } +}; + +} // namespace android::ftl::details diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 97626bec7d..22267912b9 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,6 +14,7 @@ cc_test { address: true, }, srcs: [ + "cast_test.cpp", "future_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", diff --git a/libs/ftl/cast_test.cpp b/libs/ftl/cast_test.cpp new file mode 100644 index 0000000000..2abcb8fe66 --- /dev/null +++ b/libs/ftl/cast_test.cpp @@ -0,0 +1,200 @@ +/* + * Copyright 2021 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 +#include + +#include +#include +#include + +namespace android::test { + +using ftl::cast_safety; +using ftl::CastSafety; + +template +constexpr T min = std::numeric_limits::lowest(); + +template +constexpr T max = std::numeric_limits::max(); + +template +constexpr T inf = std::numeric_limits::infinity(); + +template +constexpr T NaN = std::numeric_limits::quiet_NaN(); + +// Keep in sync with example usage in header file. + +static_assert(cast_safety(-1) == CastSafety::kUnderflow); +static_assert(cast_safety(128u) == CastSafety::kOverflow); + +static_assert(cast_safety(-.1f) == CastSafety::kUnderflow); +static_assert(cast_safety(static_cast(INT32_MAX)) == CastSafety::kOverflow); + +static_assert(cast_safety(-DBL_MAX) == CastSafety::kUnderflow); + +// Unsigned to unsigned. + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(max) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(max) + 1) == + CastSafety::kOverflow); + +// Unsigned to signed. + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(max) - 1) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max) + 1) == + CastSafety::kOverflow); + +// Signed to unsigned. + +static_assert(cast_safety(0) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +static_assert(cast_safety(-1) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(max) - 1) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max) + 1) == + CastSafety::kOverflow); + +// Signed to signed. + +static_assert(cast_safety(-129) == CastSafety::kUnderflow); +static_assert(cast_safety(-128) == CastSafety::kSafe); +static_assert(cast_safety(127) == CastSafety::kSafe); +static_assert(cast_safety(128) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +// Float to float. + +static_assert(cast_safety(max) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kSafe); + +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +TEST(CastSafety, FloatToFloat) { + EXPECT_EQ(cast_safety(std::nexttoward(static_cast(min), min)), + CastSafety::kUnderflow); + EXPECT_EQ(cast_safety(std::nexttoward(static_cast(max), max)), + CastSafety::kOverflow); +} + +// Unsigned to float. + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +static_assert(cast_safety(0u) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +// Signed to float. + +static_assert(cast_safety(min) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +static_assert(cast_safety(min) == CastSafety::kSafe); +static_assert(cast_safety(max) == CastSafety::kSafe); + +// Float to unsigned. + +static_assert(cast_safety(0.f) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); +static_assert(cast_safety(-.1f) == CastSafety::kUnderflow); + +static_assert(cast_safety(-inf) == CastSafety::kUnderflow); +static_assert(cast_safety(inf) == CastSafety::kOverflow); +static_assert(cast_safety(NaN) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(0.0) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); +static_assert(cast_safety(-.1) == CastSafety::kUnderflow); + +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); + +// Float to signed. + +static_assert(cast_safety(0.f) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(-inf) == CastSafety::kUnderflow); +static_assert(cast_safety(inf) == CastSafety::kOverflow); +static_assert(cast_safety(NaN) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); + +static_assert(cast_safety(0.0) == CastSafety::kSafe); +static_assert(cast_safety(min) == CastSafety::kUnderflow); +static_assert(cast_safety(max) == CastSafety::kOverflow); + +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); +static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); +static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); + +TEST(CastSafety, FloatToSigned) { + constexpr int32_t kMax = ftl::details::safe_limits::max(); + static_assert(kMax == 2'147'483'520); + EXPECT_EQ(kMax, static_cast(std::nexttowardf(max, 0))); + + EXPECT_EQ(cast_safety(std::nexttowardf(min, 0)), CastSafety::kSafe); + EXPECT_EQ(cast_safety(std::nexttowardf(max, 0)), CastSafety::kSafe); + EXPECT_EQ(cast_safety(std::nexttoward(min, 0)), CastSafety::kSafe); + EXPECT_EQ(cast_safety(std::nexttoward(max, 0)), CastSafety::kSafe); + + EXPECT_EQ(cast_safety(std::nexttowardf(min, min)), + CastSafety::kUnderflow); + EXPECT_EQ(cast_safety(std::nexttowardf(max, max)), + CastSafety::kOverflow); + EXPECT_EQ(cast_safety(std::nexttoward(min, min)), + CastSafety::kUnderflow); + EXPECT_EQ(cast_safety(std::nexttoward(max, max)), + CastSafety::kOverflow); +} + +} // namespace android::test -- cgit v1.2.3-59-g8ed1b From 98318de954ba00293cfd179266f09f266dc1c82b Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 19 May 2021 16:45:23 -0500 Subject: Renamed and moved InputWindow and related files In preparation for the hierarchy listener interface, moved the InputWindow structs into libgui and have libinput dependant on libgui. Also renamed InputWindow to exclude Input since it will be used for more generic purposes. Test: Builds and flashes Bug: 188792659 Change-Id: I24262cbc14d409c00273de0024a672394a959e5f --- include/ftl/Flags.h | 280 ++++++++++++++++++++ include/ftl/NamedEnum.h | 125 +++++++++ include/input/DisplayViewport.h | 3 +- include/input/Flags.h | 283 --------------------- include/input/Input.h | 15 -- include/input/InputApplication.h | 85 ------- include/input/InputWindow.h | 279 -------------------- include/input/NamedEnum.h | 128 ---------- libs/ftl/Android.bp | 10 + libs/ftl/Flags_test.cpp | 227 +++++++++++++++++ libs/ftl/NamedEnum_test.cpp | 101 ++++++++ libs/gui/Android.bp | 56 +++- libs/gui/BLASTBufferQueue.cpp | 6 +- libs/gui/LayerState.cpp | 27 +- libs/gui/SurfaceComposerClient.cpp | 16 +- libs/gui/WindowInfo.cpp | 223 ++++++++++++++++ libs/gui/android/gui/FocusRequest.aidl | 45 ++++ libs/gui/android/gui/InputApplicationInfo.aidl | 23 ++ libs/gui/android/gui/TouchOcclusionMode.aidl | 47 ++++ libs/gui/android/gui/WindowInfo.aidl | 19 ++ libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/InputApplication.h | 79 ++++++ libs/gui/include/gui/LayerState.h | 14 +- libs/gui/include/gui/SurfaceComposerClient.h | 6 +- libs/gui/include/gui/WindowInfo.h | 273 ++++++++++++++++++++ libs/gui/include/gui/constants.h | 37 +++ libs/gui/tests/Android.bp | 1 + libs/gui/tests/EndToEndNativeInputTest.cpp | 27 +- libs/gui/tests/WindowInfo_test.cpp | 133 ++++++++++ libs/input/Android.bp | 14 +- libs/input/Input.cpp | 1 + libs/input/InputDevice.cpp | 2 +- libs/input/InputTransport.cpp | 2 +- libs/input/InputWindow.cpp | 224 ---------------- libs/input/KeyCharacterMap.cpp | 5 +- libs/input/KeyLayoutMap.cpp | 2 +- libs/input/android/FocusRequest.aidl | 45 ---- libs/input/android/InputApplicationInfo.aidl | 23 -- libs/input/android/InputWindowInfo.aidl | 20 -- libs/input/android/os/IInputFlinger.aidl | 6 +- libs/input/android/os/TouchOcclusionMode.aidl | 47 ---- libs/input/tests/Android.bp | 10 +- libs/input/tests/Flags_test.cpp | 227 ----------------- libs/input/tests/InputEvent_test.cpp | 24 +- .../input/tests/InputPublisherAndConsumer_test.cpp | 1 + libs/input/tests/InputWindow_test.cpp | 129 ---------- libs/input/tests/NamedEnum_test.cpp | 101 -------- libs/input/tests/VelocityTracker_test.cpp | 7 +- libs/input/tests/VerifiedInputEvent_test.cpp | 8 +- libs/nativedisplay/AChoreographer.cpp | 1 - services/inputflinger/InputManager.cpp | 16 +- services/inputflinger/InputManager.h | 4 +- services/inputflinger/InputReaderBase.cpp | 2 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 11 +- services/inputflinger/dispatcher/DragState.cpp | 2 - services/inputflinger/dispatcher/DragState.h | 10 +- services/inputflinger/dispatcher/Entry.h | 2 +- services/inputflinger/dispatcher/FocusResolver.cpp | 15 +- services/inputflinger/dispatcher/FocusResolver.h | 18 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 233 ++++++++--------- services/inputflinger/dispatcher/InputDispatcher.h | 90 ++++--- services/inputflinger/dispatcher/InputTarget.h | 3 +- services/inputflinger/dispatcher/TouchState.cpp | 11 +- services/inputflinger/dispatcher/TouchState.h | 12 +- services/inputflinger/dispatcher/TouchedWindow.h | 6 +- .../dispatcher/include/InputDispatcherInterface.h | 11 +- .../include/InputDispatcherPolicyInterface.h | 2 +- services/inputflinger/host/InputFlinger.h | 4 +- services/inputflinger/reader/InputDevice.cpp | 2 +- .../reader/controller/PeripheralController.cpp | 2 +- services/inputflinger/reader/include/EventHub.h | 2 +- services/inputflinger/reader/include/InputDevice.h | 2 +- .../reader/mapper/TouchInputMapper.cpp | 2 +- services/inputflinger/tests/Android.bp | 1 + services/inputflinger/tests/FocusResolver_test.cpp | 19 +- .../inputflinger/tests/IInputFlingerQuery.aidl | 6 +- .../tests/InputClassifierConverter_test.cpp | 2 +- .../inputflinger/tests/InputClassifier_test.cpp | 1 + .../inputflinger/tests/InputDispatcher_test.cpp | 149 +++++------ .../tests/InputFlingerService_test.cpp | 52 ++-- services/inputflinger/tests/InputReader_test.cpp | 1 + services/surfaceflinger/Android.bp | 1 - services/surfaceflinger/BufferLayer.cpp | 4 +- .../compositionengine/impl/planner/LayerState.h | 2 +- services/surfaceflinger/Layer.cpp | 24 +- services/surfaceflinger/Layer.h | 18 +- services/surfaceflinger/LayerProtoHelper.cpp | 7 +- services/surfaceflinger/LayerProtoHelper.h | 4 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- .../tests/RefreshRateOverlay_test.cpp | 4 + .../surfaceflinger/tests/utils/CallbackUtils.h | 4 + 92 files changed, 2158 insertions(+), 2088 deletions(-) create mode 100644 include/ftl/Flags.h create mode 100644 include/ftl/NamedEnum.h delete mode 100644 include/input/Flags.h delete mode 100644 include/input/InputApplication.h delete mode 100644 include/input/InputWindow.h delete mode 100644 include/input/NamedEnum.h create mode 100644 libs/ftl/Flags_test.cpp create mode 100644 libs/ftl/NamedEnum_test.cpp create mode 100644 libs/gui/WindowInfo.cpp create mode 100644 libs/gui/android/gui/FocusRequest.aidl create mode 100644 libs/gui/android/gui/InputApplicationInfo.aidl create mode 100644 libs/gui/android/gui/TouchOcclusionMode.aidl create mode 100644 libs/gui/android/gui/WindowInfo.aidl create mode 100644 libs/gui/include/gui/InputApplication.h create mode 100644 libs/gui/include/gui/WindowInfo.h create mode 100644 libs/gui/include/gui/constants.h create mode 100644 libs/gui/tests/WindowInfo_test.cpp delete mode 100644 libs/input/InputWindow.cpp delete mode 100644 libs/input/android/FocusRequest.aidl delete mode 100644 libs/input/android/InputApplicationInfo.aidl delete mode 100644 libs/input/android/InputWindowInfo.aidl delete mode 100644 libs/input/android/os/TouchOcclusionMode.aidl delete mode 100644 libs/input/tests/Flags_test.cpp delete mode 100644 libs/input/tests/InputWindow_test.cpp delete mode 100644 libs/input/tests/NamedEnum_test.cpp (limited to 'include') diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h new file mode 100644 index 0000000000..27c84769cb --- /dev/null +++ b/include/ftl/Flags.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2020 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 + +#include +#include +#include +#include +#include + +#include +#include "utils/BitSet.h" + +#pragma once + +namespace android { + +namespace details { + +template +inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__; + +template +constexpr auto generate_flag_values(std::integer_sequence seq) { + constexpr size_t count = seq.size(); + + std::array values{}; + for (size_t i = 0, v = 0; v < count; ++i) { + values[v++] = static_cast(T{1} << i); + } + + return values; +} + +template +inline constexpr auto flag_values = generate_flag_values( + std::make_integer_sequence, flag_count>{}); + +template +constexpr auto generate_flag_names(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + {enum_value_name[I]>()...}}; +} + +template +inline constexpr auto flag_names = + generate_flag_names(std::make_index_sequence>{}); + +// A trait for determining whether a type is specifically an enum class or not. +template > +struct is_enum_class : std::false_type {}; + +// By definition, an enum class is an enum that is not implicitly convertible to its underlying +// type. +template +struct is_enum_class + : std::bool_constant>> {}; + +template +inline constexpr bool is_enum_class_v = is_enum_class::value; +} // namespace details + +template +constexpr auto flag_name() { + using F = decltype(V); + return details::enum_value_name(); +} + +template +constexpr std::optional flag_name(F flag) { + using U = std::underlying_type_t; + auto idx = static_cast(__builtin_ctzl(static_cast(flag))); + return details::flag_names[idx]; +} + +/* A class for handling flags defined by an enum or enum class in a type-safe way. */ +template +class Flags { + // F must be an enum or its underlying type is undefined. Theoretically we could specialize this + // further to avoid this restriction but in general we want to encourage the use of enums + // anyways. + static_assert(std::is_enum_v, "Flags type must be an enum"); + using U = typename std::underlying_type_t; + +public: + constexpr Flags(F f) : mFlags(static_cast(f)) {} + constexpr Flags() : mFlags(0) {} + constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} + + // Provide a non-explicit construct for non-enum classes since they easily convert to their + // underlying types (e.g. when used with bitwise operators). For enum classes, however, we + // should force them to be explicitly constructed from their underlying types to make full use + // of the type checker. + template + constexpr Flags(T t, typename std::enable_if_t, T>* = nullptr) + : mFlags(t) {} + template + explicit constexpr Flags(T t, + typename std::enable_if_t, T>* = nullptr) + : mFlags(t) {} + + class Iterator { + // The type can't be larger than 64-bits otherwise it won't fit in BitSet64. + static_assert(sizeof(U) <= sizeof(uint64_t)); + + public: + Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } + Iterator() : mRemainingFlags(0), mCurrFlag(static_cast(0)) {} + + // Pre-fix ++ + Iterator& operator++() { + if (mRemainingFlags.isEmpty()) { + mCurrFlag = static_cast(0); + } else { + uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left + const U flag = 1 << (64 - bit - 1); + mCurrFlag = static_cast(flag); + } + return *this; + } + + // Post-fix ++ + Iterator operator++(int) { + Iterator iter = *this; + ++*this; + return iter; + } + + bool operator==(Iterator other) const { + return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; + } + + bool operator!=(Iterator other) const { return !(*this == other); } + + F operator*() { return mCurrFlag; } + + // iterator traits + + // In the future we could make this a bidirectional const iterator instead of a forward + // iterator but it doesn't seem worth the added complexity at this point. This could not, + // however, be made a non-const iterator as assigning one flag to another is a non-sensical + // operation. + using iterator_category = std::input_iterator_tag; + using value_type = F; + // Per the C++ spec, because input iterators are not assignable the iterator's reference + // type does not actually need to be a reference. In fact, making it a reference would imply + // that modifying it would change the underlying Flags object, which is obviously wrong for + // the same reason this can't be a non-const iterator. + using reference = F; + using difference_type = void; + using pointer = void; + + private: + BitSet64 mRemainingFlags; + F mCurrFlag; + }; + + /* + * Tests whether the given flag is set. + */ + bool test(F flag) const { + U f = static_cast(flag); + return (f & mFlags) == f; + } + + /* Tests whether any of the given flags are set */ + bool any(Flags f) { return (mFlags & f.mFlags) != 0; } + + /* Tests whether all of the given flags are set */ + bool all(Flags f) { return (mFlags & f.mFlags) == f.mFlags; } + + Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } + Flags& operator|=(Flags rhs) { + mFlags = mFlags | rhs.mFlags; + return *this; + } + + Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } + Flags& operator&=(Flags rhs) { + mFlags = mFlags & rhs.mFlags; + return *this; + } + + Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } + Flags& operator^=(Flags rhs) { + mFlags = mFlags ^ rhs.mFlags; + return *this; + } + + Flags operator~() { return static_cast(~mFlags); } + + bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } + bool operator!=(Flags rhs) const { return !operator==(rhs); } + + Flags& operator=(const Flags& rhs) { + mFlags = rhs.mFlags; + return *this; + } + + Iterator begin() const { return Iterator(*this); } + + Iterator end() const { return Iterator(); } + + /* + * Returns the stored set of flags. + * + * Note that this returns the underlying type rather than the base enum class. This is because + * the value is no longer necessarily a strict member of the enum since the returned value could + * be multiple enum variants OR'd together. + */ + U get() const { return mFlags; } + + std::string string() const { + std::string result; + bool first = true; + U unstringified = 0; + for (const F f : *this) { + std::optional flagString = flag_name(f); + if (flagString) { + appendFlag(result, flagString.value(), first); + } else { + unstringified |= static_cast(f); + } + } + + if (unstringified != 0) { + appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); + } + + if (first) { + result += "0x0"; + } + + return result; + } + +private: + U mFlags; + + static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { + if (first) { + first = false; + } else { + str += " | "; + } + str += flag; + } +}; + +// This namespace provides operator overloads for enum classes to make it easier to work with them +// as flags. In order to use these, add them via a `using namespace` declaration. +namespace flag_operators { + +template >> +inline Flags operator~(F f) { + using U = typename std::underlying_type_t; + return static_cast(~static_cast(f)); +} +template >> +Flags operator|(F lhs, F rhs) { + using U = typename std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +} // namespace flag_operators +} // namespace android diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h new file mode 100644 index 0000000000..f50ff46fe2 --- /dev/null +++ b/include/ftl/NamedEnum.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 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 + +#include +#include +#include +#include + +#pragma once + +namespace android { + +namespace details { +template +constexpr std::optional enum_value_name() { + // Should look something like (but all on one line): + // std::optional + // android::details::enum_value_name() + // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] + std::string_view view = __PRETTY_FUNCTION__; + size_t templateStart = view.rfind("["); + size_t templateEnd = view.rfind("]"); + if (templateStart == std::string::npos || templateEnd == std::string::npos) { + return std::nullopt; + } + + // Extract the template parameters without the enclosing braces. + // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE + view = view.substr(templateStart + 1, templateEnd - templateStart - 1); + size_t valStart = view.rfind("V = "); + if (valStart == std::string::npos) { + return std::nullopt; + } + + // Example (cont'd): V = android::test::TestEnums::ONE + view = view.substr(valStart); + size_t nameStart = view.rfind("::"); + if (nameStart == std::string::npos) { + return std::nullopt; + } + + // Chop off the initial "::" + nameStart += 2; + return view.substr(nameStart); +} + +template +constexpr auto generate_enum_values(std::integer_sequence seq) { + constexpr size_t count = seq.size(); + + std::array values{}; + for (size_t i = 0, v = 0; v < count; ++i) { + values[v++] = static_cast(T{0} + i); + } + + return values; +} + +template +inline constexpr auto enum_values = + generate_enum_values(std::make_integer_sequence, N>{}); + +template +constexpr auto generate_enum_names(std::index_sequence) noexcept { + return std::array, sizeof...(I)>{ + {enum_value_name[I]>()...}}; +} + +template +inline constexpr auto enum_names = generate_enum_names(std::make_index_sequence{}); + +} // namespace details + +class NamedEnum { +public: + // By default allowed enum value range is 0 ~ 7. + template + static constexpr size_t max = 8; + + template + static constexpr auto enum_name() { + using E = decltype(V); + return details::enum_value_name(); + } + + template + static constexpr std::optional enum_name(E val) { + auto idx = static_cast(val); + return idx < max ? details::enum_names>[idx] : std::nullopt; + } + + // Helper function for parsing enum value to string. + // Example : enum class TestEnums { ZERO = 0x0 }; + // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". + // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, + // it should be declared to specialized the maximum enum by below: + // template <> constexpr size_t NamedEnum::max = 16; + // If the enum class definition is sparse and contains enum values starting from a large value, + // Do not specialize it to a large number to avoid performance issues. + // The recommended maximum enum number to specialize is 64. + template + static const std::string string(E val, const char* fallbackFormat = "%02d") { + std::string result; + std::optional enumString = enum_name(val); + result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); + return result; + } +}; + +} // namespace android diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 5e40ca7ece..a6213f3ddd 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,8 +18,9 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include +#include +#include #include -#include #include #include diff --git a/include/input/Flags.h b/include/input/Flags.h deleted file mode 100644 index b12a9ed2c5..0000000000 --- a/include/input/Flags.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2020 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 - -#include -#include -#include -#include -#include - -#include "NamedEnum.h" -#include "utils/BitSet.h" - -#ifndef __UI_INPUT_FLAGS_H -#define __UI_INPUT_FLAGS_H - -namespace android { - -namespace details { - -template -inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__; - -template -constexpr auto generate_flag_values(std::integer_sequence seq) { - constexpr size_t count = seq.size(); - - std::array values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast(T{1} << i); - } - - return values; -} - -template -inline constexpr auto flag_values = generate_flag_values( - std::make_integer_sequence, flag_count>{}); - -template -constexpr auto generate_flag_names(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {enum_value_name[I]>()...}}; -} - -template -inline constexpr auto flag_names = - generate_flag_names(std::make_index_sequence>{}); - -// A trait for determining whether a type is specifically an enum class or not. -template > -struct is_enum_class : std::false_type {}; - -// By definition, an enum class is an enum that is not implicitly convertible to its underlying -// type. -template -struct is_enum_class - : std::bool_constant>> {}; - -template -inline constexpr bool is_enum_class_v = is_enum_class::value; -} // namespace details - -template -constexpr auto flag_name() { - using F = decltype(V); - return details::enum_value_name(); -} - -template -constexpr std::optional flag_name(F flag) { - using U = std::underlying_type_t; - auto idx = static_cast(__builtin_ctzl(static_cast(flag))); - return details::flag_names[idx]; -} - -/* A class for handling flags defined by an enum or enum class in a type-safe way. */ -template -class Flags { - // F must be an enum or its underlying type is undefined. Theoretically we could specialize this - // further to avoid this restriction but in general we want to encourage the use of enums - // anyways. - static_assert(std::is_enum_v, "Flags type must be an enum"); - using U = typename std::underlying_type_t; - -public: - constexpr Flags(F f) : mFlags(static_cast(f)) {} - constexpr Flags() : mFlags(0) {} - constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} - - // Provide a non-explicit construct for non-enum classes since they easily convert to their - // underlying types (e.g. when used with bitwise operators). For enum classes, however, we - // should force them to be explicitly constructed from their underlying types to make full use - // of the type checker. - template - constexpr Flags(T t, typename std::enable_if_t, T>* = nullptr) - : mFlags(t) {} - template - explicit constexpr Flags(T t, - typename std::enable_if_t, T>* = nullptr) - : mFlags(t) {} - - class Iterator { - // The type can't be larger than 64-bits otherwise it won't fit in BitSet64. - static_assert(sizeof(U) <= sizeof(uint64_t)); - - public: - Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } - Iterator() : mRemainingFlags(0), mCurrFlag(static_cast(0)) {} - - // Pre-fix ++ - Iterator& operator++() { - if (mRemainingFlags.isEmpty()) { - mCurrFlag = static_cast(0); - } else { - uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left - const U flag = 1 << (64 - bit - 1); - mCurrFlag = static_cast(flag); - } - return *this; - } - - // Post-fix ++ - Iterator operator++(int) { - Iterator iter = *this; - ++*this; - return iter; - } - - bool operator==(Iterator other) const { - return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; - } - - bool operator!=(Iterator other) const { return !(*this == other); } - - F operator*() { return mCurrFlag; } - - // iterator traits - - // In the future we could make this a bidirectional const iterator instead of a forward - // iterator but it doesn't seem worth the added complexity at this point. This could not, - // however, be made a non-const iterator as assigning one flag to another is a non-sensical - // operation. - using iterator_category = std::input_iterator_tag; - using value_type = F; - // Per the C++ spec, because input iterators are not assignable the iterator's reference - // type does not actually need to be a reference. In fact, making it a reference would imply - // that modifying it would change the underlying Flags object, which is obviously wrong for - // the same reason this can't be a non-const iterator. - using reference = F; - using difference_type = void; - using pointer = void; - - private: - BitSet64 mRemainingFlags; - F mCurrFlag; - }; - - /* - * Tests whether the given flag is set. - */ - bool test(F flag) const { - U f = static_cast(flag); - return (f & mFlags) == f; - } - - /* Tests whether any of the given flags are set */ - bool any(Flags f) { return (mFlags & f.mFlags) != 0; } - - /* Tests whether all of the given flags are set */ - bool all(Flags f) { return (mFlags & f.mFlags) == f.mFlags; } - - Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } - Flags& operator|=(Flags rhs) { - mFlags = mFlags | rhs.mFlags; - return *this; - } - - Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } - Flags& operator&=(Flags rhs) { - mFlags = mFlags & rhs.mFlags; - return *this; - } - - Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } - Flags& operator^=(Flags rhs) { - mFlags = mFlags ^ rhs.mFlags; - return *this; - } - - Flags operator~() { return static_cast(~mFlags); } - - bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } - bool operator!=(Flags rhs) const { return !operator==(rhs); } - - Flags& operator=(const Flags& rhs) { - mFlags = rhs.mFlags; - return *this; - } - - Iterator begin() const { return Iterator(*this); } - - Iterator end() const { return Iterator(); } - - /* - * Returns the stored set of flags. - * - * Note that this returns the underlying type rather than the base enum class. This is because - * the value is no longer necessarily a strict member of the enum since the returned value could - * be multiple enum variants OR'd together. - */ - U get() const { return mFlags; } - - std::string string() const { - std::string result; - bool first = true; - U unstringified = 0; - for (const F f : *this) { - std::optional flagString = flag_name(f); - if (flagString) { - appendFlag(result, flagString.value(), first); - } else { - unstringified |= static_cast(f); - } - } - - if (unstringified != 0) { - appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); - } - - if (first) { - result += "0x0"; - } - - return result; - } - -private: - U mFlags; - - static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { - if (first) { - first = false; - } else { - str += " | "; - } - str += flag; - } -}; - -// This namespace provides operator overloads for enum classes to make it easier to work with them -// as flags. In order to use these, add them via a `using namespace` declaration. -namespace flag_operators { - -template >> -inline Flags operator~(F f) { - using U = typename std::underlying_type_t; - return static_cast(~static_cast(f)); -} -template >> -Flags operator|(F lhs, F rhs) { - using U = typename std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -} // namespace flag_operators -} // namespace android - -#endif // __UI_INPUT_FLAGS_H diff --git a/include/input/Input.h b/include/input/Input.h index 438121b30e..3bac7636e7 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -105,15 +105,6 @@ constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = */ constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20; -enum { - /* Used when a motion event is not associated with any display. - * Typically used for non-pointer events. */ - ADISPLAY_ID_NONE = -1, - - /* The default display id. */ - ADISPLAY_ID_DEFAULT = 0, -}; - enum { /* * Indicates that an input device has switches. @@ -338,12 +329,6 @@ private: */ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits::quiet_NaN(); -/** - * Invalid value for display size. Used when display size isn't available for an event or doesn't - * matter. This is just a constant 0 so that it has no effect if unused. - */ -constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0; - /* * Pointer coordinate data. */ diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h deleted file mode 100644 index 8e4fe796a5..0000000000 --- a/include/input/InputApplication.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef _UI_INPUT_APPLICATION_H -#define _UI_INPUT_APPLICATION_H - -#include - -#include - -#include -#include -#include - -#include -#include -#include - -namespace android { -/* - * Handle for an application that can receive input. - * - * Used by the native input dispatcher as a handle for the window manager objects - * that describe an application. - */ -class InputApplicationHandle { -public: - inline const InputApplicationInfo* getInfo() const { - return &mInfo; - } - - inline std::string getName() const { - return !mInfo.name.empty() ? mInfo.name : ""; - } - - inline std::chrono::nanoseconds getDispatchingTimeout( - std::chrono::nanoseconds defaultValue) const { - return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis) - : defaultValue; - } - - inline sp getApplicationToken() const { - return mInfo.token; - } - - bool operator==(const InputApplicationHandle& other) const { - return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); - } - - bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - -protected: - InputApplicationHandle() = default; - virtual ~InputApplicationHandle() = default; - - InputApplicationInfo mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_APPLICATION_H diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h deleted file mode 100644 index 121be6d963..0000000000 --- a/include/input/InputWindow.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "InputApplication.h" - -using android::os::TouchOcclusionMode; - -namespace android { - -/* - * Describes the properties of a window that can receive input. - */ -struct InputWindowInfo : public Parcelable { - InputWindowInfo() = default; - - // Window flags from WindowManager.LayoutParams - enum class Flag : uint32_t { - ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - DIM_BEHIND = 0x00000002, - BLUR_BEHIND = 0x00000004, - NOT_FOCUSABLE = 0x00000008, - NOT_TOUCHABLE = 0x00000010, - NOT_TOUCH_MODAL = 0x00000020, - TOUCHABLE_WHEN_WAKING = 0x00000040, - KEEP_SCREEN_ON = 0x00000080, - LAYOUT_IN_SCREEN = 0x00000100, - LAYOUT_NO_LIMITS = 0x00000200, - FULLSCREEN = 0x00000400, - FORCE_NOT_FULLSCREEN = 0x00000800, - DITHER = 0x00001000, - SECURE = 0x00002000, - SCALED = 0x00004000, - IGNORE_CHEEK_PRESSES = 0x00008000, - LAYOUT_INSET_DECOR = 0x00010000, - ALT_FOCUSABLE_IM = 0x00020000, - WATCH_OUTSIDE_TOUCH = 0x00040000, - SHOW_WHEN_LOCKED = 0x00080000, - SHOW_WALLPAPER = 0x00100000, - TURN_SCREEN_ON = 0x00200000, - DISMISS_KEYGUARD = 0x00400000, - SPLIT_TOUCH = 0x00800000, - HARDWARE_ACCELERATED = 0x01000000, - LAYOUT_IN_OVERSCAN = 0x02000000, - TRANSLUCENT_STATUS = 0x04000000, - TRANSLUCENT_NAVIGATION = 0x08000000, - LOCAL_FOCUS_MODE = 0x10000000, - SLIPPERY = 0x20000000, - LAYOUT_ATTACHED_IN_DECOR = 0x40000000, - DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000, - }; // Window types from WindowManager.LayoutParams - - enum class Type : int32_t { - UNKNOWN = 0, - FIRST_APPLICATION_WINDOW = 1, - BASE_APPLICATION = 1, - APPLICATION = 2, - APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - APPLICATION_PANEL = FIRST_SUB_WINDOW, - APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1, - APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2, - APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, - APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - STATUS_BAR = FIRST_SYSTEM_WINDOW, - SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, - PHONE = FIRST_SYSTEM_WINDOW + 2, - SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, - KEYGUARD = FIRST_SYSTEM_WINDOW + 4, - TOAST = FIRST_SYSTEM_WINDOW + 5, - SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, - PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, - SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, - KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, - SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, - INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, - INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, - WALLPAPER = FIRST_SYSTEM_WINDOW + 13, - STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, - SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, - DRAG = FIRST_SYSTEM_WINDOW + 16, - STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, - POINTER = FIRST_SYSTEM_WINDOW + 18, - NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, - VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, - BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, - INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, - NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, - MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, - ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, - DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, - ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39, - NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, - LAST_SYSTEM_WINDOW = 2999, - }; - - enum class Feature { - DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - NO_INPUT_CHANNEL = 0x00000002, - DISABLE_USER_ACTIVITY = 0x00000004, - }; - - /* These values are filled in by the WM and passed through SurfaceFlinger - * unless specified otherwise. - */ - // This value should NOT be used to uniquely identify the window. There may be different - // input windows that have the same token. - sp token; - // This uniquely identifies the input window. - int32_t id = -1; - std::string name; - Flags flags; - Type type = Type::UNKNOWN; - std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); - - /* These values are filled in by SurfaceFlinger. */ - int32_t frameLeft = -1; - int32_t frameTop = -1; - int32_t frameRight = -1; - int32_t frameBottom = -1; - - /* - * SurfaceFlinger consumes this value to shrink the computed frame. This is - * different from shrinking the touchable region in that it DOES shift the coordinate - * space where-as the touchable region does not and is more like "cropping". This - * is used for window shadows. - */ - int32_t surfaceInset = 0; - - // A global scaling factor for all windows. Unlike windowScaleX/Y this results - // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis. - float globalScaleFactor = 1.0f; - - // The opacity of this window, from 0.0 to 1.0 (inclusive). - // An alpha of 1.0 means fully opaque and 0.0 means fully transparent. - float alpha; - - // Transform applied to individual windows. - ui::Transform transform; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE; - - /* - * This is filled in by the WM relative to the frame and then translated - * to absolute coordinates by SurfaceFlinger once the frame is computed. - */ - Region touchableRegion; - bool visible = false; - bool focusable = false; - bool hasWallpaper = false; - bool paused = false; - /* This flag is set when the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool trustedOverlay = false; - TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED; - int32_t ownerPid = -1; - int32_t ownerUid = -1; - std::string packageName; - Flags inputFeatures; - int32_t displayId = ADISPLAY_ID_NONE; - int32_t portalToDisplayId = ADISPLAY_ID_NONE; - InputApplicationInfo applicationInfo; - bool replaceTouchableRegionWithCrop = false; - wp touchableRegionCropHandle; - - void addTouchableRegion(const Rect& region); - - bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - - bool frameContainsPoint(int32_t x, int32_t y) const; - - bool supportsSplitTouch() const; - - bool overlaps(const InputWindowInfo* other) const; - - bool operator==(const InputWindowInfo& inputChannel) const; - - status_t writeToParcel(android::Parcel* parcel) const override; - - status_t readFromParcel(const android::Parcel* parcel) override; -}; - -/* - * Handle for a window that can receive input. - * - * Used by the native input dispatcher to indirectly refer to the window manager objects - * that describe a window. - */ -class InputWindowHandle : public RefBase { -public: - explicit InputWindowHandle(); - InputWindowHandle(const InputWindowHandle& other); - InputWindowHandle(const InputWindowInfo& other); - - inline const InputWindowInfo* getInfo() const { return &mInfo; } - - sp getToken() const; - - int32_t getId() const { return mInfo.id; } - - sp getApplicationToken() { return mInfo.applicationInfo.token; } - - inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : ""; } - - inline std::chrono::nanoseconds getDispatchingTimeout( - std::chrono::nanoseconds defaultValue) const { - return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * As this class is created as RefBase object, no pure virtual function is allowed. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() { return false; } - - /** - * Updates from another input window handle. - */ - void updateFrom(const sp handle); - - /** - * Releases the channel used by the associated information when it is - * no longer needed. - */ - void releaseChannel(); - - // Not override since this class is not derrived from Parcelable. - status_t readFromParcel(const android::Parcel* parcel); - status_t writeToParcel(android::Parcel* parcel) const; - -protected: - virtual ~InputWindowHandle(); - - InputWindowInfo mInfo; -}; -} // namespace android - -#endif // _UI_INPUT_WINDOW_H diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h deleted file mode 100644 index 6562348701..0000000000 --- a/include/input/NamedEnum.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 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 - -#include -#include -#include -#include - -#ifndef __UI_INPUT_NAMEDENUM_H -#define __UI_INPUT_NAMEDENUM_H - -namespace android { - -namespace details { -template -constexpr std::optional enum_value_name() { - // Should look something like (but all on one line): - // std::optional - // android::details::enum_value_name() - // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] - std::string_view view = __PRETTY_FUNCTION__; - size_t templateStart = view.rfind("["); - size_t templateEnd = view.rfind("]"); - if (templateStart == std::string::npos || templateEnd == std::string::npos) { - return std::nullopt; - } - - // Extract the template parameters without the enclosing braces. - // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE - view = view.substr(templateStart + 1, templateEnd - templateStart - 1); - size_t valStart = view.rfind("V = "); - if (valStart == std::string::npos) { - return std::nullopt; - } - - // Example (cont'd): V = android::test::TestEnums::ONE - view = view.substr(valStart); - size_t nameStart = view.rfind("::"); - if (nameStart == std::string::npos) { - return std::nullopt; - } - - // Chop off the initial "::" - nameStart += 2; - return view.substr(nameStart); -} - -template -constexpr auto generate_enum_values(std::integer_sequence seq) { - constexpr size_t count = seq.size(); - - std::array values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast(T{0} + i); - } - - return values; -} - -template -inline constexpr auto enum_values = - generate_enum_values(std::make_integer_sequence, N>{}); - -template -constexpr auto generate_enum_names(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {enum_value_name[I]>()...}}; -} - -template -inline constexpr auto enum_names = generate_enum_names(std::make_index_sequence{}); - -} // namespace details - -class NamedEnum { -public: - // By default allowed enum value range is 0 ~ 7. - template - static constexpr size_t max = 8; - - template - static constexpr auto enum_name() { - using E = decltype(V); - return details::enum_value_name(); - } - - template - static constexpr std::optional enum_name(E val) { - auto idx = static_cast(val); - return idx < max ? details::enum_names>[idx] : std::nullopt; - } - - // Helper function for parsing enum value to string. - // Example : enum class TestEnums { ZERO = 0x0 }; - // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". - // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, - // it should be declared to specialized the maximum enum by below: - // template <> constexpr size_t NamedEnum::max = 16; - // If the enum class definition is sparse and contains enum values starting from a large value, - // Do not specialize it to a large number to avoid performance issues. - // The recommended maximum enum number to specialize is 64. - template - static const std::string string(E val, const char* fallbackFormat = "%02d") { - std::string result; - std::optional enumString = enum_name(val); - result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); - return result; - } -}; - -} // namespace android - -#endif // __UI_INPUT_NAMEDENUM_H \ No newline at end of file diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 436620350a..3026921044 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -15,7 +15,9 @@ cc_test { }, srcs: [ "cast_test.cpp", + "Flags_test.cpp", "future_test.cpp", + "NamedEnum_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", @@ -27,4 +29,12 @@ cc_test { "-Wextra", "-Wpedantic", ], + + header_libs: [ + "libbase_headers", + ], + + shared_libs: [ + "libbase", + ], } diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp new file mode 100644 index 0000000000..8c00b5299b --- /dev/null +++ b/libs/ftl/Flags_test.cpp @@ -0,0 +1,227 @@ +/* + * Copyright 2020 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 +#include + +#include + +namespace android::test { + +using namespace android::flag_operators; + +enum class TestFlags { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; + +TEST(Flags, Test) { + Flags flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); + ASSERT_FALSE(flags.test(TestFlags::THREE)); +} + +TEST(Flags, Any) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.any(TestFlags::ONE)); + ASSERT_TRUE(flags.any(TestFlags::TWO)); + ASSERT_FALSE(flags.any(TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO)); + ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, All) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.all(TestFlags::ONE)); + ASSERT_TRUE(flags.all(TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::THREE)); + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, DefaultConstructor_hasNoFlagsSet) { + Flags flags; + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) { + Flags flags; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) { + Flags flags = TestFlags::TWO; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withNewFlag) { + Flags flags = TestFlags::ONE; + Flags flags2 = flags | TestFlags::TWO; + ASSERT_FALSE(flags2.test(TestFlags::THREE)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags flags2 = flags | TestFlags::THREE; + ASSERT_FALSE(flags2.test(TestFlags::TWO)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE)); +} + +TEST(Flags, OrEqualsOperator_withNewFlag) { + Flags flags; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.test(TestFlags::THREE)); + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrEqualsOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withOneSetFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::THREE; + ASSERT_TRUE(andFlags.test(TestFlags::THREE)); + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withMultipleSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & (TestFlags::ONE | TestFlags::THREE); + ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(andFlags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withNoSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::TWO; + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, Equality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags1, flags2); +} + +TEST(Flags, Inequality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::THREE; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, EqualsOperator) { + Flags flags; + flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, EqualsOperator_DontShareState) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = flags1; + ASSERT_EQ(flags1, flags2); + + flags1 &= TestFlags::TWO; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, GetValue) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.get(), 0x3); +} + +TEST(Flags, String_NoFlags) { + Flags flags; + ASSERT_EQ(flags.string(), "0x0"); +} + +TEST(Flags, String_KnownValues) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.string(), "ONE | TWO"); +} + +TEST(Flags, String_UnknownValues) { + auto flags = Flags(0b1011); + ASSERT_EQ(flags.string(), "ONE | TWO | 0x00000008"); +} + +TEST(FlagsIterator, IteratesOverAllFlags) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2; + for (TestFlags f : flags1) { + flags2 |= f; + } + ASSERT_EQ(flags2, flags1); +} + +TEST(FlagsIterator, IteratesInExpectedOrder) { + const std::vector flagOrder = {TestFlags::ONE, TestFlags::TWO}; + Flags flags; + for (TestFlags f : flagOrder) { + flags |= f; + } + + size_t idx = 0; + auto iter = flags.begin(); + while (iter != flags.end() && idx < flagOrder.size()) { + // Make sure the order is what we expect + ASSERT_EQ(*iter, flagOrder[idx]); + iter++; + idx++; + } + ASSERT_EQ(iter, flags.end()); +} +TEST(FlagsIterator, PostFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*(iter++), TestFlags::ONE); + ASSERT_EQ(*iter, TestFlags::TWO); + ASSERT_EQ(*(iter++), TestFlags::TWO); + ASSERT_EQ(iter, flags.end()); +} + +TEST(FlagsIterator, PreFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*++iter, TestFlags::TWO); + ASSERT_EQ(++iter, flags.end()); +} + +TEST(FlagNames, RuntimeFlagName) { + TestFlags f = TestFlags::ONE; + ASSERT_EQ(flag_name(f), "ONE"); +} + +TEST(FlagNames, RuntimeUnknownFlagName) { + TestFlags f = static_cast(0x8); + ASSERT_EQ(flag_name(f), std::nullopt); +} + +TEST(FlagNames, CompileTimeFlagName) { + static_assert(flag_name() == "TWO"); +} + +} // namespace android::test \ No newline at end of file diff --git a/libs/ftl/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp new file mode 100644 index 0000000000..dff2b8aaa1 --- /dev/null +++ b/libs/ftl/NamedEnum_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2020 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 +#include + +namespace android { + +// Test enum class maximum enum value smaller than default maximum of 8. +enum class TestEnums { ZERO = 0x0, ONE = 0x1, TWO = 0x2, THREE = 0x3, SEVEN = 0x7 }; +// Big enum contains enum values greater than default maximum of 8. +enum class TestBigEnums { ZERO = 0x0, FIFTEEN = 0xF }; + +// Declared to specialize the maximum enum since the enum size exceeds 8 by default. +template <> +constexpr size_t NamedEnum::max = 16; + +namespace test { +using android::TestBigEnums; +using android::TestEnums; + +TEST(NamedEnum, RuntimeNamedEnum) { + TestEnums e = TestEnums::ZERO; + ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); + + e = TestEnums::ONE; + ASSERT_EQ(NamedEnum::enum_name(e), "ONE"); + + e = TestEnums::THREE; + ASSERT_EQ(NamedEnum::enum_name(e), "THREE"); + + e = TestEnums::SEVEN; + ASSERT_EQ(NamedEnum::enum_name(e), "SEVEN"); +} + +// Test big enum +TEST(NamedEnum, RuntimeBigNamedEnum) { + TestBigEnums e = TestBigEnums::ZERO; + ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); + + e = TestBigEnums::FIFTEEN; + ASSERT_EQ(NamedEnum::enum_name(e), "FIFTEEN"); +} + +TEST(NamedEnum, RuntimeNamedEnumAsString) { + TestEnums e = TestEnums::ZERO; + ASSERT_EQ(NamedEnum::string(e), "ZERO"); + + e = TestEnums::ONE; + ASSERT_EQ(NamedEnum::string(e), "ONE"); + + e = TestEnums::THREE; + ASSERT_EQ(NamedEnum::string(e), "THREE"); + + e = TestEnums::SEVEN; + ASSERT_EQ(NamedEnum::string(e), "SEVEN"); +} + +TEST(NamedEnum, RuntimeBigNamedEnumAsString) { + TestBigEnums e = TestBigEnums::ZERO; + ASSERT_EQ(NamedEnum::string(e), "ZERO"); + + e = TestBigEnums::FIFTEEN; + ASSERT_EQ(NamedEnum::string(e), "FIFTEEN"); +} + +TEST(NamedEnum, RuntimeUnknownNamedEnum) { + TestEnums e = static_cast(0x5); + ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); + e = static_cast(0x9); + ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); +} + +TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) { + TestEnums e = static_cast(0x5); + ASSERT_EQ(NamedEnum::string(e), "05"); + e = static_cast(0x9); + ASSERT_EQ(NamedEnum::string(e, "0x%08x"), "0x00000009"); +} + +TEST(NamedEnum, CompileTimeFlagName) { + static_assert(NamedEnum::enum_name() == "TWO"); + static_assert(NamedEnum::enum_name() == "THREE"); +} + +} // namespace test + +} // namespace android diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 64203f78a8..2d8fff91da 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -51,6 +51,51 @@ cc_library_headers { ], } +// AIDL files that should be exposed to java +filegroup { + name: "guiconstants_aidl", + srcs: [ + "android/**/TouchOcclusionMode.aidl", + ], +} + +cc_library_static { + name: "libgui_window_info_static", + vendor_available: true, + host_supported: true, + srcs: [ + ":guiconstants_aidl", + "android/gui/FocusRequest.aidl", + "android/gui/InputApplicationInfo.aidl", + "android/gui/WindowInfo.aidl", + "WindowInfo.cpp", + ], + + shared_libs: [ + "libbinder", + ], + + local_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "libbinder", + ], + + static_libs: [ + "libui-types", + ], + + aidl: { + export_aidl_headers: true + }, + + include_dirs: [ + "frameworks/native/include", + ], +} + filegroup { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], @@ -77,12 +122,15 @@ cc_library_static { "libbinder", ], + static_libs: [ + "libui-types", + ], + aidl: { export_aidl_headers: true } } - cc_library_shared { name: "libgui", vendor_available: true, @@ -96,9 +144,11 @@ cc_library_shared { static_libs: [ "libgui_aidl_static", + "libgui_window_info_static", ], export_static_lib_headers: [ "libgui_aidl_static", + "libgui_window_info_static", ], srcs: [ @@ -150,13 +200,11 @@ cc_library_shared { "libbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. - "libinput", "libpdx_default_transport", ], export_shared_lib_headers: [ "libbinder", - "libinput", ], export_header_lib_headers: [ @@ -168,7 +216,6 @@ cc_library_shared { vendor: { cflags: [ "-DNO_BUFFERHUB", - "-DNO_INPUT", ], exclude_srcs: [ "BufferHubConsumer.cpp", @@ -178,7 +225,6 @@ cc_library_shared { "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", - "libinput", "libpdx_default_transport", ], }, diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 29701168e7..dbb1cb0c17 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -38,7 +38,7 @@ using namespace std::chrono_literals; namespace { -inline const char* toString(bool b) { +inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace @@ -513,7 +513,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" " graphicBufferId=%" PRIu64 "%s", - mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), + mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), bufferItem.mAutoRefresh ? " mAutoRefresh" : ""); @@ -543,7 +543,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - toString(nextTransactionSet)); + boolToString(nextTransactionSet)); processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index d102e07623..001570c391 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -31,6 +31,9 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfoHandle; + layer_state_t::layer_state_t() : what(0), x(0), @@ -94,9 +97,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, color.r); SAFE_PARCEL(output.writeFloat, color.g); SAFE_PARCEL(output.writeFloat, color.b); -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->writeToParcel, &output); -#endif + SAFE_PARCEL(windowInfoHandle->writeToParcel, &output); SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); @@ -205,9 +206,7 @@ status_t layer_state_t::read(const Parcel& input) color.g = tmpFloat; SAFE_PARCEL(input.readFloat, &tmpFloat); color.b = tmpFloat; -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->readFromParcel, &input); -#endif + SAFE_PARCEL(windowInfoHandle->readFromParcel, &input); SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); @@ -491,14 +490,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eHasListenerCallbacksChanged) { what |= eHasListenerCallbacksChanged; } - -#ifndef NO_INPUT if (other.what & eInputInfoChanged) { what |= eInputInfoChanged; - inputHandle = new InputWindowHandle(*other.inputHandle); + windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle); } -#endif - if (other.what & eCachedBufferChanged) { what |= eCachedBufferChanged; cachedBuffer = other.cachedBuffer; @@ -589,11 +584,9 @@ status_t layer_state_t::matrix22_t::read(const Parcel& input) { bool InputWindowCommands::merge(const InputWindowCommands& other) { bool changes = false; -#ifndef NO_INPUT changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); -#endif changes |= other.syncInputWindows && !syncInputWindows; syncInputWindows |= other.syncInputWindows; return changes; @@ -601,31 +594,23 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { bool InputWindowCommands::empty() const { bool empty = true; -#ifndef NO_INPUT empty = focusRequests.empty() && !syncInputWindows; -#endif return empty; } void InputWindowCommands::clear() { -#ifndef NO_INPUT focusRequests.clear(); -#endif syncInputWindows = false; } status_t InputWindowCommands::write(Parcel& output) const { -#ifndef NO_INPUT SAFE_PARCEL(output.writeParcelableVector, focusRequests); -#endif SAFE_PARCEL(output.writeBool, syncInputWindows); return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { -#ifndef NO_INPUT SAFE_PARCEL(input.readParcelableVector, &focusRequests); -#endif SAFE_PARCEL(input.readBool, &syncInputWindows); return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3118c72276..ec03c2105b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -39,14 +39,11 @@ #include #include #include +#include #include #include #include -#ifndef NO_INPUT -#include -#endif - #include // This server size should always be smaller than the server cache size @@ -54,6 +51,9 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfo; +using gui::WindowInfoHandle; using ui::ColorMode; // --------------------------------------------------------------------------- @@ -1491,16 +1491,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } -#ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( - const sp& sc, - const InputWindowInfo& info) { + const sp& sc, const WindowInfo& info) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->inputHandle = new InputWindowHandle(info); + s->windowInfoHandle = new WindowInfoHandle(info); s->what |= layer_state_t::eInputInfoChanged; return *this; } @@ -1516,8 +1514,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInpu return *this; } -#endif - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform( const sp& sc, const mat3& matrix, const vec3& translation) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp new file mode 100644 index 0000000000..ff0bb8aa55 --- /dev/null +++ b/libs/gui/WindowInfo.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2011 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 +#define LOG_TAG "WindowInfo" +#define LOG_NDEBUG 0 + +#include +#include +#include + +#include + +namespace android::gui { + +// --- WindowInfo --- +void WindowInfo::addTouchableRegion(const Rect& region) { + touchableRegion.orSelf(region); +} + +bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x, y); +} + +bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; +} + +bool WindowInfo::supportsSplitTouch() const { + return flags.test(Flag::SPLIT_TOUCH); +} + +bool WindowInfo::overlaps(const WindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft && + frameTop < other->frameBottom && frameBottom > other->frameTop; +} + +bool WindowInfo::operator==(const WindowInfo& info) const { + return info.token == token && info.id == id && info.name == name && info.flags == flags && + info.type == type && info.dispatchingTimeout == dispatchingTimeout && + info.frameLeft == frameLeft && info.frameTop == frameTop && + info.frameRight == frameRight && info.frameBottom == frameBottom && + info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && + info.transform == transform && info.displayWidth == displayWidth && + info.displayHeight == displayHeight && + info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && + info.trustedOverlay == trustedOverlay && info.focusable == focusable && + info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && + info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.packageName == packageName && info.inputFeatures == inputFeatures && + info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && + info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && + info.applicationInfo == applicationInfo; +} + +status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + if (name.empty()) { + parcel->writeInt32(0); + return OK; + } + parcel->writeInt32(1); + + // clang-format off + status_t status = parcel->writeStrongBinder(token) ?: + parcel->writeInt64(dispatchingTimeout.count()) ?: + parcel->writeInt32(id) ?: + parcel->writeUtf8AsUtf16(name) ?: + parcel->writeInt32(flags.get()) ?: + parcel->writeInt32(static_cast>(type)) ?: + parcel->writeInt32(frameLeft) ?: + parcel->writeInt32(frameTop) ?: + parcel->writeInt32(frameRight) ?: + parcel->writeInt32(frameBottom) ?: + parcel->writeInt32(surfaceInset) ?: + parcel->writeFloat(globalScaleFactor) ?: + parcel->writeFloat(alpha) ?: + parcel->writeFloat(transform.dsdx()) ?: + parcel->writeFloat(transform.dtdx()) ?: + parcel->writeFloat(transform.tx()) ?: + parcel->writeFloat(transform.dtdy()) ?: + parcel->writeFloat(transform.dsdy()) ?: + parcel->writeFloat(transform.ty()) ?: + parcel->writeInt32(displayWidth) ?: + parcel->writeInt32(displayHeight) ?: + parcel->writeBool(visible) ?: + parcel->writeBool(focusable) ?: + parcel->writeBool(hasWallpaper) ?: + parcel->writeBool(paused) ?: + parcel->writeBool(trustedOverlay) ?: + parcel->writeInt32(static_cast(touchOcclusionMode)) ?: + parcel->writeInt32(ownerPid) ?: + parcel->writeInt32(ownerUid) ?: + parcel->writeUtf8AsUtf16(packageName) ?: + parcel->writeInt32(inputFeatures.get()) ?: + parcel->writeInt32(displayId) ?: + parcel->writeInt32(portalToDisplayId) ?: + applicationInfo.writeToParcel(parcel) ?: + parcel->write(touchableRegion) ?: + parcel->writeBool(replaceTouchableRegionWithCrop) ?: + parcel->writeStrongBinder(touchableRegionCropHandle.promote()); + // clang-format on + return status; +} + +status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + if (parcel->readInt32() == 0) { + return OK; + } + + token = parcel->readStrongBinder(); + dispatchingTimeout = static_cast(parcel->readInt64()); + status_t status = parcel->readInt32(&id) ?: parcel->readUtf8FromUtf16(&name); + if (status != OK) { + return status; + } + + flags = Flags(parcel->readInt32()); + type = static_cast(parcel->readInt32()); + float dsdx, dtdx, tx, dtdy, dsdy, ty; + int32_t touchOcclusionModeInt; + // clang-format off + status = parcel->readInt32(&frameLeft) ?: + parcel->readInt32(&frameTop) ?: + parcel->readInt32(&frameRight) ?: + parcel->readInt32(&frameBottom) ?: + parcel->readInt32(&surfaceInset) ?: + parcel->readFloat(&globalScaleFactor) ?: + parcel->readFloat(&alpha) ?: + parcel->readFloat(&dsdx) ?: + parcel->readFloat(&dtdx) ?: + parcel->readFloat(&tx) ?: + parcel->readFloat(&dtdy) ?: + parcel->readFloat(&dsdy) ?: + parcel->readFloat(&ty) ?: + parcel->readInt32(&displayWidth) ?: + parcel->readInt32(&displayHeight) ?: + parcel->readBool(&visible) ?: + parcel->readBool(&focusable) ?: + parcel->readBool(&hasWallpaper) ?: + parcel->readBool(&paused) ?: + parcel->readBool(&trustedOverlay) ?: + parcel->readInt32(&touchOcclusionModeInt) ?: + parcel->readInt32(&ownerPid) ?: + parcel->readInt32(&ownerUid) ?: + parcel->readUtf8FromUtf16(&packageName); + // clang-format on + + if (status != OK) { + return status; + } + + touchOcclusionMode = static_cast(touchOcclusionModeInt); + + inputFeatures = Flags(parcel->readInt32()); + // clang-format off + status = parcel->readInt32(&displayId) ?: + parcel->readInt32(&portalToDisplayId) ?: + applicationInfo.readFromParcel(parcel) ?: + parcel->read(touchableRegion) ?: + parcel->readBool(&replaceTouchableRegionWithCrop); + // clang-format on + + if (status != OK) { + return status; + } + + touchableRegionCropHandle = parcel->readStrongBinder(); + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +// --- WindowInfoHandle --- + +WindowInfoHandle::WindowInfoHandle() {} + +WindowInfoHandle::~WindowInfoHandle() {} + +WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {} + +WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {} + +status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const { + return mInfo.writeToParcel(parcel); +} + +status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) { + return mInfo.readFromParcel(parcel); +} + +void WindowInfoHandle::releaseChannel() { + mInfo.token.clear(); +} + +sp WindowInfoHandle::getToken() const { + return mInfo.token; +} + +void WindowInfoHandle::updateFrom(sp handle) { + mInfo = handle->mInfo; +} +} // namespace android::gui diff --git a/libs/gui/android/gui/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl new file mode 100644 index 0000000000..90186351c5 --- /dev/null +++ b/libs/gui/android/gui/FocusRequest.aidl @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2020, 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. + */ + +package android.gui; + +/** @hide */ +parcelable FocusRequest { + /** + * Input channel token used to identify the window that should gain focus. + */ + IBinder token; + @utf8InCpp String windowName; + /** + * The token that the caller expects currently to be focused. If the + * specified token does not match the currently focused window, this request will be dropped. + * If the specified focused token matches the currently focused window, the call will succeed. + * Set this to "null" if this call should succeed no matter what the currently focused token + * is. + */ + @nullable IBinder focusedToken; + @utf8InCpp String focusedWindowName; + /** + * SYSTEM_TIME_MONOTONIC timestamp in nanos set by the client (wm) when requesting the focus + * change. This determines which request gets precedence if there is a focus change request + * from another source such as pointer down. + */ + long timestamp; + /** + * Display id associated with this request. + */ + int displayId; +} diff --git a/libs/gui/android/gui/InputApplicationInfo.aidl b/libs/gui/android/gui/InputApplicationInfo.aidl new file mode 100644 index 0000000000..c0fd666543 --- /dev/null +++ b/libs/gui/android/gui/InputApplicationInfo.aidl @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2020, 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. + */ + +package android.gui; + +parcelable InputApplicationInfo { + @nullable IBinder token; + @utf8InCpp String name; + long dispatchingTimeoutMillis; +} diff --git a/libs/gui/android/gui/TouchOcclusionMode.aidl b/libs/gui/android/gui/TouchOcclusionMode.aidl new file mode 100644 index 0000000000..d91d052135 --- /dev/null +++ b/libs/gui/android/gui/TouchOcclusionMode.aidl @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2020, 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. + */ + +package android.gui; + + +/** + * Touch occlusion modes: These modes represent how windows are taken into + * consideration in order to decide whether to block obscured touches or + * not. + * + * @hide + */ +@Backing(type="int") +enum TouchOcclusionMode { + /** + * Touches that pass through this window will be blocked if they are + * consumed by a different UID and this window is not trusted. + */ + BLOCK_UNTRUSTED, + + /** + * The window's opacity will be taken into consideration for touch + * occlusion rules if the touch passes through it and the window is not + * trusted. + */ + USE_OPACITY, + + /** + * The window won't count for touch occlusion rules if the touch passes + * through it. + */ + ALLOW +} diff --git a/libs/gui/android/gui/WindowInfo.aidl b/libs/gui/android/gui/WindowInfo.aidl new file mode 100644 index 0000000000..2c85d155a8 --- /dev/null +++ b/libs/gui/android/gui/WindowInfo.aidl @@ -0,0 +1,19 @@ +/* +** Copyright 2020, 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. +*/ + +package android.gui; + +parcelable WindowInfo cpp_header "gui/WindowInfo.h"; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 8ec7e6d630..c0a2335885 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/libs/gui/include/gui/InputApplication.h b/libs/gui/include/gui/InputApplication.h new file mode 100644 index 0000000000..679c2a1754 --- /dev/null +++ b/libs/gui/include/gui/InputApplication.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _UI_INPUT_APPLICATION_H +#define _UI_INPUT_APPLICATION_H + +#include + +#include + +#include +#include +#include + +#include +#include + +namespace android { + +/* + * Handle for an application that can receive input. + * + * Used by the native input dispatcher as a handle for the window manager objects + * that describe an application. + */ +class InputApplicationHandle { +public: + inline const gui::InputApplicationInfo* getInfo() const { return &mInfo; } + + inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : ""; } + + inline std::chrono::nanoseconds getDispatchingTimeout( + std::chrono::nanoseconds defaultValue) const { + return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis) + : defaultValue; + } + + inline sp getApplicationToken() const { return mInfo.token; } + + bool operator==(const InputApplicationHandle& other) const { + return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); + } + + bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); } + + /** + * Requests that the state of this object be updated to reflect + * the most current available information about the application. + * + * This method should only be called from within the input dispatcher's + * critical section. + * + * Returns true on success, or false if the handle is no longer valid. + */ + virtual bool updateInfo() = 0; + +protected: + InputApplicationHandle() = default; + virtual ~InputApplicationHandle() = default; + + gui::InputApplicationInfo mInfo; +}; + +} // namespace android + +#endif // _UI_INPUT_APPLICATION_H diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 7961f4bd07..92de74a414 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,14 +26,12 @@ #include #include -#ifndef NO_INPUT -#include -#include (flag))); - return details::flag_names[idx]; -} - /* A class for handling flags defined by an enum or enum class in a type-safe way. */ template class Flags { @@ -94,7 +37,7 @@ class Flags { // further to avoid this restriction but in general we want to encourage the use of enums // anyways. static_assert(std::is_enum_v, "Flags type must be an enum"); - using U = typename std::underlying_type_t; + using U = std::underlying_type_t; public: constexpr Flags(F f) : mFlags(static_cast(f)) {} @@ -106,11 +49,10 @@ public: // should force them to be explicitly constructed from their underlying types to make full use // of the type checker. template - constexpr Flags(T t, typename std::enable_if_t, T>* = nullptr) - : mFlags(t) {} + constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} + template - explicit constexpr Flags(T t, - typename std::enable_if_t, T>* = nullptr) + explicit constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} class Iterator { @@ -229,16 +171,16 @@ public: bool first = true; U unstringified = 0; for (const F f : *this) { - std::optional flagString = flag_name(f); - if (flagString) { - appendFlag(result, flagString.value(), first); + if (const auto flagName = ftl::flag_name(f)) { + appendFlag(result, flagName.value(), first); } else { unstringified |= static_cast(f); } } if (unstringified != 0) { - appendFlag(result, base::StringPrintf("0x%08x", unstringified), first); + constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex; + appendFlag(result, ftl::to_string(unstringified, radix), first); } if (first) { @@ -265,15 +207,14 @@ private: // as flags. In order to use these, add them via a `using namespace` declaration. namespace flag_operators { -template >> +template >> inline Flags operator~(F f) { - using U = typename std::underlying_type_t; - return static_cast(~static_cast(f)); + return static_cast(~ftl::enum_cast(f)); } -template >> + +template >> Flags operator|(F lhs, F rhs) { - using U = typename std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); + return static_cast(ftl::enum_cast(lhs) | ftl::enum_cast(rhs)); } } // namespace flag_operators diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h deleted file mode 100644 index 6e98feeb87..0000000000 --- a/include/ftl/NamedEnum.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2020 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 - -#include -#include -#include -#include - -#pragma once - -namespace android { - -namespace details { -template -constexpr std::optional enum_value_name() { - // Should look something like (but all on one line): - // std::optional - // android::details::enum_value_name() - // [E = android::test::TestEnums, V = android::test::TestEnums::ONE] - std::string_view view = __PRETTY_FUNCTION__; - size_t templateStart = view.rfind("["); - size_t templateEnd = view.rfind("]"); - if (templateStart == std::string::npos || templateEnd == std::string::npos) { - return std::nullopt; - } - - // Extract the template parameters without the enclosing braces. - // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE - view = view.substr(templateStart + 1, templateEnd - templateStart - 1); - size_t valStart = view.rfind("V = "); - if (valStart == std::string::npos) { - return std::nullopt; - } - - // Example (cont'd): V = android::test::TestEnums::ONE - view = view.substr(valStart); - // Check invalid enum values with cast, like V = (android::test::TestEnums)8. - if (view.find('(') != std::string::npos) { - return std::nullopt; - } - size_t nameStart = view.rfind("::"); - if (nameStart == std::string::npos) { - return std::nullopt; - } - - // Chop off the initial "::" - nameStart += 2; - return view.substr(nameStart); -} - -template -constexpr auto generate_enum_values(std::integer_sequence seq) { - constexpr size_t count = seq.size(); - - std::array values{}; - for (size_t i = 0, v = 0; v < count; ++i) { - values[v++] = static_cast(T{0} + i); - } - - return values; -} - -template -inline constexpr auto enum_values = - generate_enum_values(std::make_integer_sequence, N>{}); - -template -constexpr auto generate_enum_names(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{ - {enum_value_name[I]>()...}}; -} - -template -inline constexpr auto enum_names = generate_enum_names(std::make_index_sequence{}); - -} // namespace details - -class NamedEnum { -public: - // By default allowed enum value range is 0 ~ 7. - template - static constexpr size_t max = 8; - - template - static constexpr auto enum_name() { - using E = decltype(V); - return details::enum_value_name(); - } - - template - static constexpr std::optional enum_name(E val) { - auto idx = static_cast(val); - return idx < max ? details::enum_names>[idx] : std::nullopt; - } - - // Helper function for parsing enum value to string. - // Example : enum class TestEnums { ZERO = 0x0 }; - // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO". - // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16, - // it should be declared to specialized the maximum enum by below: - // template <> constexpr size_t NamedEnum::max = 16; - // If the enum class definition is sparse and contains enum values starting from a large value, - // Do not specialize it to a large number to avoid performance issues. - // The recommended maximum enum number to specialize is 64. - template - static const std::string string(E val, const char* fallbackFormat = "%02d") { - std::string result; - std::optional enumString = enum_name(val); - result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val); - return result; - } -}; - -} // namespace android diff --git a/include/ftl/enum.h b/include/ftl/enum.h new file mode 100644 index 0000000000..dfe3a0976b --- /dev/null +++ b/include/ftl/enum.h @@ -0,0 +1,299 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +// Returns the name of enumerator E::V (i.e. "V") as std::optional by parsing the +// compiler-generated string literal for the signature of this function. The function is defined in +// the global namespace with a short name and inferred return type to reduce bloat in the read-only +// data segment. +template +constexpr auto ftl_enum() { + static_assert(std::is_enum_v); + + using R = std::optional; + using namespace std::literals; + + // The "pretty" signature has the following format: + // + // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue] + // + std::string_view view = __PRETTY_FUNCTION__; + const auto template_begin = view.rfind('['); + const auto template_end = view.rfind(']'); + if (template_begin == view.npos || template_end == view.npos) return R{}; + + // Extract the template parameters without the enclosing brackets. Example (cont'd): + // + // E = android::test::Enum, V = android::test::Enum::kValue + // + view = view.substr(template_begin + 1, template_end - template_begin - 1); + const auto value_begin = view.rfind("V = "sv); + if (value_begin == view.npos) return R{}; + + // Example (cont'd): + // + // V = android::test::Enum::kValue + // + view = view.substr(value_begin); + const auto name_begin = view.rfind("::"sv); + if (name_begin == view.npos) return R{}; + + // Chop off the leading "::". + const auto name = view.substr(name_begin + 2); + + // A value that is not enumerated has the format "Enum)42". + return name.find(')') == view.npos ? R{name} : R{}; +} + +namespace android::ftl { + +// Trait for determining whether a type is specifically a scoped enum or not. By definition, a +// scoped enum is one that is not implicitly convertible to its underlying type. +// +// TODO: Replace with std::is_scoped_enum in C++23. +// +template > +struct is_scoped_enum : std::false_type {}; + +template +struct is_scoped_enum : std::negation>> { +}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + +// Shorthand for casting an enumerator to its integral value. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_cast(E::B) == 1); +// +template +constexpr auto enum_cast(E v) { + return static_cast>(v); +} + +// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named +// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1 +// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the +// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of- +// range values results in undefined behavior if the underlying type is not fixed. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_begin_v == E::A); +// static_assert(ftl::enum_last_v == E::F); +// static_assert(ftl::enum_size_v == 6); +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::enum_begin_v == F{0}); +// static_assert(ftl::enum_last_v == F{15}); +// static_assert(ftl::enum_size_v == 16); +// +template +struct enum_begin { + static_assert(is_scoped_enum_v, "Missing ftl_first enumerator"); + static constexpr E value{0}; +}; + +template +struct enum_begin> { + static constexpr E value = E::ftl_first; +}; + +template +inline constexpr E enum_begin_v = enum_begin::value; + +template +struct enum_end { + using U = std::underlying_type_t; + static_assert(is_scoped_enum_v && std::is_unsigned_v, "Missing ftl_last enumerator"); + + static constexpr E value{std::numeric_limits::digits}; +}; + +template +struct enum_end> { + static constexpr E value = E{enum_cast(E::ftl_last) + 1}; +}; + +template +inline constexpr E enum_end_v = enum_end::value; + +template +inline constexpr E enum_last_v = E{enum_cast(enum_end_v) - 1}; + +template +struct enum_size { + static constexpr auto kBegin = enum_cast(enum_begin_v); + static constexpr auto kEnd = enum_cast(enum_end_v); + static_assert(kBegin < kEnd, "Invalid range"); + + static constexpr std::size_t value = kEnd - kBegin; + static_assert(value <= 64, "Excessive range size"); +}; + +template +inline constexpr std::size_t enum_size_v = enum_size::value; + +namespace details { + +template +struct Identity { + static constexpr auto value = V; +}; + +template +using make_enum_sequence = std::make_integer_sequence, enum_size_v>; + +template class = Identity, typename = make_enum_sequence> +struct EnumRange; + +template class F, typename T, T... Vs> +struct EnumRange> { + static constexpr auto kBegin = enum_cast(enum_begin_v); + static constexpr auto kSize = enum_size_v; + + using R = decltype(F::value); + const R values[kSize] = {F(Vs + kBegin)>::value...}; + + constexpr const auto* begin() const { return values; } + constexpr const auto* end() const { return values + kSize; } +}; + +template +struct EnumName { + static constexpr auto value = ftl_enum(); +}; + +template +struct FlagName { + using E = decltype(I); + using U = std::underlying_type_t; + + static constexpr E V{U{1} << enum_cast(I)}; + static constexpr auto value = ftl_enum(); +}; + +} // namespace details + +// Returns an iterable over the range of an enum. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// std::string string; +// for (E v : ftl::enum_range()) { +// string += ftl::enum_name(v).value_or("?"); +// } +// +// assert(string == "ABC??F"); +// +template +constexpr auto enum_range() { + return details::EnumRange{}; +} + +// Returns a stringified enumerator at compile time. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_name() == "B"); +// +template +constexpr std::string_view enum_name() { + constexpr auto kName = ftl_enum(); + static_assert(kName, "Unknown enumerator"); + return *kName; +} + +// Returns a stringified enumerator, possibly at compile time. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_name(E::C).value_or("?") == "C"); +// static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +// +template +constexpr std::optional enum_name(E v) { + const auto value = enum_cast(v); + + constexpr auto kBegin = enum_cast(enum_begin_v); + constexpr auto kLast = enum_cast(enum_last_v); + if (value < kBegin || value > kLast) return {}; + + constexpr auto kRange = details::EnumRange{}; + return kRange.values[value - kBegin]; +} + +// Returns a stringified flag enumerator, possibly at compile time. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z"); +// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?"); +// +template +constexpr std::optional flag_name(E v) { + const auto value = enum_cast(v); + + // TODO: Replace with std::popcount and std::countr_zero in C++20. + if (__builtin_popcountl(value) != 1) return {}; + + constexpr auto kRange = details::EnumRange{}; + return kRange.values[__builtin_ctzl(value)]; +} + +// Returns a stringified enumerator, or its integral value if not named. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// assert(ftl::enum_string(E::C) == "C"); +// assert(ftl::enum_string(E{3}) == "3"); +// +template +inline std::string enum_string(E v) { + if (const auto name = enum_name(v)) { + return std::string(*name); + } + return to_string(enum_cast(v)); +} + +// Returns a stringified flag enumerator, or its integral value if not named. +// +// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; +// +// assert(ftl::flag_string(F::Z) == "Z"); +// assert(ftl::flag_string(F{7}) == "0b111"); +// +template +inline std::string flag_string(E v) { + if (const auto name = flag_name(v)) { + return std::string(*name); + } + constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex; + return to_string(enum_cast(v), radix); +} + +} // namespace android::ftl diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index a6213f3ddd..9148fee532 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -18,7 +18,8 @@ #define _LIBINPUT_DISPLAY_VIEWPORT_H #include -#include +#include +#include #include #include @@ -44,6 +45,8 @@ enum class ViewportType : int32_t { INTERNAL = 1, EXTERNAL = 2, VIRTUAL = 3, + + ftl_last = VIRTUAL }; /* @@ -132,9 +135,8 @@ struct DisplayViewport { "physicalFrame=[%d, %d, %d, %d], " "deviceSize=[%d, %d], " "isActive=[%d]", - NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(), - physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str() - : "", + ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(), + physicalPort ? ftl::to_string(*physicalPort).c_str() : "", orientation, logicalLeft, logicalTop, logicalRight, logicalBottom, physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth, deviceHeight, isActive); diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 7f0324a4a8..22aae196c6 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -84,6 +84,9 @@ enum class InputDeviceSensorType : int32_t { GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR, GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED, SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION, + + ftl_first = ACCELEROMETER, + ftl_last = SIGNIFICANT_MOTION }; enum class InputDeviceSensorAccuracy : int32_t { @@ -105,6 +108,8 @@ enum class InputDeviceLightType : int32_t { PLAYER_ID = 1, RGB = 2, MULTI_COLOR = 3, + + ftl_last = MULTI_COLOR }; struct InputDeviceSensorInfo { diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 9a150eb0e2..7632b30bd2 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -73,6 +73,8 @@ struct InputMessage { DRAG, TIMELINE, TOUCH_MODE, + + ftl_last = TOUCH_MODE }; struct Header { diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 3026921044..5a80ad067c 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,10 +14,10 @@ cc_test { address: true, }, srcs: [ - "cast_test.cpp", "Flags_test.cpp", + "cast_test.cpp", + "enum_test.cpp", "future_test.cpp", - "NamedEnum_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp index 8c00b5299b..d241fa272a 100644 --- a/libs/ftl/Flags_test.cpp +++ b/libs/ftl/Flags_test.cpp @@ -23,7 +23,7 @@ namespace android::test { using namespace android::flag_operators; -enum class TestFlags { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; +enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; TEST(Flags, Test) { Flags flags = TestFlags::ONE; @@ -165,7 +165,7 @@ TEST(Flags, String_KnownValues) { TEST(Flags, String_UnknownValues) { auto flags = Flags(0b1011); - ASSERT_EQ(flags.string(), "ONE | TWO | 0x00000008"); + ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000"); } TEST(FlagsIterator, IteratesOverAllFlags) { @@ -210,18 +210,4 @@ TEST(FlagsIterator, PreFixIncrement) { ASSERT_EQ(++iter, flags.end()); } -TEST(FlagNames, RuntimeFlagName) { - TestFlags f = TestFlags::ONE; - ASSERT_EQ(flag_name(f), "ONE"); -} - -TEST(FlagNames, RuntimeUnknownFlagName) { - TestFlags f = static_cast(0x8); - ASSERT_EQ(flag_name(f), std::nullopt); -} - -TEST(FlagNames, CompileTimeFlagName) { - static_assert(flag_name() == "TWO"); -} - -} // namespace android::test \ No newline at end of file +} // namespace android::test diff --git a/libs/ftl/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp deleted file mode 100644 index dff2b8aaa1..0000000000 --- a/libs/ftl/NamedEnum_test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020 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 -#include - -namespace android { - -// Test enum class maximum enum value smaller than default maximum of 8. -enum class TestEnums { ZERO = 0x0, ONE = 0x1, TWO = 0x2, THREE = 0x3, SEVEN = 0x7 }; -// Big enum contains enum values greater than default maximum of 8. -enum class TestBigEnums { ZERO = 0x0, FIFTEEN = 0xF }; - -// Declared to specialize the maximum enum since the enum size exceeds 8 by default. -template <> -constexpr size_t NamedEnum::max = 16; - -namespace test { -using android::TestBigEnums; -using android::TestEnums; - -TEST(NamedEnum, RuntimeNamedEnum) { - TestEnums e = TestEnums::ZERO; - ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); - - e = TestEnums::ONE; - ASSERT_EQ(NamedEnum::enum_name(e), "ONE"); - - e = TestEnums::THREE; - ASSERT_EQ(NamedEnum::enum_name(e), "THREE"); - - e = TestEnums::SEVEN; - ASSERT_EQ(NamedEnum::enum_name(e), "SEVEN"); -} - -// Test big enum -TEST(NamedEnum, RuntimeBigNamedEnum) { - TestBigEnums e = TestBigEnums::ZERO; - ASSERT_EQ(NamedEnum::enum_name(e), "ZERO"); - - e = TestBigEnums::FIFTEEN; - ASSERT_EQ(NamedEnum::enum_name(e), "FIFTEEN"); -} - -TEST(NamedEnum, RuntimeNamedEnumAsString) { - TestEnums e = TestEnums::ZERO; - ASSERT_EQ(NamedEnum::string(e), "ZERO"); - - e = TestEnums::ONE; - ASSERT_EQ(NamedEnum::string(e), "ONE"); - - e = TestEnums::THREE; - ASSERT_EQ(NamedEnum::string(e), "THREE"); - - e = TestEnums::SEVEN; - ASSERT_EQ(NamedEnum::string(e), "SEVEN"); -} - -TEST(NamedEnum, RuntimeBigNamedEnumAsString) { - TestBigEnums e = TestBigEnums::ZERO; - ASSERT_EQ(NamedEnum::string(e), "ZERO"); - - e = TestBigEnums::FIFTEEN; - ASSERT_EQ(NamedEnum::string(e), "FIFTEEN"); -} - -TEST(NamedEnum, RuntimeUnknownNamedEnum) { - TestEnums e = static_cast(0x5); - ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); - e = static_cast(0x9); - ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt); -} - -TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) { - TestEnums e = static_cast(0x5); - ASSERT_EQ(NamedEnum::string(e), "05"); - e = static_cast(0x9); - ASSERT_EQ(NamedEnum::string(e, "0x%08x"), "0x00000009"); -} - -TEST(NamedEnum, CompileTimeFlagName) { - static_assert(NamedEnum::enum_name() == "TWO"); - static_assert(NamedEnum::enum_name() == "THREE"); -} - -} // namespace test - -} // namespace android diff --git a/libs/ftl/enum_test.cpp b/libs/ftl/enum_test.cpp new file mode 100644 index 0000000000..1fd43abbc6 --- /dev/null +++ b/libs/ftl/enum_test.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2021 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 +#include + +namespace android::test { + +// Keep in sync with example usage in header file. +namespace { + +enum class E { A, B, C, F = 5, ftl_last = F }; + +static_assert(ftl::enum_begin_v == E::A); +static_assert(ftl::enum_last_v == E::F); +static_assert(ftl::enum_size_v == 6); + +static_assert(ftl::enum_name() == "B"); +static_assert(ftl::enum_name() == "F"); +static_assert(ftl::enum_name(E::C).value_or("?") == "C"); +static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); + +enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; + +static_assert(ftl::enum_begin_v == F{0}); +static_assert(ftl::enum_last_v == F{15}); +static_assert(ftl::enum_size_v == 16); + +static_assert(ftl::flag_name(F::Z).value_or("?") == "Z"); +static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?"); + +// If a scoped enum is unsigned, its implicit range corresponds to its bit indices. +enum class Flags : std::uint8_t { + kNone = 0, + kFlag1 = 0b0000'0010, + kFlag4 = 0b0001'0000, + kFlag7 = 0b1000'0000, + kMask = kFlag1 | kFlag4 | kFlag7, + kAll = 0b1111'1111 +}; + +static_assert(ftl::enum_begin_v == Flags{0}); +static_assert(ftl::enum_last_v == Flags{7}); +static_assert(ftl::enum_size_v == 8); + +static_assert(ftl::enum_name() == "kNone"); +static_assert(ftl::enum_name() == "kFlag4"); +static_assert(ftl::enum_name() == "kFlag7"); + +// Though not flags, the enumerators are within the implicit range of bit indices. +enum class Planet : std::uint8_t { + kMercury, + kVenus, + kEarth, + kMars, + kJupiter, + kSaturn, + kUranus, + kNeptune +}; + +constexpr Planet kPluto{ftl::enum_cast(Planet::kNeptune) + 1}; // Honorable mention. + +static_assert(ftl::enum_begin_v == Planet::kMercury); +static_assert(ftl::enum_last_v == Planet::kNeptune); +static_assert(ftl::enum_size_v == 8); + +static_assert(ftl::enum_name() == "kMercury"); +static_assert(ftl::enum_name() == "kSaturn"); + +// Unscoped enum must define explicit range, even if the underlying type is fixed. +enum Temperature : int { + kRoom = 20, + kFridge = 4, + kFreezer = -18, + + ftl_first = kFreezer, + ftl_last = kRoom +}; + +static_assert(ftl::enum_begin_v == kFreezer); +static_assert(ftl::enum_last_v == kRoom); +static_assert(ftl::enum_size_v == 39); + +static_assert(ftl::enum_name() == "kFreezer"); +static_assert(ftl::enum_name() == "kFridge"); +static_assert(ftl::enum_name() == "kRoom"); + +} // namespace + +TEST(Enum, Range) { + std::string string; + for (E v : ftl::enum_range()) { + string += ftl::enum_name(v).value_or("?"); + } + EXPECT_EQ(string, "ABC??F"); +} + +TEST(Enum, Name) { + { + EXPECT_EQ(ftl::flag_name(Flags::kFlag1), "kFlag1"); + EXPECT_EQ(ftl::flag_name(Flags::kFlag7), "kFlag7"); + + EXPECT_EQ(ftl::flag_name(Flags::kNone), std::nullopt); + EXPECT_EQ(ftl::flag_name(Flags::kMask), std::nullopt); + EXPECT_EQ(ftl::flag_name(Flags::kAll), std::nullopt); + } + { + EXPECT_EQ(ftl::enum_name(Planet::kEarth), "kEarth"); + EXPECT_EQ(ftl::enum_name(Planet::kNeptune), "kNeptune"); + + EXPECT_EQ(ftl::enum_name(kPluto), std::nullopt); + } + { + EXPECT_EQ(ftl::enum_name(kRoom), "kRoom"); + EXPECT_EQ(ftl::enum_name(kFridge), "kFridge"); + EXPECT_EQ(ftl::enum_name(kFreezer), "kFreezer"); + + EXPECT_EQ(ftl::enum_name(static_cast(-30)), std::nullopt); + EXPECT_EQ(ftl::enum_name(static_cast(0)), std::nullopt); + EXPECT_EQ(ftl::enum_name(static_cast(100)), std::nullopt); + } +} + +TEST(Enum, String) { + { + EXPECT_EQ(ftl::flag_string(Flags::kFlag1), "kFlag1"); + EXPECT_EQ(ftl::flag_string(Flags::kFlag7), "kFlag7"); + + EXPECT_EQ(ftl::flag_string(Flags::kNone), "0b0"); + EXPECT_EQ(ftl::flag_string(Flags::kMask), "0b10010010"); + EXPECT_EQ(ftl::flag_string(Flags::kAll), "0b11111111"); + } + { + EXPECT_EQ(ftl::enum_string(Planet::kEarth), "kEarth"); + EXPECT_EQ(ftl::enum_string(Planet::kNeptune), "kNeptune"); + + EXPECT_EQ(ftl::enum_string(kPluto), "8"); + } + { + EXPECT_EQ(ftl::enum_string(kRoom), "kRoom"); + EXPECT_EQ(ftl::enum_string(kFridge), "kFridge"); + EXPECT_EQ(ftl::enum_string(kFreezer), "kFreezer"); + + EXPECT_EQ(ftl::enum_string(static_cast(-30)), "-30"); + EXPECT_EQ(ftl::enum_string(static_cast(0)), "0"); + EXPECT_EQ(ftl::enum_string(static_cast(100)), "100"); + } +} + +} // namespace android::test diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index f090c63228..47f6c05bff 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -71,8 +71,9 @@ struct WindowInfo : public Parcelable { SLIPPERY = 0x20000000, LAYOUT_ATTACHED_IN_DECOR = 0x40000000, DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000, - }; // Window types from WindowManager.LayoutParams + }; + // Window types from WindowManager.LayoutParams enum class Type : int32_t { UNKNOWN = 0, FIRST_APPLICATION_WINDOW = 1, @@ -87,40 +88,50 @@ struct WindowInfo : public Parcelable { APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - STATUS_BAR = FIRST_SYSTEM_WINDOW, - SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, - PHONE = FIRST_SYSTEM_WINDOW + 2, - SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, - KEYGUARD = FIRST_SYSTEM_WINDOW + 4, - TOAST = FIRST_SYSTEM_WINDOW + 5, - SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, - PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, - SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, - KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, - SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, - INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, - INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, - WALLPAPER = FIRST_SYSTEM_WINDOW + 13, - STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, - SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, - DRAG = FIRST_SYSTEM_WINDOW + 16, - STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, - POINTER = FIRST_SYSTEM_WINDOW + 18, - NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, - VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, - BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, - INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, - NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, - MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, - ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, - DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, - ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39, - NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, + +#define FIRST_SYSTEM_WINDOW_ 2000 + + STATUS_BAR = FIRST_SYSTEM_WINDOW_, + SEARCH_BAR = FIRST_SYSTEM_WINDOW_ + 1, + PHONE = FIRST_SYSTEM_WINDOW_ + 2, + SYSTEM_ALERT = FIRST_SYSTEM_WINDOW_ + 3, + KEYGUARD = FIRST_SYSTEM_WINDOW_ + 4, + TOAST = FIRST_SYSTEM_WINDOW_ + 5, + SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW_ + 6, + PRIORITY_PHONE = FIRST_SYSTEM_WINDOW_ + 7, + SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW_ + 8, + KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW_ + 9, + SYSTEM_ERROR = FIRST_SYSTEM_WINDOW_ + 10, + INPUT_METHOD = FIRST_SYSTEM_WINDOW_ + 11, + INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW_ + 12, + WALLPAPER = FIRST_SYSTEM_WINDOW_ + 13, + STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW_ + 14, + SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW_ + 15, + DRAG = FIRST_SYSTEM_WINDOW_ + 16, + STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW_ + 17, + POINTER = FIRST_SYSTEM_WINDOW_ + 18, + NAVIGATION_BAR = FIRST_SYSTEM_WINDOW_ + 19, + VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW_ + 20, + BOOT_PROGRESS = FIRST_SYSTEM_WINDOW_ + 21, + INPUT_CONSUMER = FIRST_SYSTEM_WINDOW_ + 22, + NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW_ + 24, + MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW_ + 27, + ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW_ + 32, + DOCK_DIVIDER = FIRST_SYSTEM_WINDOW_ + 34, + ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW_ + 39, + NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW_ + 40, + + FIRST_SYSTEM_WINDOW = FIRST_SYSTEM_WINDOW_, LAST_SYSTEM_WINDOW = 2999, + +#undef FIRST_SYSTEM_WINDOW_ + + // Small range to limit LUT size. + ftl_first = FIRST_SYSTEM_WINDOW, + ftl_last = FIRST_SYSTEM_WINDOW + 15 }; - enum class Feature { + enum class Feature : uint32_t { DISABLE_TOUCH_PAD_GESTURES = 0x00000001, NO_INPUT_CHANNEL = 0x00000002, DISABLE_USER_ACTIVITY = 0x00000004, @@ -265,4 +276,4 @@ protected: WindowInfo mInfo; }; -} // namespace android::gui \ No newline at end of file +} // namespace android::gui diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 220c8e1e6e..69ae9a02ec 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -228,7 +228,7 @@ void InputDeviceInfo::addMotionRange(const MotionRange& range) { void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) { if (mSensors.find(info.type) != mSensors.end()) { ALOGW("Sensor type %s already exists, will be replaced by new sensor added.", - NamedEnum::string(info.type).c_str()); + ftl::enum_string(info.type).c_str()); } mSensors.insert_or_assign(info.type, info); } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 1e93dfb488..91ab008161 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -30,10 +30,10 @@ static constexpr bool DEBUG_TRANSPORT_ACTIONS = false; #include #include #include +#include #include #include -#include #include using android::base::StringPrintf; @@ -714,7 +714,7 @@ android::base::Result InputPublisher::receiveC } ALOGE("channel '%s' publisher ~ Received unexpected %s message from consumer", - mChannel->getName().c_str(), NamedEnum::string(msg.header.type).c_str()); + mChannel->getName().c_str(), ftl::enum_string(msg.header.type).c_str()); return android::base::Error(UNKNOWN_ERROR); } @@ -856,7 +856,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum case InputMessage::Type::TIMELINE: { LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by " "InputConsumer!", - NamedEnum::string(mMsg.header.type).c_str()); + ftl::enum_string(mMsg.header.type).c_str()); break; } @@ -1449,14 +1449,14 @@ std::string InputConsumer::dump() const { out = out + "mChannel = " + mChannel->getName() + "\n"; out = out + "mMsgDeferred: " + toString(mMsgDeferred) + "\n"; if (mMsgDeferred) { - out = out + "mMsg : " + NamedEnum::string(mMsg.header.type) + "\n"; + out = out + "mMsg : " + ftl::enum_string(mMsg.header.type) + "\n"; } out += "Batches:\n"; for (const Batch& batch : mBatches) { out += " Batch:\n"; for (const InputMessage& msg : batch.samples) { out += android::base::StringPrintf(" Message %" PRIu32 ": %s ", msg.header.seq, - NamedEnum::string(msg.header.type).c_str()); + ftl::enum_string(msg.header.type).c_str()); switch (msg.header.type) { case InputMessage::Type::KEY: { out += android::base::StringPrintf("action=%s keycode=%" PRId32, diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index c365ab070e..7c25cda9ac 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -16,10 +16,8 @@ #define LOG_TAG "KeyLayoutMap" -#include - #include -#include +#include #include #include #include @@ -28,6 +26,10 @@ #include #include +#include +#include +#include + // Enables debug output for the parser. #define DEBUG_PARSER 0 @@ -39,37 +41,39 @@ namespace android { +namespace { -static const char* WHITESPACE = " \t\r"; - -#define SENSOR_ENTRY(type) NamedEnum::string(type), type -static const std::unordered_map SENSOR_LIST = - {{SENSOR_ENTRY(InputDeviceSensorType::ACCELEROMETER)}, - {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD)}, - {SENSOR_ENTRY(InputDeviceSensorType::ORIENTATION)}, - {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE)}, - {SENSOR_ENTRY(InputDeviceSensorType::LIGHT)}, - {SENSOR_ENTRY(InputDeviceSensorType::PRESSURE)}, - {SENSOR_ENTRY(InputDeviceSensorType::TEMPERATURE)}, - {SENSOR_ENTRY(InputDeviceSensorType::PROXIMITY)}, - {SENSOR_ENTRY(InputDeviceSensorType::GRAVITY)}, - {SENSOR_ENTRY(InputDeviceSensorType::LINEAR_ACCELERATION)}, - {SENSOR_ENTRY(InputDeviceSensorType::ROTATION_VECTOR)}, - {SENSOR_ENTRY(InputDeviceSensorType::RELATIVE_HUMIDITY)}, - {SENSOR_ENTRY(InputDeviceSensorType::AMBIENT_TEMPERATURE)}, - {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED)}, - {SENSOR_ENTRY(InputDeviceSensorType::GAME_ROTATION_VECTOR)}, - {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)}, - {SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}}; - -// --- KeyLayoutMap --- - -KeyLayoutMap::KeyLayoutMap() { -} +constexpr const char* WHITESPACE = " \t\r"; -KeyLayoutMap::~KeyLayoutMap() { +template +constexpr auto sensorPair() { + return std::make_pair(ftl::enum_name(), S); } +static const std::unordered_map SENSOR_LIST = + {sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair(), + sensorPair()}; + +} // namespace + +KeyLayoutMap::KeyLayoutMap() = default; +KeyLayoutMap::~KeyLayoutMap() = default; + base::Result> KeyLayoutMap::loadContents(const std::string& filename, const char* contents) { Tokenizer* tokenizer; @@ -160,8 +164,8 @@ base::Result> KeyLayoutMap::mapSensor( const Sensor& sensor = it->second; #if DEBUG_MAPPING - ALOGD("mapSensor: absCode=%d, sensorType=0x%0x, sensorDataIndex=0x%x.", absCode, - NamedEnum::string(sensor.sensorType), sensor.sensorDataIndex); + ALOGD("mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode, + ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex); #endif return std::make_pair(sensor.sensorType, sensor.sensorDataIndex); } @@ -513,7 +517,7 @@ status_t KeyLayoutMap::Parser::parseLed() { } static std::optional getSensorType(const char* token) { - auto it = SENSOR_LIST.find(std::string(token)); + auto it = SENSOR_LIST.find(token); if (it == SENSOR_LIST.end()) { return std::nullopt; } @@ -581,8 +585,8 @@ status_t KeyLayoutMap::Parser::parseSensor() { int32_t sensorDataIndex = indexOpt.value(); #if DEBUG_PARSER - ALOGD("Parsed sensor: abs code=%d, sensorType=%d, sensorDataIndex=%d.", code, - NamedEnum::string(sensorType).c_str(), sensorDataIndex); + ALOGD("Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code, + ftl::enum_string(sensorType).c_str(), sensorDataIndex); #endif Sensor sensor; @@ -591,4 +595,5 @@ status_t KeyLayoutMap::Parser::parseSensor() { map.emplace(code, sensor); return NO_ERROR; } -}; + +} // namespace android diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp index 05ef489133..a864cf8202 100644 --- a/services/inputflinger/InputReaderBase.cpp +++ b/services/inputflinger/InputReaderBase.cpp @@ -19,12 +19,12 @@ //#define LOG_NDEBUG 0 #include "InputReaderBase.h" -#include #include "input/DisplayViewport.h" #include "input/Input.h" -#include #include +#include +#include #define INDENT " " #define INDENT2 " " @@ -117,7 +117,7 @@ std::optional InputReaderConfiguration::getDisplayViewportByTyp } if (count > 1) { ALOGW("Found %zu viewports with type %s, but expected 1 at most", count, - NamedEnum::string(type).c_str()); + ftl::enum_string(type).c_str()); } return result; } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 547021ca22..5365a78b0a 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -40,6 +40,8 @@ struct EventEntry { POINTER_CAPTURE_CHANGED, DRAG, TOUCH_MODE_CHANGED, + + ftl_last = TOUCH_MODE_CHANGED }; int32_t id; diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index 4a75773201..600f02ba80 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -27,7 +27,7 @@ static constexpr bool DEBUG_FOCUS = false; #include #include -#include +#include #include #include @@ -65,7 +65,7 @@ std::optional FocusResolver::setInputWindows( if (result == Focusability::OK) { return std::nullopt; } - removeFocusReason = NamedEnum::string(result); + removeFocusReason = ftl::enum_string(result); } // We don't have a focused window or the currently focused window is no longer focusable. Check @@ -79,7 +79,7 @@ std::optional FocusResolver::setInputWindows( if (result == Focusability::OK) { return updateFocusedWindow(displayId, "Window became focusable. Previous reason: " + - NamedEnum::string(previousResult), + ftl::enum_string(previousResult), requestedFocus, request->windowName); } } @@ -116,7 +116,7 @@ std::optional FocusResolver::setFocusedWindow( request.token, request.windowName); } ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s", - request.windowName.c_str(), displayId, NamedEnum::string(result).c_str()); + request.windowName.c_str(), displayId, ftl::enum_string(result).c_str()); return std::nullopt; } @@ -134,7 +134,7 @@ std::optional FocusResolver::setFocusedWindow( // The requested window is not currently focusable. Wait for the window to become focusable // but remove focus from the current window so that input events can go into a pending queue // and be sent to the window when it becomes focused. - return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result), + return updateFocusedWindow(displayId, "Waiting for window because " + ftl::enum_string(result), nullptr); } @@ -212,7 +212,7 @@ std::string FocusResolver::dump() const { for (const auto& [displayId, request] : mFocusRequestByDisplay) { auto it = mLastFocusResultByDisplay.find(displayId); std::string result = - it != mLastFocusResultByDisplay.end() ? NamedEnum::string(it->second) : ""; + it != mLastFocusResultByDisplay.end() ? ftl::enum_string(it->second) : ""; dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s' result='%s'\n", displayId, request.windowName.c_str(), result.c_str()); } diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h index 1d6cd9a5fa..6d11a77aad 100644 --- a/services/inputflinger/dispatcher/FocusResolver.h +++ b/services/inputflinger/dispatcher/FocusResolver.h @@ -77,6 +77,8 @@ private: NO_WINDOW, NOT_FOCUSABLE, NOT_VISIBLE, + + ftl_last = NOT_VISIBLE }; // Checks if the window token can be focused on a display. The token can be focused if there is @@ -113,4 +115,4 @@ private: std::optional getFocusRequest(int32_t displayId); }; -} // namespace android::inputdispatcher \ No newline at end of file +} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 92ba52c3f4..9da71925ce 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1151,7 +1152,7 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason case EventEntry::Type::TOUCH_MODE_CHANGED: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { - LOG_ALWAYS_FATAL("Should not drop %s events", NamedEnum::string(entry.type).c_str()); + LOG_ALWAYS_FATAL("Should not drop %s events", ftl::enum_string(entry.type).c_str()); break; } } @@ -1573,7 +1574,7 @@ void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, " "source=0x%x, sensorType=%s", entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source, - NamedEnum::string(entry->sensorType).c_str()); + ftl::enum_string(entry->sensorType).c_str()); } auto command = [this, entry]() REQUIRES(mLock) { scoped_unlock unlock(mLock); @@ -1590,7 +1591,7 @@ void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) { if (DEBUG_OUTBOUND_EVENT_DETAILS) { ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId, - NamedEnum::string(sensorType).c_str()); + ftl::enum_string(sensorType).c_str()); } { // acquire lock std::scoped_lock _l(mLock); @@ -1811,7 +1812,7 @@ int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::SENSOR: case EventEntry::Type::DRAG: { - ALOGE("%s events do not have a target display", NamedEnum::string(entry.type).c_str()); + ALOGE("%s events do not have a target display", ftl::enum_string(entry.type).c_str()); return ADISPLAY_ID_NONE; } } @@ -1863,7 +1864,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) { ALOGI("Dropping %s event because there is no focused window or focused application in " "display %" PRId32 ".", - NamedEnum::string(entry.type).c_str(), displayId); + ftl::enum_string(entry.type).c_str(), displayId); return InputEventInjectionResult::FAILED; } @@ -1888,7 +1889,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( } else if (currentTime > *mNoFocusedWindowTimeoutTime) { // Already raised ANR. Drop the event ALOGE("Dropping %s event because there is no focused window", - NamedEnum::string(entry.type).c_str()); + ftl::enum_string(entry.type).c_str()); return InputEventInjectionResult::FAILED; } else { // Still waiting for the focused window @@ -2676,8 +2677,7 @@ std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, " "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", - (isTouchedWindow) ? "[TOUCHED] " : "", - NamedEnum::string(info->type, "%" PRId32).c_str(), + isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(), info->packageName.c_str(), info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, info->frameTop, info->frameRight, info->frameBottom, @@ -2804,7 +2804,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { case EventEntry::Type::POINTER_CAPTURE_CHANGED: case EventEntry::Type::DRAG: { LOG_ALWAYS_FATAL("%s events are not user activity", - NamedEnum::string(eventEntry.type).c_str()); + ftl::enum_string(eventEntry.type).c_str()); break; } } @@ -2849,7 +2849,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, if (inputTarget.flags & InputTarget::FLAG_SPLIT) { LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION, "Entry type %s should not have FLAG_SPLIT", - NamedEnum::string(eventEntry->type).c_str()); + ftl::enum_string(eventEntry->type).c_str()); const MotionEntry& originalMotionEntry = static_cast(*eventEntry); if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) { @@ -3037,7 +3037,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp& connectio case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { LOG_ALWAYS_FATAL("%s events should not go to apps", - NamedEnum::string(newEntry.type).c_str()); + ftl::enum_string(newEntry.type).c_str()); break; } } @@ -3276,7 +3276,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::SENSOR: { LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events", - NamedEnum::string(eventEntry.type).c_str()); + ftl::enum_string(eventEntry.type).c_str()); return; } } @@ -3592,14 +3592,14 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( case EventEntry::Type::POINTER_CAPTURE_CHANGED: case EventEntry::Type::DRAG: { LOG_ALWAYS_FATAL("Canceling %s events is not supported", - NamedEnum::string(cancelationEventEntry->type).c_str()); + ftl::enum_string(cancelationEventEntry->type).c_str()); break; } case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::SENSOR: { LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue", - NamedEnum::string(cancelationEventEntry->type).c_str()); + ftl::enum_string(cancelationEventEntry->type).c_str()); break; } } @@ -3659,7 +3659,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( case EventEntry::Type::SENSOR: case EventEntry::Type::DRAG: { LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue", - NamedEnum::string(downEventEntry->type).c_str()); + ftl::enum_string(downEventEntry->type).c_str()); break; } } @@ -4007,7 +4007,7 @@ void InputDispatcher::notifySensor(const NotifySensorArgs* args) { ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, " " sensorType=%s", args->id, args->eventTime, args->deviceId, args->source, - NamedEnum::string(args->sensorType).c_str()); + ftl::enum_string(args->sensorType).c_str()); } bool needWake; @@ -5115,7 +5115,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { toString(windowInfo->hasWallpaper), toString(windowInfo->visible), windowInfo->alpha, windowInfo->flags.string().c_str(), - NamedEnum::string(windowInfo->type).c_str(), + ftl::enum_string(windowInfo->type).c_str(), windowInfo->frameLeft, windowInfo->frameTop, windowInfo->frameRight, windowInfo->frameBottom, windowInfo->globalScaleFactor, diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 0f0ad0a102..d10f8b6605 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -263,7 +264,7 @@ static std::vector allFilesInPath(const std::filesystem:: */ static std::vector findSysfsNodes(const std::filesystem::path& sysfsRoot, SysfsClass clazz) { - std::string nodeStr = NamedEnum::string(clazz); + std::string nodeStr = ftl::enum_string(clazz); std::for_each(nodeStr.begin(), nodeStr.end(), [](char& c) { c = std::tolower(static_cast(c)); }); std::vector nodes; diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index 9c8a29a059..a6934960c9 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -17,9 +17,9 @@ #include #include -#include "../Macros.h" +#include -#include +#include "../Macros.h" #include "PeripheralController.h" // Log detailed debug messages about input device lights. @@ -286,7 +286,7 @@ void PeripheralController::dump(std::string& dump) { for (const auto& [lightId, light] : mLights) { dump += StringPrintf(INDENT4 "Id: %d", lightId); dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str()); - dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str()); + dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str()); light->dump(dump); } } @@ -487,7 +487,7 @@ bool PeripheralController::setLightColor(int32_t lightId, int32_t color) { auto& light = it->second; if (DEBUG_LIGHT_DETAILS) { ALOGD("setLightColor lightId %d type %s color 0x%x", lightId, - NamedEnum::string(light->type).c_str(), color); + ftl::enum_string(light->type).c_str(), color); } return light->setLightColor(color); } @@ -501,7 +501,7 @@ std::optional PeripheralController::getLightColor(int32_t lightId) { std::optional color = light->getLightColor(); if (DEBUG_LIGHT_DETAILS) { ALOGD("getLightColor lightId %d type %s color 0x%x", lightId, - NamedEnum::string(light->type).c_str(), color.value_or(0)); + ftl::enum_string(light->type).c_str(), color.value_or(0)); } return color; } diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 7a00bace6e..1f96294e96 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -146,6 +146,8 @@ enum class InputDeviceClass : uint32_t { enum class SysfsClass : uint32_t { POWER_SUPPLY = 0, LEDS = 1, + + ftl_last = LEDS }; enum class LightColor : uint32_t { diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp index a507632d0e..a1bd548403 100644 --- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp @@ -16,8 +16,9 @@ #include -#include "../Macros.h" +#include +#include "../Macros.h" #include "SensorInputMapper.h" // Log detailed debug messages about each sensor event notification to the dispatcher. @@ -93,7 +94,7 @@ void SensorInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT3 " mHasHardwareTimestamp %d\n", mHasHardwareTimestamp); dump += INDENT3 "Sensors:\n"; for (const auto& [sensorType, sensor] : mSensors) { - dump += StringPrintf(INDENT4 "%s\n", NamedEnum::string(sensorType).c_str()); + dump += StringPrintf(INDENT4 "%s\n", ftl::enum_string(sensorType).c_str()); dump += StringPrintf(INDENT5 "enabled: %d\n", sensor.enabled); dump += StringPrintf(INDENT5 "samplingPeriod: %lld\n", sensor.samplingPeriod.count()); dump += StringPrintf(INDENT5 "maxBatchReportLatency: %lld\n", @@ -208,10 +209,10 @@ SensorInputMapper::Sensor SensorInputMapper::createSensor(InputDeviceSensorType axis.max /* maxRange */, axis.scale /* resolution */, 0.0f /* power */, 0 /* minDelay */, 0 /* fifoReservedEventCount */, 0 /* fifoMaxEventCount */, - NamedEnum::string(sensorType), 0 /* maxDelay */, 0 /* flags */, + ftl::enum_string(sensorType), 0 /* maxDelay */, 0 /* flags */, getDeviceId()); - std::string prefix = "sensor." + NamedEnum::string(sensorType); + std::string prefix = "sensor." + ftl::enum_string(sensorType); transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower); int32_t reportingMode = 0; @@ -335,7 +336,7 @@ bool SensorInputMapper::enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds maxBatchReportLatency) { if (DEBUG_SENSOR_EVENT_DETAILS) { ALOGD("Enable Sensor %s samplingPeriod %lld maxBatchReportLatency %lld", - NamedEnum::string(sensorType).c_str(), samplingPeriod.count(), + ftl::enum_string(sensorType).c_str(), samplingPeriod.count(), maxBatchReportLatency.count()); } @@ -359,7 +360,7 @@ bool SensorInputMapper::enableSensor(InputDeviceSensorType sensorType, void SensorInputMapper::disableSensor(InputDeviceSensorType sensorType) { if (DEBUG_SENSOR_EVENT_DETAILS) { - ALOGD("Disable Sensor %s", NamedEnum::string(sensorType).c_str()); + ALOGD("Disable Sensor %s", ftl::enum_string(sensorType).c_str()); } if (!setSensorEnabled(sensorType, false /* enabled */)) { @@ -393,13 +394,12 @@ void SensorInputMapper::sync(nsecs_t when, bool force) { nsecs_t timestamp = mHasHardwareTimestamp ? mHardwareTimestamp : when; if (DEBUG_SENSOR_EVENT_DETAILS) { ALOGD("Sensor %s timestamp %" PRIu64 " values [%f %f %f]", - NamedEnum::string(sensorType).c_str(), timestamp, values[0], values[1], - values[2]); + ftl::enum_string(sensorType).c_str(), timestamp, values[0], values[1], values[2]); } if (sensor.lastSampleTimeNs.has_value() && timestamp - sensor.lastSampleTimeNs.value() < sensor.samplingPeriod.count()) { if (DEBUG_SENSOR_EVENT_DETAILS) { - ALOGD("Sensor %s Skip a sample.", NamedEnum::string(sensorType).c_str()); + ALOGD("Sensor %s Skip a sample.", ftl::enum_string(sensorType).c_str()); } } else { // Convert to Android unit diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index ac5f6b652b..419b0d0eed 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -18,9 +18,10 @@ #include "../Macros.h" // clang-format on -#include #include "TouchInputMapper.h" +#include + #include "CursorButtonAccumulator.h" #include "CursorScrollAccumulator.h" #include "TouchButtonAccumulator.h" @@ -259,7 +260,7 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { void TouchInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", - NamedEnum::string(mDeviceMode).c_str()); + ftl::enum_string(mDeviceMode).c_str()); dumpParameters(dump); dumpVirtualKeys(dump); dumpRawPointerAxes(dump); @@ -515,9 +516,9 @@ void TouchInputMapper::configureParameters() { void TouchInputMapper::dumpParameters(std::string& dump) { dump += INDENT3 "Parameters:\n"; - dump += INDENT4 "GestureMode: " + NamedEnum::string(mParameters.gestureMode) + "\n"; + dump += INDENT4 "GestureMode: " + ftl::enum_string(mParameters.gestureMode) + "\n"; - dump += INDENT4 "DeviceType: " + NamedEnum::string(mParameters.deviceType) + "\n"; + dump += INDENT4 "DeviceType: " + ftl::enum_string(mParameters.deviceType) + "\n"; dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, " "displayId='%s'\n", @@ -525,7 +526,7 @@ void TouchInputMapper::dumpParameters(std::string& dump) { toString(mParameters.associatedDisplayIsExternal), mParameters.uniqueDisplayId.c_str()); dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); - dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n"; + dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n"; } void TouchInputMapper::configureRawPointerAxes() { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index e104220e47..a56468f445 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -185,6 +185,8 @@ protected: UNSCALED, // unscaled mapping (touchpad) NAVIGATION, // unscaled mapping with assist gesture (touch navigation) POINTER, // pointer mapping (pointer) + + ftl_last = POINTER }; DeviceMode mDeviceMode; @@ -198,6 +200,8 @@ protected: TOUCH_PAD, TOUCH_NAVIGATION, POINTER, + + ftl_last = POINTER }; DeviceType deviceType; @@ -210,6 +214,8 @@ protected: ORIENTATION_90 = DISPLAY_ORIENTATION_90, ORIENTATION_180 = DISPLAY_ORIENTATION_180, ORIENTATION_270 = DISPLAY_ORIENTATION_270, + + ftl_last = ORIENTATION_270 }; Orientation orientation; @@ -219,6 +225,8 @@ protected: enum class GestureMode { SINGLE_TOUCH, MULTI_TOUCH, + + ftl_last = MULTI_TOUCH }; GestureMode gestureMode; @@ -818,4 +826,4 @@ private: } // namespace android -#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H \ No newline at end of file +#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index f310738423..1ef8f78894 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -21,12 +21,12 @@ #include +#include + #include "ClientCache.h" namespace android { -using base::StringAppendF; - ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache); ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {} @@ -212,16 +212,15 @@ void ClientCache::CacheDeathRecipient::binderDied(const wp& who) { void ClientCache::dump(std::string& result) { std::lock_guard lock(mMutex); - for (auto i : mBuffers) { - const sp& cacheOwner = i.second.first; - StringAppendF(&result," Cache owner: %p\n", cacheOwner.get()); - auto &buffers = i.second.second; - for (auto& [id, clientCacheBuffer] : buffers) { - StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id, - (int)clientCacheBuffer.buffer->getBuffer()->getWidth(), - (int)clientCacheBuffer.buffer->getBuffer()->getHeight()); + for (const auto& [_, cache] : mBuffers) { + base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get()); + + for (const auto& [id, entry] : cache.second) { + const auto& buffer = entry.buffer->getBuffer(); + base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(), + buffer->getHeight()); } } } -}; // namespace android +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index 936dba3b29..2532e3df5d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -93,11 +93,7 @@ Flags LayerState::getDifferingFields(const LayerState& other) c void LayerState::dump(std::string& result) const { for (const StateInterface* field : getNonUniqueFields()) { - if (auto viewOpt = flag_name(field->getField()); viewOpt) { - base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str()); - } else { - result.append(":\n"); - } + base::StringAppendF(&result, " %16s: ", ftl::flag_string(field->getField()).c_str()); bool first = true; for (const std::string& line : field->toStrings()) { @@ -126,11 +122,7 @@ std::optional LayerState::compare(const LayerState& other) const { continue; } - if (auto viewOpt = flag_name(thisField->getField()); viewOpt) { - base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str()); - } else { - result.append(":\n"); - } + base::StringAppendF(&result, " %16s: ", ftl::flag_string(thisField->getField()).c_str()); const auto& thisStrings = thisField->toStrings(); const auto& otherStrings = otherField->toStrings(); -- cgit v1.2.3-59-g8ed1b From ca20550407a1707c48f4c3a839ef55725962f19c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 16 Jul 2021 21:31:58 +0000 Subject: Cancel wallpaper touch stream when foreground window is gone When the foreground window is gone, we should also cancel the touch stream for its wallpaper window. We already cancel touch for the window itself, and for global monitor. Without this patch, the wallpaper window simply stops receiving touches, and never gets CANCEL, either. The behaviour is slightly strange for the global monitor in this case. First of all, the global monitor receives CANCEL, which is questionable (things like pointer location stop working). Also, it only gets cancel when a *new* event comes in. That said, it's probably fine, so let's just document this behaviour by adding a test for it. Bug: 192981537 Test: atest inputflinger_tests Change-Id: I8a2ef7cd552acc5cf64b2e13a6df5d5988bd1808 --- include/input/Input.h | 12 +- libs/input/Input.cpp | 4 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 20 +- services/inputflinger/dispatcher/TouchState.cpp | 10 + services/inputflinger/dispatcher/TouchState.h | 1 + .../inputflinger/tests/InputDispatcher_test.cpp | 267 ++++++++++++++++++++- 6 files changed, 302 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index d2d9fd48e8..f170f0fa23 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -524,13 +524,17 @@ public: inline int32_t getAction() const { return mAction; } - inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } + static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; } - inline int32_t getActionIndex() const { - return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + inline int32_t getActionMasked() const { return getActionMasked(mAction); } + + static int32_t getActionIndex(int32_t action) { + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } + inline int32_t getActionIndex() const { return getActionIndex(mAction); } + inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 1e8ff945ef..037849eac4 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -834,9 +834,9 @@ std::string MotionEvent::actionToString(int32_t action) { case AMOTION_EVENT_ACTION_OUTSIDE: return "OUTSIDE"; case AMOTION_EVENT_ACTION_POINTER_DOWN: - return "POINTER_DOWN"; + return StringPrintf("POINTER_DOWN(%" PRId32 ")", MotionEvent::getActionIndex(action)); case AMOTION_EVENT_ACTION_POINTER_UP: - return "POINTER_UP"; + return StringPrintf("POINTER_UP(%" PRId32 ")", MotionEvent::getActionIndex(action)); case AMOTION_EVENT_ACTION_HOVER_MOVE: return "HOVER_MOVE"; case AMOTION_EVENT_ACTION_SCROLL: diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 058e099faa..ce383d9f25 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1706,13 +1706,13 @@ void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionE if (DEBUG_OUTBOUND_EVENT_DETAILS) { ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, " + "action=%s, actionButton=0x%x, flags=0x%x, " "metaState=0x%x, buttonState=0x%x," "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, - entry.policyFlags, entry.action, entry.actionButton, entry.flags, entry.metaState, - entry.buttonState, entry.edgeFlags, entry.xPrecision, entry.yPrecision, - entry.downTime); + entry.policyFlags, MotionEvent::actionToString(entry.action).c_str(), + entry.actionButton, entry.flags, entry.metaState, entry.buttonState, entry.edgeFlags, + entry.xPrecision, entry.yPrecision, entry.downTime); for (uint32_t i = 0; i < entry.pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " @@ -4642,6 +4642,18 @@ void InputDispatcher::setInputWindowsLocked( CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options); + // Since we are about to drop the touch, cancel the events for the wallpaper as + // well. + if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND && + touchedWindow.windowHandle->getInfo()->hasWallpaper) { + sp wallpaper = state.getWallpaperWindow(); + if (wallpaper != nullptr) { + sp wallpaperConnection = + getConnectionLocked(wallpaper->getToken()); + synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, + options); + } + } } state.windows.erase(state.windows.begin() + i); } else { diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index b7ed658777..4a50a683e9 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -134,4 +134,14 @@ bool TouchState::isSlippery() const { return haveSlipperyForegroundWindow; } +sp TouchState::getWallpaperWindow() const { + for (size_t i = 0; i < windows.size(); i++) { + const TouchedWindow& window = windows[i]; + if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { + return window.windowHandle; + } + } + return nullptr; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 579b868443..7dcf55d813 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -51,6 +51,7 @@ struct TouchState { void filterNonMonitors(); sp getFirstForegroundWindowHandle() const; bool isSlippery() const; + sp getWallpaperWindow() const; }; } // namespace inputdispatcher diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 0a91bde03b..e223372fe1 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -74,6 +74,12 @@ static KeyEvent getTestKeyEvent() { return event; } +static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) { + ASSERT_EQ(expectedAction, receivedAction) + << "expected " << MotionEvent::actionToString(expectedAction) << ", got " + << MotionEvent::actionToString(receivedAction); +} + // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { @@ -801,7 +807,8 @@ public: } case AINPUT_EVENT_TYPE_MOTION: { const MotionEvent& motionEvent = static_cast(*event); - EXPECT_EQ(expectedAction, motionEvent.getAction()); + assertMotionAction(expectedAction, motionEvent.getAction()); + if (expectedFlags.has_value()) { EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags()); } @@ -982,6 +989,10 @@ public: mInfo.addTouchableRegion(frame); } + void setType(WindowInfo::Type type) { mInfo.type = type; } + + void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; } + void addFlags(Flags flags) { mInfo.flags |= flags; } void setFlags(Flags flags) { mInfo.flags = flags; } @@ -1485,6 +1496,197 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { windowSecond->assertNoEvents(); } +/** + * Two windows: A top window, and a wallpaper behind the window. + * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window + * gets ACTION_CANCEL. + * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true) + * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER) + */ +TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) { + std::shared_ptr application = std::make_shared(); + sp foregroundWindow = + new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + foregroundWindow->setHasWallpaper(true); + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both foreground window and its wallpaper should receive the touch down + foregroundWindow->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {110, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + foregroundWindow->consumeMotionMove(); + wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Now the foreground window goes away, but the wallpaper stays + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}}); + foregroundWindow->consumeMotionCancel(); + // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); +} + +/** + * A single window that receives touch (on top), and a wallpaper window underneath it. + * The top window gets a multitouch gesture. + * Ensure that wallpaper gets the same gesture. + */ +TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + window->setHasWallpaper(true); + + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + + // Touch down on top window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both top window and its wallpaper should receive the touch down + window->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Second finger down on the top window + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionPointerDown(1 /* pointerIndex */); + wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT, + expectedWallpaperFlags); + window->assertNoEvents(); + wallpaperWindow->assertNoEvents(); +} + +/** + * Two windows: a window on the left and window on the right. + * A third window, wallpaper, is behind both windows, and spans both top windows. + * The first touch down goes to the left window. A second pointer touches down on the right window. + * The touch is split, so both left and right windows should receive ACTION_DOWN. + * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by + * ACTION_POINTER_DOWN(1). + */ +TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { + std::shared_ptr application = std::make_shared(); + sp leftWindow = + new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); + leftWindow->setHasWallpaper(true); + + sp rightWindow = + new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); + rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); + rightWindow->setHasWallpaper(true); + + sp wallpaperWindow = + new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); + wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); + + // Touch down on left window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both foreground window and its wallpaper should receive the touch down + leftWindow->consumeMotionDown(); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Second finger down on the right window + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(300) + .y(100)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + leftWindow->consumeMotionMove(); + // Since the touch is split, right window gets ACTION_DOWN + rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT, + expectedWallpaperFlags); + + // Now, leftWindow, which received the first finger, disappears. + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightWindow, wallpaperWindow}}}); + leftWindow->consumeMotionCancel(); + // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // The pointer that's still down on the right window moves, and goes to the right window only. + // As far as the dispatcher's concerned though, both pointers are still present. + const MotionEvent secondFingerMoveEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(310) + .y(110)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)); + rightWindow->consumeMotionMove(); + + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); + wallpaperWindow->assertNoEvents(); +} + TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { std::shared_ptr application = std::make_shared(); sp windowLeft = @@ -2301,11 +2503,21 @@ public: expectedDisplayId, expectedFlags); } + void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, + expectedDisplayId, expectedFlags); + } + void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId, expectedFlags); } + void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, + expectedDisplayId, expectedFlags); + } + MotionEvent* consumeMotion() { InputEvent* event = mInputReceiver->consume(); if (!event) { @@ -2325,6 +2537,57 @@ private: std::unique_ptr mInputReceiver; }; +/** + * Two entities that receive touch: A window, and a global monitor. + * The touch goes to the window, and then the window disappears. + * The monitor does not get cancel right away. But if more events come in, the touch gets canceled + * for the monitor, as well. + * 1. foregroundWindow + * 2. monitor <-- global monitor (doesn't observe z order, receives all events) + */ +TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_GlobalMonitorTouchIsCanceled) { + std::shared_ptr application = std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + + FakeMonitorReceiver monitor = + FakeMonitorReceiver(mDispatcher, "GlobalMonitor", ADISPLAY_ID_DEFAULT, + false /*isGestureMonitor*/); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Both the foreground window and the global monitor should receive the touch down + window->consumeMotionDown(); + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {110, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionMove(); + monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); + + // Now the foreground window goes away + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + window->consumeMotionCancel(); + monitor.assertNoEvents(); // Global monitor does not get a cancel yet + + // If more events come in, there will be no more foreground window to send them to. This will + // cause a cancel for the monitor, as well. + ASSERT_EQ(InputEventInjectionResult::FAILED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {120, 200})) + << "Injection should fail because the window was removed"; + window->assertNoEvents(); + // Global monitor now gets the cancel + monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); +} + // Tests for gesture monitors TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) { std::shared_ptr application = std::make_shared(); @@ -3567,7 +3830,7 @@ protected: << " event, got " << inputEventTypeToString(event->getType()) << " event"; const MotionEvent& motionEvent = static_cast(*event); - EXPECT_EQ(expectedAction, motionEvent.getAction()); + assertMotionAction(expectedAction, motionEvent.getAction()); for (size_t i = 0; i < points.size(); i++) { float expectedX = points[i].x; -- cgit v1.2.3-59-g8ed1b From b9b18509a6d0f5f074e86802b322a4fb01b43cd5 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 26 Aug 2021 12:30:32 -0700 Subject: Add display transform to MotionEvent for raw coords Since input now works in display coordinates, we need to include the display projection with MotionEvent so that the getRaw API can continue to report logical display coordinates. It is also important to highlight the difference in the coordinate systems used by regular input windows and input monitors. MotionEvents coming from input monitors will always report values in unrotated logical display coordinates, because we do not yet have an API to report unrotated values in MotionEvents. Bug: 179274888 Test: presubmit Test: manual, ensure input works Change-Id: Ief3b2b31c6644beaa2f8c4b90302f441f93ab960 --- include/input/Input.h | 12 +- include/input/InputTransport.h | 29 +-- libs/input/Input.cpp | 83 +++----- libs/input/InputTransport.cpp | 40 ++-- libs/input/tests/InputEvent_test.cpp | 216 +++++++++------------ .../input/tests/InputPublisherAndConsumer_test.cpp | 89 ++++----- libs/input/tests/StructLayout_test.cpp | 14 +- libs/input/tests/VelocityTracker_test.cpp | 3 +- libs/input/tests/VerifiedInputEvent_test.cpp | 4 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 4 +- services/inputflinger/dispatcher/Entry.cpp | 7 +- services/inputflinger/dispatcher/Entry.h | 7 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 63 +++--- services/inputflinger/dispatcher/InputDispatcher.h | 3 +- services/inputflinger/dispatcher/InputTarget.h | 7 +- .../inputflinger/tests/InputDispatcher_test.cpp | 47 ++--- 16 files changed, 280 insertions(+), 348 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index f170f0fa23..d397313ab6 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -579,9 +579,7 @@ public: void setCursorPosition(float x, float y); - uint32_t getDisplayOrientation() const { return mDisplayOrientation; } - - int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; } + ui::Transform getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } @@ -757,8 +755,8 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, - float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, + float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime, + nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -816,9 +814,7 @@ protected: float mYPrecision; float mRawXCursorPosition; float mRawYCursorPosition; - uint32_t mDisplayOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; + ui::Transform mRawTransform; nsecs_t mDownTime; Vector mPointerProperties; std::vector mSampleEventTimes; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 7632b30bd2..d655b28278 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -114,7 +114,7 @@ struct InputMessage { struct Motion { int32_t eventId; - uint32_t empty1; + uint32_t pointerCount; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; @@ -129,20 +129,22 @@ struct InputMessage { uint8_t empty2[3]; // 3 bytes to fill gap created by classification int32_t edgeFlags; nsecs_t downTime __attribute__((aligned(8))); - float dsdx; - float dtdx; - float dtdy; - float dsdy; - float tx; - float ty; + float dsdx; // Begin window transform + float dtdx; // + float dtdy; // + float dsdy; // + float tx; // + float ty; // End window transform float xPrecision; float yPrecision; float xCursorPosition; float yCursorPosition; - uint32_t displayOrientation; - int32_t displayWidth; - int32_t displayHeight; - uint32_t pointerCount; + float dsdxRaw; // Begin raw transform + float dtdxRaw; // + float dtdyRaw; // + float dsdyRaw; // + float txRaw; // + float tyRaw; // End raw transform /** * The "pointers" field must be the last field of the struct InputMessage. * When we send the struct InputMessage across the socket, we are not @@ -367,9 +369,8 @@ public: int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, uint32_t displayOrientation, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, - nsecs_t eventTime, uint32_t pointerCount, + float yCursorPosition, const ui::Transform& rawTransform, + nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 037849eac4..30e5d5b0bc 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -76,36 +76,13 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return result; } -// Rotates the given point to the specified orientation. If the display width and height are -// provided, the point is rotated in the screen space. Otherwise, the point is rotated about the -// origin. This helper is used to avoid the extra overhead of creating new Transforms. -vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0, - int32_t displayHeight = 0) { - if (orientation == ui::Transform::ROT_0) { - return {x, y}; - } - - vec2 xy(x, y); - if (orientation == ui::Transform::ROT_90) { - xy.x = displayHeight - y; - xy.y = x; - } else if (orientation == ui::Transform::ROT_180) { - xy.x = displayWidth - x; - xy.y = displayHeight - y; - } else if (orientation == ui::Transform::ROT_270) { - xy.x = y; - xy.y = displayWidth - x; - } - return xy; -} - -vec2 applyTransformWithoutTranslation(const ui::Transform& transform, float x, float y) { +vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { const vec2 transformedXy = transform.transform(x, y); const vec2 transformedOrigin = transform.transform(0, 0); return transformedXy - transformedOrigin; } -bool shouldDisregardWindowTranslation(uint32_t source) { +bool shouldDisregardTranslation(uint32_t source) { // Pointer events are the only type of events that refer to absolute coordinates on the display, // so we should apply the entire window transform. For other types of events, we should make // sure to not apply the window translation/offset. @@ -431,8 +408,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, float rawYCursorPosition, - uint32_t displayOrientation, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(id, deviceId, source, displayId, hmac); @@ -448,9 +424,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mYPrecision = yPrecision; mRawXCursorPosition = rawXCursorPosition; mRawYCursorPosition = rawYCursorPosition; - mDisplayOrientation = displayOrientation; - mDisplayWidth = displayWidth; - mDisplayHeight = displayHeight; + mRawTransform = rawTransform; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); @@ -474,9 +448,7 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYPrecision = other->mYPrecision; mRawXCursorPosition = other->mRawXCursorPosition; mRawYCursorPosition = other->mRawYCursorPosition; - mDisplayOrientation = other->mDisplayOrientation; - mDisplayWidth = other->mDisplayWidth; - mDisplayHeight = other->mDisplayHeight; + mRawTransform = other->mRawTransform; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; @@ -542,20 +514,19 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, if (!isPerWindowInputRotationEnabled()) return coords->getAxisValue(axis); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - // For compatibility, convert raw coordinates into "oriented screen space". Once app - // developers are educated about getRaw, we can consider removing this. - const vec2 xy = shouldDisregardWindowTranslation(mSource) - ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY()) - : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth, - mDisplayHeight); + // For compatibility, convert raw coordinates into logical display space. + const vec2 xy = shouldDisregardTranslation(mSource) + ? transformWithoutTranslation(mRawTransform, coords->getX(), coords->getY()) + : mRawTransform.transform(coords->getX(), coords->getY()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - // For compatibility, since we convert raw coordinates into "oriented screen space", we + // For compatibility, since we report raw coordinates in logical display space, we // need to convert the relative axes into the same orientation for consistency. - const vec2 relativeXy = rotatePoint(mDisplayOrientation, + const vec2 relativeXy = + transformWithoutTranslation(mRawTransform, coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; @@ -569,8 +540,8 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = shouldDisregardWindowTranslation(mSource) - ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY()) + const vec2 xy = shouldDisregardTranslation(mSource) + ? transformWithoutTranslation(mTransform, coords->getX(), coords->getY()) : mTransform.transform(coords->getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; @@ -578,11 +549,9 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { const vec2 relativeXy = - applyTransformWithoutTranslation(mTransform, - coords->getAxisValue( - AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue( - AMOTION_EVENT_AXIS_RELATIVE_Y)); + transformWithoutTranslation(mTransform, + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; } @@ -607,6 +576,8 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) { void MotionEvent::scale(float globalScaleFactor) { mTransform.set(mTransform.tx() * globalScaleFactor, mTransform.ty() * globalScaleFactor); + mRawTransform.set(mRawTransform.tx() * globalScaleFactor, + mRawTransform.ty() * globalScaleFactor); mXPrecision *= globalScaleFactor; mYPrecision *= globalScaleFactor; @@ -708,9 +679,11 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYPrecision = parcel->readFloat(); mRawXCursorPosition = parcel->readFloat(); mRawYCursorPosition = parcel->readFloat(); - mDisplayOrientation = parcel->readUint32(); - mDisplayWidth = parcel->readInt32(); - mDisplayHeight = parcel->readInt32(); + + result = android::readFromParcel(mRawTransform, *parcel); + if (result != OK) { + return result; + } mDownTime = parcel->readInt64(); mPointerProperties.clear(); @@ -770,9 +743,11 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYPrecision); parcel->writeFloat(mRawXCursorPosition); parcel->writeFloat(mRawYCursorPosition); - parcel->writeUint32(mDisplayOrientation); - parcel->writeInt32(mDisplayWidth); - parcel->writeInt32(mDisplayHeight); + + result = android::writeToParcel(mRawTransform, *parcel); + if (result != OK) { + return result; + } parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 91ab008161..02a5a0807b 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -203,6 +203,8 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { case InputMessage::Type::MOTION: { // int32_t eventId msg->body.motion.eventId = body.motion.eventId; + // uint32_t pointerCount + msg->body.motion.pointerCount = body.motion.pointerCount; // nsecs_t eventTime msg->body.motion.eventTime = body.motion.eventTime; // int32_t deviceId @@ -245,14 +247,14 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.xCursorPosition = body.motion.xCursorPosition; // float yCursorPosition msg->body.motion.yCursorPosition = body.motion.yCursorPosition; - // uint32_t displayOrientation - msg->body.motion.displayOrientation = body.motion.displayOrientation; - // int32_t displayWidth - msg->body.motion.displayWidth = body.motion.displayWidth; - // int32_t displayHeight - msg->body.motion.displayHeight = body.motion.displayHeight; - // uint32_t pointerCount - msg->body.motion.pointerCount = body.motion.pointerCount; + + msg->body.motion.dsdxRaw = body.motion.dsdxRaw; + msg->body.motion.dtdxRaw = body.motion.dtdxRaw; + msg->body.motion.dtdyRaw = body.motion.dtdyRaw; + msg->body.motion.dsdyRaw = body.motion.dsdyRaw; + msg->body.motion.txRaw = body.motion.txRaw; + msg->body.motion.tyRaw = body.motion.tyRaw; + //struct Pointer pointers[MAX_POINTERS] for (size_t i = 0; i < body.motion.pointerCount; i++) { // PointerProperties properties @@ -542,8 +544,8 @@ status_t InputPublisher::publishMotionEvent( std::array hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, - float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + float yPrecision, float xCursorPosition, float yCursorPosition, + const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { @@ -603,9 +605,12 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.yPrecision = yPrecision; msg.body.motion.xCursorPosition = xCursorPosition; msg.body.motion.yCursorPosition = yCursorPosition; - msg.body.motion.displayOrientation = displayOrientation; - msg.body.motion.displayWidth = displayWidth; - msg.body.motion.displayHeight = displayHeight; + msg.body.motion.dsdxRaw = rawTransform.dsdx(); + msg.body.motion.dtdxRaw = rawTransform.dtdx(); + msg.body.motion.dtdyRaw = rawTransform.dtdy(); + msg.body.motion.dsdyRaw = rawTransform.dsdy(); + msg.body.motion.txRaw = rawTransform.tx(); + msg.body.motion.tyRaw = rawTransform.ty(); msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; @@ -1391,6 +1396,10 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage ui::Transform transform; transform.set({msg->body.motion.dsdx, msg->body.motion.dtdx, msg->body.motion.tx, msg->body.motion.dtdy, msg->body.motion.dsdy, msg->body.motion.ty, 0, 0, 1}); + ui::Transform displayTransform; + displayTransform.set({msg->body.motion.dsdxRaw, msg->body.motion.dtdxRaw, + msg->body.motion.txRaw, msg->body.motion.dtdyRaw, + msg->body.motion.dsdyRaw, msg->body.motion.tyRaw, 0, 0, 1}); event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source, msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action, msg->body.motion.actionButton, msg->body.motion.flags, @@ -1398,9 +1407,8 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage msg->body.motion.buttonState, msg->body.motion.classification, transform, msg->body.motion.xPrecision, msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, - msg->body.motion.displayOrientation, msg->body.motion.displayWidth, - msg->body.motion.displayHeight, msg->body.motion.downTime, - msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); + displayTransform, msg->body.motion.downTime, msg->body.motion.eventTime, + pointerCount, pointerProperties, pointerCoords); } void InputConsumer::initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index b1ef7534e4..7e7dfd5416 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -226,11 +226,16 @@ protected: static constexpr float Y_SCALE = 3.0; static constexpr float X_OFFSET = 1; static constexpr float Y_OFFSET = 1.1; + static constexpr float RAW_X_SCALE = 4.0; + static constexpr float RAW_Y_SCALE = -5.0; + static constexpr float RAW_X_OFFSET = 12; + static constexpr float RAW_Y_OFFSET = -41.1; static const std::optional INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE; int32_t mId; ui::Transform mTransform; + ui::Transform mRawTransform; void SetUp() override; void TearDown() override; @@ -259,6 +264,7 @@ void MotionEventTest::TearDown() { void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { mId = InputEvent::nextId(); mTransform.set({X_SCALE, 0, X_OFFSET, 0, Y_SCALE, Y_OFFSET, 0, 0, 1}); + mRawTransform.set({RAW_X_SCALE, 0, RAW_X_OFFSET, 0, RAW_Y_SCALE, RAW_Y_OFFSET, 0, 0, 1}); PointerProperties pointerProperties[2]; pointerProperties[0].clear(); @@ -294,9 +300,8 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, mTransform, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, - pointerCoords); + mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, + pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -373,39 +378,37 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1)); ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime()); - ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(211, event->getRawPointerCoords(0)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(221, event->getRawPointerCoords(1)-> - getAxisValue(AMOTION_EVENT_AXIS_Y)); - - ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); - ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); - ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); - ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); - ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); - ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); - - ASSERT_EQ(10, event->getHistoricalRawX(0, 0)); - ASSERT_EQ(20, event->getHistoricalRawX(1, 0)); - ASSERT_EQ(110, event->getHistoricalRawX(0, 1)); - ASSERT_EQ(120, event->getHistoricalRawX(1, 1)); - ASSERT_EQ(210, event->getRawX(0)); - ASSERT_EQ(220, event->getRawX(1)); - - ASSERT_EQ(11, event->getHistoricalRawY(0, 0)); - ASSERT_EQ(21, event->getHistoricalRawY(1, 0)); - ASSERT_EQ(111, event->getHistoricalRawY(0, 1)); - ASSERT_EQ(121, event->getHistoricalRawY(1, 1)); - ASSERT_EQ(211, event->getRawY(0)); - ASSERT_EQ(221, event->getRawY(1)); + ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + ASSERT_EQ(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); + + ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); + + ASSERT_EQ(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0)); + ASSERT_EQ(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0)); + ASSERT_EQ(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1)); + ASSERT_EQ(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1)); + ASSERT_EQ(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0)); + ASSERT_EQ(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1)); + + ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0)); + ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1)); + ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0)); + ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1)); ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0)); ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0)); @@ -543,8 +546,8 @@ TEST_F(MotionEventTest, Scale) { ASSERT_EQ(X_OFFSET * 2, event.getXOffset()); ASSERT_EQ(Y_OFFSET * 2, event.getYOffset()); - ASSERT_EQ(210 * 2, event.getRawX(0)); - ASSERT_EQ(211 * 2, event.getRawY(0)); + ASSERT_EQ((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0)); + ASSERT_EQ((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0)); ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0)); ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0)); ASSERT_EQ(212, event.getPressure(0)); @@ -592,10 +595,10 @@ TEST_F(MotionEventTest, Transform) { // The geometrical representation is irrelevant to the test, it's just easy to generate // and check rotation. We set the orientation to the same angle. // Coordinate system: down is increasing Y, right is increasing X. - const float PI_180 = float(M_PI / 180); - const float RADIUS = 10; - const float ARC = 36; - const float ROTATION = ARC * 2; + static constexpr float PI_180 = float(M_PI / 180); + static constexpr float RADIUS = 10; + static constexpr float ARC = 36; + static constexpr float ROTATION = ARC * 2; const size_t pointerCount = 11; PointerProperties pointerProperties[pointerCount]; @@ -616,9 +619,8 @@ TEST_F(MotionEventTest, Transform) { AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, - pointerCoords); + identityTransform, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; @@ -661,7 +663,7 @@ TEST_F(MotionEventTest, Transform) { MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, const ui::Transform& transform, - uint32_t displayOrientation = ui::Transform::ROT_0) { + const ui::Transform& rawTransform) { std::vector pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector pointerCoords; @@ -677,19 +679,18 @@ MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation, - /* displayWidth */ 400, - /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), - pointerProperties.data(), pointerCoords.data()); + AMOTION_EVENT_INVALID_CURSOR_POSITION, rawTransform, eventTime, eventTime, + pointerCoords.size(), pointerProperties.data(), pointerCoords.data()); return event; } TEST_F(MotionEventTest, ApplyTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform identity; - ui::Transform xform(ui::Transform::ROT_90, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + ui::Transform rawTransform(ui::Transform::ROT_90, 800, 400); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, rawTransform); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); @@ -698,10 +699,10 @@ TEST_F(MotionEventTest, ApplyTransform) { ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity); - const std::array rowMajor{xform[0][0], xform[1][0], xform[2][0], - xform[0][1], xform[1][1], xform[2][1], - xform[0][2], xform[1][2], xform[2][2]}; + MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity, identity); + const std::array rowMajor{transform[0][0], transform[1][0], transform[2][0], + transform[0][1], transform[1][1], transform[2][1], + transform[0][2], transform[1][2], transform[2][2]}; changedEvent.applyTransform(rowMajor); // transformContent effectively rotates the raw coordinates, so those should now include @@ -727,9 +728,9 @@ TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { AINPUT_SOURCE_JOYSTICK}; for (uint32_t source : NON_POINTER_SOURCES) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). - ui::Transform xform(ui::Transform::ROT_90, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, transform); event.setSource(source); // Since this event comes from a non-pointer source, it should include rotation but not @@ -741,72 +742,34 @@ TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { } } -TEST_F(MotionEventTest, RawCompatTransform) { - { - // Make sure raw is raw regardless of transform translation. - ui::Transform xform; - xform.set(20, 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform); - ASSERT_EQ(60, event.getRawX(0)); - ASSERT_EQ(100, event.getRawY(0)); - ASSERT_NE(event.getRawX(0), event.getX(0)); - ASSERT_NE(event.getRawY(0), event.getY(0)); - // Relative values should not be modified. - ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } +TEST_F(MotionEventTest, AxesAreCorrectlyTransformed) { + const ui::Transform identity; + ui::Transform transform; + transform.set({1.1, -2.2, 3.3, -4.4, 5.5, -6.6, 0, 0, 1}); + ui::Transform rawTransform; + rawTransform.set({-6.6, 5.5, -4.4, 3.3, -2.2, 1.1, 0, 0, 1}); + auto transformWithoutTranslation = [](const ui::Transform& t, float x, float y) { + auto newPoint = t.transform(x, y); + auto newOrigin = t.transform(0, 0); + return newPoint - newOrigin; + }; - // Next check that getRaw contains rotation (for compatibility) but otherwise is still - // "Screen-space". The following tests check all 3 rotations. - { - // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). - ui::Transform xform(ui::Transform::ROT_90, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); - ASSERT_EQ(700, event.getRawX(0)); - ASSERT_EQ(60, event.getRawY(0)); - ASSERT_NE(event.getRawX(0), event.getX(0)); - ASSERT_NE(event.getRawY(0), event.getY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + const MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, rawTransform); - { - // Same as above, but check rotate-180. - ui::Transform xform(ui::Transform::ROT_180, 400, 800); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180); - ASSERT_EQ(340, event.getRawX(0)); - ASSERT_EQ(700, event.getRawY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + // The x and y axes should have the window transform applied. + const auto newPoint = transform.transform(60, 100); + ASSERT_EQ(newPoint.x, event.getX(0)); + ASSERT_EQ(newPoint.y, event.getY(0)); - { - // Same as above, but check rotate-270. - ui::Transform xform(ui::Transform::ROT_270, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270); - ASSERT_EQ(100, event.getRawX(0)); - ASSERT_EQ(340, event.getRawY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + // The raw values should have the display transform applied. + const auto raw = rawTransform.transform(60, 100); + ASSERT_EQ(raw.x, event.getRawX(0)); + ASSERT_EQ(raw.y, event.getRawY(0)); - { - // Finally, check that raw isn't effected by transform - ui::Transform xform(ui::Transform::ROT_270, 800, 400); - xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); - ASSERT_EQ(700, event.getRawX(0)); - ASSERT_EQ(60, event.getRawY(0)); - // Relative values should be rotated but not translated. - ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - } + // Relative values should have the window transform applied without any translation. + const auto rel = transformWithoutTranslation(transform, 42, 96); + ASSERT_EQ(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } TEST_F(MotionEventTest, Initialize_SetsClassification) { @@ -832,8 +795,7 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); } @@ -854,9 +816,9 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, - pointerCount, pointerProperties, pointerCoords); + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identityTransform, + 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, + pointerCoords); event.offsetLocation(20, 60); ASSERT_EQ(280, event.getRawXCursorPosition()); ASSERT_EQ(540, event.getRawYCursorPosition()); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 8db5bf1289..d09f2ac748 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -160,13 +160,14 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yScale = 3; constexpr float xOffset = -10; constexpr float yOffset = -20; + constexpr float rawXScale = 4; + constexpr float rawYScale = -5; + constexpr float rawXOffset = -11; + constexpr float rawYOffset = 42; constexpr float xPrecision = 0.25; constexpr float yPrecision = 0.5; constexpr float xCursorPosition = 1.3; constexpr float yCursorPosition = 50.6; - constexpr uint32_t displayOrientation = ui::Transform::ROT_0; - constexpr int32_t displayWidth = 1000; - constexpr int32_t displayHeight = 2000; constexpr nsecs_t downTime = 3; constexpr size_t pointerCount = 3; constexpr nsecs_t eventTime = 4; @@ -192,12 +193,14 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { ui::Transform transform; transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1}); + ui::Transform rawTransform; + rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1}); status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action, actionButton, flags, edgeFlags, metaState, buttonState, classification, transform, xPrecision, yPrecision, - xCursorPosition, yCursorPosition, displayOrientation, - displayWidth, displayHeight, downTime, eventTime, - pointerCount, pointerProperties, pointerCoords); + xCursorPosition, yCursorPosition, rawTransform, + downTime, eventTime, pointerCount, pointerProperties, + pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -234,9 +237,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition()); EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition()); - EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation()); - EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x); - EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y); + EXPECT_EQ(rawTransform, motionEvent->getRawTransform()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); @@ -247,28 +248,18 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - motionEvent->getRawX(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - motionEvent->getRawY(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) * xScale + xOffset, - motionEvent->getX(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) * yScale + yOffset, - motionEvent->getY(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - motionEvent->getPressure(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - motionEvent->getSize(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - motionEvent->getTouchMajor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - motionEvent->getTouchMinor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - motionEvent->getToolMajor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - motionEvent->getToolMinor(i)); - EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - motionEvent->getOrientation(i)); + const auto& pc = pointerCoords[i]; + EXPECT_EQ(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i)); + EXPECT_EQ(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i)); + EXPECT_EQ(pc.getX() * xScale + xOffset, motionEvent->getX(i)); + EXPECT_EQ(pc.getY() * yScale + yOffset, motionEvent->getY(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i)); + EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i)); } status = mConsumer->sendFinishedSignal(seq, false); @@ -505,12 +496,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer } ui::Transform identityTransform; - status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, - 0, 0, 0, MotionClassification::NONE, identityTransform, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, identityTransform, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -522,12 +513,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerCoords pointerCoords[pointerCount]; ui::Transform identityTransform; - status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, - 0, 0, 0, MotionClassification::NONE, identityTransform, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, identityTransform, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -544,12 +535,12 @@ TEST_F(InputPublisherAndConsumerTest, } ui::Transform identityTransform; - status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, - 0, 0, 0, MotionClassification::NONE, identityTransform, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, identityTransform, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 18289a5f11..2f88704d63 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -49,7 +49,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Key, downTime, 88); CHECK_OFFSET(InputMessage::Body::Motion, eventId, 0); - CHECK_OFFSET(InputMessage::Body::Motion, empty1, 4); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 4); CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); @@ -74,11 +74,13 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124); CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128); CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132); - CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136); - CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140); - CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148); - CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152); + CHECK_OFFSET(InputMessage::Body::Motion, dsdxRaw, 136); + CHECK_OFFSET(InputMessage::Body::Motion, dtdxRaw, 140); + CHECK_OFFSET(InputMessage::Body::Motion, dtdyRaw, 144); + CHECK_OFFSET(InputMessage::Body::Motion, dsdyRaw, 148); + CHECK_OFFSET(InputMessage::Body::Motion, txRaw, 152); + CHECK_OFFSET(InputMessage::Body::Motion, tyRaw, 156); + CHECK_OFFSET(InputMessage::Body::Motion, pointers, 160); CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 13e2b02ca4..3039362c2b 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -184,8 +184,7 @@ static std::vector createMotionEventStream( AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); events.emplace_back(event); diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp index b29c9a4877..f2b59ea9ab 100644 --- a/libs/input/tests/VerifiedInputEvent_test.cpp +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -43,12 +43,12 @@ static MotionEvent getMotionEventWithFlags(int32_t flags) { ui::Transform transform; transform.set({2, 0, 4, 0, 3, 5, 0, 0, 1}); + ui::Transform identity; event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/, + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identity, 100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); return event; } diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 6ce0313929..68d25f9ec7 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -236,8 +236,8 @@ static MotionEvent generateMotionEvent() { /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, currentTime, currentTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, currentTime, + currentTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); return event; } diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 571c126658..bcb00719cd 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -309,15 +309,14 @@ std::string SensorEntry::getDescription() const { volatile int32_t DispatchEntry::sNextSeqAtomic; DispatchEntry::DispatchEntry(std::shared_ptr eventEntry, int32_t targetFlags, - ui::Transform transform, float globalScaleFactor, - uint32_t displayOrientation, int2 displaySize) + const ui::Transform& transform, const ui::Transform& rawTransform, + float globalScaleFactor) : seq(nextSeq()), eventEntry(std::move(eventEntry)), targetFlags(targetFlags), transform(transform), + rawTransform(rawTransform), globalScaleFactor(globalScaleFactor), - displayOrientation(displayOrientation), - displaySize(displaySize), deliveryTime(0), resolvedAction(0), resolvedFlags(0) {} diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 5365a78b0a..7a121ce798 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -226,9 +226,8 @@ struct DispatchEntry { std::shared_ptr eventEntry; // the event to dispatch int32_t targetFlags; ui::Transform transform; + ui::Transform rawTransform; float globalScaleFactor; - uint32_t displayOrientation; - int2 displaySize; // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app, // and will be undefined before that. nsecs_t deliveryTime; // time when the event was actually delivered @@ -241,8 +240,8 @@ struct DispatchEntry { int32_t resolvedFlags; DispatchEntry(std::shared_ptr eventEntry, int32_t targetFlags, - ui::Transform transform, float globalScaleFactor, uint32_t displayOrientation, - int2 displaySize); + const ui::Transform& transform, const ui::Transform& rawTransform, + float globalScaleFactor); inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index da3e237e3e..22d2e9a97e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -346,18 +346,15 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge // Use identity transform for joystick and position-based (touchpad) events because they // don't depend on the window transform. return std::make_unique(eventEntry, inputTargetFlags, identityTransform, - 1.0f /*globalScaleFactor*/, - inputTarget.displayOrientation, - inputTarget.displaySize); + identityTransform, 1.0f /*globalScaleFactor*/); } } if (inputTarget.useDefaultPointerTransform()) { const ui::Transform& transform = inputTarget.getDefaultPointerTransform(); return std::make_unique(eventEntry, inputTargetFlags, transform, - inputTarget.globalScaleFactor, - inputTarget.displayOrientation, - inputTarget.displaySize); + inputTarget.displayTransform, + inputTarget.globalScaleFactor); } ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION); @@ -408,9 +405,8 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge std::unique_ptr dispatchEntry = std::make_unique(std::move(combinedMotionEntry), inputTargetFlags, - firstPointerTransform, inputTarget.globalScaleFactor, - inputTarget.displayOrientation, - inputTarget.displaySize); + firstPointerTransform, inputTarget.displayTransform, + inputTarget.globalScaleFactor); return dispatchEntry; } @@ -2347,7 +2343,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) { addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, - touchedMonitor.yOffset, inputTargets); + touchedMonitor.yOffset, displayId, inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -2526,9 +2522,7 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); if (displayInfoIt != mDisplayInfos.end()) { - const auto& displayInfo = displayInfoIt->second; - inputTarget.displayOrientation = displayInfo.transform.getOrientation(); - inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight); + inputTarget.displayTransform = displayInfoIt->second.transform; } else { ALOGI_IF(isPerWindowInputRotationEnabled(), "DisplayInfo not found for window on display: %d", windowInfo->displayId); @@ -2552,19 +2546,38 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector& if (it != mGlobalMonitorsByDisplay.end()) { const std::vector& monitors = it->second; for (const Monitor& monitor : monitors) { - addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets); + addMonitoringTargetLocked(monitor, xOffset, yOffset, displayId, inputTargets); } } } void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset, - float yOffset, + float yOffset, int32_t displayId, std::vector& inputTargets) { InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - ui::Transform t; - t.set(xOffset, yOffset); + ui::Transform t = ui::Transform(xOffset, yOffset); + if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { + // Input monitors always get un-rotated display coordinates. We undo the display + // rotation that is present in the display transform so that display rotation is not + // applied to these input targets. + const auto& displayInfo = it->second; + int32_t width = displayInfo.logicalWidth; + int32_t height = displayInfo.logicalHeight; + const auto orientation = displayInfo.transform.getOrientation(); + uint32_t inverseOrientation = orientation; + if (orientation == ui::Transform::ROT_90) { + inverseOrientation = ui::Transform::ROT_270; + std::swap(width, height); + } else if (orientation == ui::Transform::ROT_270) { + inverseOrientation = ui::Transform::ROT_90; + std::swap(width, height); + } + target.displayTransform = + ui::Transform(inverseOrientation, width, height) * displayInfo.transform; + t = t * target.displayTransform; + } target.setDefaultPointerTransform(t); inputTargets.push_back(target); } @@ -3250,9 +3263,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, motionEntry.xPrecision, motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, - dispatchEntry->displayOrientation, - dispatchEntry->displaySize.x, - dispatchEntry->displaySize.y, + dispatchEntry->rawTransform, motionEntry.downTime, motionEntry.eventTime, motionEntry.pointerCount, motionEntry.pointerProperties, usingCoords); @@ -3981,14 +3992,14 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - ui::Transform transform; + ui::Transform identityTransform; event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC, args->action, args->actionButton, args->flags, args->edgeFlags, - args->metaState, args->buttonState, args->classification, transform, - args->xPrecision, args->yPrecision, args->xCursorPosition, - args->yCursorPosition, ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, - INVALID_DISPLAY_SIZE, args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); + args->metaState, args->buttonState, args->classification, + identityTransform, args->xPrecision, args->yPrecision, + args->xCursorPosition, args->yCursorPosition, identityTransform, + args->downTime, args->eventTime, args->pointerCount, + args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 4f6d0d2759..e9fe2810d1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -525,7 +525,8 @@ private: int32_t targetFlags, BitSet32 pointerIds, std::vector& inputTargets) REQUIRES(mLock); void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, - std::vector& inputTargets) REQUIRES(mLock); + int32_t displayId, std::vector& inputTargets) + REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector& inputTargets, int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock); void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 7c463c8697..5b76eee343 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -101,11 +101,8 @@ struct InputTarget { // (ignored for KeyEvents) float globalScaleFactor = 1.0f; - // Current display orientation - uint32_t displayOrientation = ui::Transform::ROT_0; - - // Display-size in its natural rotation. Used for compatibility transform of raw coordinates. - int2 displaySize = {INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE}; + // Current display transform. Used for compatibility for raw coordinates. + ui::Transform displayTransform; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 903f337eb9..e9d45b22ad 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -542,8 +542,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -556,8 +556,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -569,8 +568,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -583,8 +581,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -596,8 +593,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, + identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -608,8 +604,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -619,8 +615,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -632,8 +628,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -644,8 +640,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -658,8 +654,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, + ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -1296,9 +1292,8 @@ public: mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE, mButtonState, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition, - mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight, - mEventTime, mEventTime, mPointers.size(), pointerProperties.data(), - pointerCoords.data()); + mRawYCursorPosition, identityTransform, mEventTime, mEventTime, + mPointers.size(), pointerProperties.data(), pointerCoords.data()); return event; } @@ -1313,9 +1308,6 @@ private: int32_t mFlags{0}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; - uint32_t mDisplayOrientation{ui::Transform::ROT_0}; - int32_t mDisplayWidth{INVALID_DISPLAY_SIZE}; - int32_t mDisplayHeight{INVALID_DISPLAY_SIZE}; std::vector mPointers; }; @@ -3622,8 +3614,7 @@ protected: DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, - 0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime, eventTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); -- cgit v1.2.3-59-g8ed1b From 44828cecf86354ca3a18dfca8d0d5c110c86da48 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 13 Sep 2021 11:00:22 -0700 Subject: FTL: Add clear() to containers Bug: 185536303 Test: ftl_test Change-Id: Icc13d1dcfdc006fd26a418e4904e5d2ce12724dd --- include/ftl/small_map.h | 6 ++++++ include/ftl/small_vector.h | 19 ++++++++++--------- include/ftl/static_vector.h | 12 ++++++++++-- libs/ftl/small_map_test.cpp | 17 +++++++++++++++++ libs/ftl/small_vector_test.cpp | 30 ++++++++++++++++++++++++++++++ libs/ftl/static_vector_test.cpp | 15 +++++++++++++++ 6 files changed, 88 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index bcaba82934..988431a7e9 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -237,6 +237,12 @@ class SmallMap final { // bool erase(const key_type& key) { return erase(key, begin()); } + // Removes all mappings. + // + // All iterators are invalidated. + // + void clear() { map_.clear(); } + private: iterator find(const key_type& key, iterator first) { return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; }); diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index 0341435813..65a953670d 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -151,8 +151,6 @@ class SmallVector final : ArrayTraits, ArrayComparators { DISPATCH(reference, back, noexcept) DISPATCH(const_reference, back, const) -#undef DISPATCH - reference operator[](size_type i) { return dynamic() ? std::get(vector_)[i] : std::get(vector_)[i]; } @@ -214,13 +212,15 @@ class SmallVector final : ArrayTraits, ArrayComparators { // // The last() and end() iterators are invalidated. // - void pop_back() { - if (dynamic()) { - std::get(vector_).pop_back(); - } else { - std::get(vector_).pop_back(); - } - } + DISPATCH(void, pop_back, noexcept) + + // Removes all elements. + // + // All iterators are invalidated. + // + DISPATCH(void, clear, noexcept) + +#undef DISPATCH // Erases an element, but does not preserve order. Rather than shifting subsequent elements, // this moves the last element to the slot of the erased element. @@ -345,6 +345,7 @@ class SmallVector final : ArrayTraits, return true; } + using Impl::clear; using Impl::pop_back; void unstable_erase(iterator it) { diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h index 96a1ae853d..cd7b92a758 100644 --- a/include/ftl/static_vector.h +++ b/include/ftl/static_vector.h @@ -189,8 +189,7 @@ class StaticVector final : ArrayTraits, } StaticVector& operator=(StaticVector&& other) { - std::destroy(begin(), end()); - size_ = 0; + clear(); swap(other); return *this; } @@ -280,6 +279,15 @@ class StaticVector final : ArrayTraits, // void pop_back() { unstable_erase(last()); } + // Removes all elements. + // + // All iterators are invalidated. + // + void clear() { + std::destroy(begin(), end()); + size_ = 0; + } + // Erases an element, but does not preserve order. Rather than shifting subsequent elements, // this moves the last element to the slot of the erased element. // diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp index 2e81022f38..c292108c46 100644 --- a/libs/ftl/small_map_test.cpp +++ b/libs/ftl/small_map_test.cpp @@ -345,4 +345,21 @@ TEST(SmallMap, Erase) { } } +TEST(SmallMap, Clear) { + SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3'); + + map.clear(); + + EXPECT_TRUE(map.empty()); + EXPECT_FALSE(map.dynamic()); + + map = ftl::init::map(1, '1')(2, '2')(3, '3'); + map.try_emplace(4, '4'); + + map.clear(); + + EXPECT_TRUE(map.empty()); + EXPECT_TRUE(map.dynamic()); +} + } // namespace android::test diff --git a/libs/ftl/small_vector_test.cpp b/libs/ftl/small_vector_test.cpp index 3a03e696d1..42374969f1 100644 --- a/libs/ftl/small_vector_test.cpp +++ b/libs/ftl/small_vector_test.cpp @@ -460,4 +460,34 @@ TEST(SmallVector, Destroy) { EXPECT_EQ(0, dead); } +TEST(SmallVector, Clear) { + int live = 0; + int dead = 0; + + SmallVector counts; + counts.emplace_back(live, dead); + counts.emplace_back(live, dead); + + counts.clear(); + + EXPECT_TRUE(counts.empty()); + EXPECT_FALSE(counts.dynamic()); + + EXPECT_EQ(2, live); + EXPECT_EQ(0, dead); + + live = 0; + counts.emplace_back(live, dead); + counts.emplace_back(live, dead); + counts.emplace_back(live, dead); + + counts.clear(); + + EXPECT_TRUE(counts.empty()); + EXPECT_TRUE(counts.dynamic()); + + EXPECT_EQ(3, live); + EXPECT_EQ(2, dead); +} + } // namespace android::test diff --git a/libs/ftl/static_vector_test.cpp b/libs/ftl/static_vector_test.cpp index cbe8dff527..2de3ad273e 100644 --- a/libs/ftl/static_vector_test.cpp +++ b/libs/ftl/static_vector_test.cpp @@ -396,4 +396,19 @@ TEST(StaticVector, Destroy) { EXPECT_EQ(0, dead); } +TEST(StaticVector, Clear) { + int live = 0; + int dead = 0; + + StaticVector counts; + counts.emplace_back(live, dead); + counts.emplace_back(live, dead); + + counts.clear(); + + EXPECT_TRUE(counts.empty()); + EXPECT_EQ(2, live); + EXPECT_EQ(0, dead); +} + } // namespace android::test -- cgit v1.2.3-59-g8ed1b From 187489657e13f5910961180af7aefb0f7c4c765a Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sun, 26 Sep 2021 18:47:58 -0700 Subject: FTL: Parametrize SmallMap key equality Bug: 185536303 Test: ftl_test Change-Id: I8cc8287c1dfcaf60350039323492de1ddb2101a9 --- include/ftl/initializer_list.h | 13 +++++++------ include/ftl/small_map.h | 21 +++++++++++---------- libs/ftl/small_map_test.cpp | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h index 769c09ff11..2102c253f1 100644 --- a/include/ftl/initializer_list.h +++ b/include/ftl/initializer_list.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -65,18 +66,18 @@ struct InitializerList, Types...> { std::tuple tuple; }; -template +template > struct KeyValue {}; // Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the // value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works // with the latter. -template -struct InitializerList, std::index_sequence, Types...> { +template +struct InitializerList, std::index_sequence, Types...> { // Accumulate the three arguments to std::pair's piecewise constructor. template [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList< - KeyValue, std::index_sequence, Types..., std::piecewise_construct_t, + KeyValue, std::index_sequence, Types..., std::piecewise_construct_t, std::tuple, std::tuple> { return {std::tuple_cat( std::move(tuple), @@ -94,9 +95,9 @@ template return InitializerList{}(std::forward(args)...); } -template +template , typename... Args> [[nodiscard]] constexpr auto map(Args&&... args) { - return list>(std::forward(args)...); + return list>(std::forward(args)...); } template diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 988431a7e9..2effaa437c 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -61,7 +61,7 @@ namespace android::ftl { // // assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); // -template +template > class SmallMap final { using Map = SmallVector, N>; @@ -153,7 +153,7 @@ class SmallMap final { auto get(const key_type& key, F f) const -> std::conditional_t, bool, std::optional> { for (auto& [k, v] : *this) { - if (k == key) { + if (KeyEqual{}(k, key)) { if constexpr (std::is_void_v) { f(v); return true; @@ -245,7 +245,8 @@ class SmallMap final { private: iterator find(const key_type& key, iterator first) { - return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; }); + return std::find_if(first, end(), + [&key](const auto& pair) { return KeyEqual{}(pair.first, key); }); } bool erase(const key_type& key, iterator first) { @@ -267,13 +268,13 @@ class SmallMap final { }; // Deduction guide for in-place constructor. -template -SmallMap(InitializerList, std::index_sequence, Types...>&&) - -> SmallMap; +template +SmallMap(InitializerList, std::index_sequence, Types...>&&) + -> SmallMap; // Returns whether the key-value pairs of two maps are equal. -template -bool operator==(const SmallMap& lhs, const SmallMap& rhs) { +template +bool operator==(const SmallMap& lhs, const SmallMap& rhs) { if (lhs.size() != rhs.size()) return false; for (const auto& [k, v] : lhs) { @@ -287,8 +288,8 @@ bool operator==(const SmallMap& lhs, const SmallMap& rhs) { } // TODO: Remove in C++20. -template -inline bool operator!=(const SmallMap& lhs, const SmallMap& rhs) { +template +inline bool operator!=(const SmallMap& lhs, const SmallMap& rhs) { return !(lhs == rhs); } diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp index c292108c46..ee650e5627 100644 --- a/libs/ftl/small_map_test.cpp +++ b/libs/ftl/small_map_test.cpp @@ -362,4 +362,24 @@ TEST(SmallMap, Clear) { EXPECT_TRUE(map.dynamic()); } +TEST(SmallMap, KeyEqual) { + struct KeyEqual { + bool operator()(int lhs, int rhs) const { return lhs % 10 == rhs % 10; } + }; + + SmallMap map; + + EXPECT_TRUE(map.try_emplace(3, '3').second); + EXPECT_FALSE(map.try_emplace(13, '3').second); + + EXPECT_TRUE(map.try_emplace(22, '2').second); + EXPECT_TRUE(map.contains(42)); + + EXPECT_TRUE(map.try_emplace(111, '1').second); + EXPECT_EQ(map.get(321), '1'); + + map.erase(123); + EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(2, '2'))); +} + } // namespace android::test -- cgit v1.2.3-59-g8ed1b From 4879d8144abedcc77d9c42186b20ff0557bdca2a Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 25 Aug 2021 11:50:11 -0700 Subject: Choreographer: add new NDK APIs for callback data. Bug: 198191648 Bug: 168552873 Test: atest ChoreographerNativeTest Change-Id: I2472acb7b724354b657fc89983fade7ced5eb7eb --- include/android/choreographer.h | 58 ++++++ libs/nativedisplay/AChoreographer.cpp | 205 ++++++++++++++++++--- .../private/android/choreographer.h | 15 ++ libs/nativedisplay/libnativedisplay.map.txt | 14 ++ 4 files changed, 264 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/android/choreographer.h b/include/android/choreographer.h index b743f491e4..0389e573a2 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -39,6 +39,12 @@ struct AChoreographer; */ typedef struct AChoreographer AChoreographer; +struct AChoreographerFrameCallbackData; +/** + * Opaque type that provides access to an AChoreographerFrameCallbackData object. + */ +typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData; + /** * Prototype of the function that is called when a new frame is being rendered. * It's passed the time that the frame is being rendered as nanoseconds in the @@ -59,6 +65,14 @@ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); */ typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data); +/** + * Prototype of the function that is called when a new frame is being rendered. + * It's passed the frame data that should not outlive the callback, as well as the data pointer + * provided by the application that registered a callback. + */ +typedef void (*AChoreographer_extendedFrameCallback)( + const AChoreographerFrameCallbackData* callbackData, void* data); + /** * Prototype of the function that is called when the display refresh rate * changes. It's passed the new vsync period in nanoseconds, as well as the data @@ -110,6 +124,14 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29); +/** + * Posts a callback to run on the next frame. The data pointer provided will + * be passed to the callback function when it's called. + */ +void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer, + AChoreographer_extendedFrameCallback callback, void* data) + __INTRODUCED_IN(33); + /** * Registers a callback to be run when the display refresh rate changes. The * data pointer provided will be passed to the callback function when it's @@ -160,6 +182,42 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback, void* data) __INTRODUCED_IN(30); +/** + * The time in nanoseconds when the frame started being rendered. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimeNanos( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * The number of possible frame timelines. + */ +size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * Get index of the platform-preferred FrameTimeline. + */ +size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( + const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); + +/** + * The vsync ID token used to map Choreographer data. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + +/** + * The time in nanoseconds which the frame at given index is expected to be presented. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + +/** + * The time in nanoseconds which the frame at given index needs to be ready by. + */ +int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( + const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_CHOREOGRAPHER_H diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index ba71960751..4c4a34f7e2 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -77,6 +77,7 @@ namespace android { struct FrameCallback { AChoreographer_frameCallback callback; AChoreographer_frameCallback64 callback64; + AChoreographer_extendedFrameCallback extendedCallback; void* data; nsecs_t dueTime; @@ -95,6 +96,27 @@ struct RefreshRateCallback { class Choreographer; +/** + * Implementation of AChoreographerFrameCallbackData. + */ +struct ChoreographerFrameCallbackDataImpl { + struct FrameTimeline { + int64_t vsyncId{0}; + int64_t expectedPresentTimeNanos{0}; + int64_t deadlineNanos{0}; + }; + + int64_t frameTimeNanos{0}; + + size_t frameTimelinesLength; + + std::vector frameTimelines; + + size_t preferredFrameTimelineIndex; + + const Choreographer* choreographer; +}; + struct { std::mutex lock; std::vector ptrs GUARDED_BY(lock); @@ -107,7 +129,9 @@ class Choreographer : public DisplayEventDispatcher, public MessageHandler { public: explicit Choreographer(const sp& looper) EXCLUDES(gChoreographers.lock); void postFrameCallbackDelayed(AChoreographer_frameCallback cb, - AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay); + AChoreographer_frameCallback64 cb64, + AChoreographer_extendedFrameCallback extendedCallback, void* data, + nsecs_t delay); void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) EXCLUDES(gChoreographers.lock); void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); @@ -130,6 +154,7 @@ public: int64_t getVsyncId() const; int64_t getFrameDeadline() const; int64_t getFrameInterval() const; + bool inCallback() const; private: Choreographer(const Choreographer&) = delete; @@ -145,6 +170,8 @@ private: void scheduleCallbacks(); + ChoreographerFrameCallbackDataImpl createFrameCallbackData(nsecs_t timestamp) const; + std::mutex mLock; // Protected by mLock std::priority_queue mFrameCallbacks; @@ -152,6 +179,7 @@ private: nsecs_t mLatestVsyncPeriod = -1; VsyncEventData mLastVsyncEventData; + bool mInCallback = false; const sp mLooper; const std::thread::id mThreadId; @@ -211,10 +239,12 @@ Choreographer::~Choreographer() { } } -void Choreographer::postFrameCallbackDelayed( - AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) { +void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb, + AChoreographer_frameCallback64 cb64, + AChoreographer_extendedFrameCallback extendedCallback, + void* data, nsecs_t delay) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - FrameCallback callback{cb, cb64, data, now + delay}; + FrameCallback callback{cb, cb64, extendedCallback, data, now + delay}; { std::lock_guard _l{mLock}; mFrameCallbacks.push(callback); @@ -370,7 +400,15 @@ void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t } mLastVsyncEventData = vsyncEventData; for (const auto& cb : callbacks) { - if (cb.callback64 != nullptr) { + if (cb.extendedCallback != nullptr) { + const ChoreographerFrameCallbackDataImpl frameCallbackData = + createFrameCallbackData(timestamp); + mInCallback = true; + cb.extendedCallback(reinterpret_cast( + &frameCallbackData), + cb.data); + mInCallback = false; + } else if (cb.callback64 != nullptr) { cb.callback64(timestamp, cb.data); } else if (cb.callback != nullptr) { cb.callback(timestamp, cb.data); @@ -379,8 +417,8 @@ void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t } void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) { - ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", - this, to_string(displayId).c_str(), toString(connected)); + ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this, + to_string(displayId).c_str(), toString(connected)); } void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) { @@ -399,15 +437,15 @@ void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) { void Choreographer::handleMessage(const Message& message) { switch (message.what) { - case MSG_SCHEDULE_CALLBACKS: - scheduleCallbacks(); - break; - case MSG_SCHEDULE_VSYNC: - scheduleVsync(); - break; - case MSG_HANDLE_REFRESH_RATE_UPDATES: - handleRefreshRateUpdates(); - break; + case MSG_SCHEDULE_CALLBACKS: + scheduleCallbacks(); + break; + case MSG_SCHEDULE_VSYNC: + scheduleVsync(); + break; + case MSG_HANDLE_REFRESH_RATE_UPDATES: + handleRefreshRateUpdates(); + break; } } @@ -423,6 +461,22 @@ int64_t Choreographer::getFrameInterval() const { return mLastVsyncEventData.frameInterval; } +bool Choreographer::inCallback() const { + return mInCallback; +} + +ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { + std::vector frameTimelines; + frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id, + .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime, + .deadlineNanos = mLastVsyncEventData.deadlineTimestamp}); + return {.frameTimeNanos = timestamp, + .frameTimelinesLength = 1, + .preferredFrameTimelineIndex = 0, + .frameTimelines = frameTimelines, + .choreographer = this}; +} + } // namespace android using namespace android; @@ -435,6 +489,12 @@ static inline const Choreographer* AChoreographer_to_Choreographer( return reinterpret_cast(choreographer); } +static inline const ChoreographerFrameCallbackDataImpl* +AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl( + const AChoreographerFrameCallbackData* data) { + return reinterpret_cast(data); +} + // Glue for private C api namespace android { void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) { @@ -487,6 +547,11 @@ void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographe void* data, uint32_t delayMillis) { return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis); } +void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer, + AChoreographer_extendedFrameCallback callback, + void* data) { + return AChoreographer_postExtendedFrameCallback(choreographer, callback, data); +} void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback callback, void* data) { @@ -497,6 +562,30 @@ void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreogra void* data) { return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data); } +int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos( + const AChoreographerFrameCallbackData* data) { + return AChoreographerFrameCallbackData_getFrameTimeNanos(data); +} +size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength( + const AChoreographerFrameCallbackData* data) { + return AChoreographerFrameCallbackData_getFrameTimelinesLength(data); +} +size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex( + const AChoreographerFrameCallbackData* data) { + return AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(data); +} +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( + const AChoreographerFrameCallbackData* data, size_t index) { + return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index); +} +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime( + const AChoreographerFrameCallbackData* data, size_t index) { + return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(data, index); +} +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline( + const AChoreographerFrameCallbackData* data, size_t index) { + return AChoreographerFrameCallbackData_getFrameTimelineDeadline(data, index); +} int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) { return AChoreographer_to_Choreographer(choreographer)->getVsyncId(); @@ -523,24 +612,32 @@ AChoreographer* AChoreographer_getInstance() { } void AChoreographer_postFrameCallback(AChoreographer* choreographer, - AChoreographer_frameCallback callback, void* data) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - callback, nullptr, data, 0); + AChoreographer_frameCallback callback, void* data) { + AChoreographer_to_Choreographer(choreographer) + ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0); } void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, - AChoreographer_frameCallback callback, void* data, long delayMillis) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - callback, nullptr, data, ms2ns(delayMillis)); + AChoreographer_frameCallback callback, void* data, + long delayMillis) { + AChoreographer_to_Choreographer(choreographer) + ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis)); +} +void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer, + AChoreographer_extendedFrameCallback callback, + void* data) { + AChoreographer_to_Choreographer(choreographer) + ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0); } void AChoreographer_postFrameCallback64(AChoreographer* choreographer, - AChoreographer_frameCallback64 callback, void* data) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - nullptr, callback, data, 0); + AChoreographer_frameCallback64 callback, void* data) { + AChoreographer_to_Choreographer(choreographer) + ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0); } void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, - AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - nullptr, callback, data, ms2ns(delayMillis)); + AChoreographer_frameCallback64 callback, void* data, + uint32_t delayMillis) { + AChoreographer_to_Choreographer(choreographer) + ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis)); } void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback callback, @@ -553,6 +650,58 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data); } +int64_t AChoreographerFrameCallbackData_getFrameTimeNanos( + const AChoreographerFrameCallbackData* data) { + const ChoreographerFrameCallbackDataImpl* frameCallbackData = + AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); + LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), + "Data is only valid in callback"); + return frameCallbackData->frameTimeNanos; +} +size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( + const AChoreographerFrameCallbackData* data) { + const ChoreographerFrameCallbackDataImpl* frameCallbackData = + AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); + LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), + "Data is only valid in callback"); + return frameCallbackData->frameTimelinesLength; +} +size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( + const AChoreographerFrameCallbackData* data) { + const ChoreographerFrameCallbackDataImpl* frameCallbackData = + AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); + LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), + "Data is only valid in callback"); + return frameCallbackData->preferredFrameTimelineIndex; +} +int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( + const AChoreographerFrameCallbackData* data, size_t index) { + const ChoreographerFrameCallbackDataImpl* frameCallbackData = + AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); + LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), + "Data is only valid in callback"); + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].vsyncId; +} +int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( + const AChoreographerFrameCallbackData* data, size_t index) { + const ChoreographerFrameCallbackDataImpl* frameCallbackData = + AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); + LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), + "Data is only valid in callback"); + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos; +} +int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( + const AChoreographerFrameCallbackData* data, size_t index) { + const ChoreographerFrameCallbackDataImpl* frameCallbackData = + AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); + LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), + "Data is only valid in callback"); + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].deadlineNanos; +} + AChoreographer* AChoreographer_create() { Choreographer* choreographer = new Choreographer(nullptr); status_t result = choreographer->initialize(); diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h index 7d25ce8253..6e90853b51 100644 --- a/libs/nativedisplay/include-private/private/android/choreographer.h +++ b/libs/nativedisplay/include-private/private/android/choreographer.h @@ -63,11 +63,26 @@ void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer, void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer, AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis); +void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer, + AChoreographer_extendedFrameCallback callback, + void* data); void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback callback, void* data); void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer, AChoreographer_refreshRateCallback callback, void* data); +int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos( + const AChoreographerFrameCallbackData* data); +size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength( + const AChoreographerFrameCallbackData* data); +size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex( + const AChoreographerFrameCallbackData* data); +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( + const AChoreographerFrameCallbackData* data, size_t index); +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime( + const AChoreographerFrameCallbackData* data, size_t index); +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline( + const AChoreographerFrameCallbackData* data, size_t index); } // namespace android diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt index 9ed4915481..b4a70e871c 100644 --- a/libs/nativedisplay/libnativedisplay.map.txt +++ b/libs/nativedisplay/libnativedisplay.map.txt @@ -7,6 +7,13 @@ LIBNATIVEDISPLAY { AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30 AChoreographer_registerRefreshRateCallback; # apex # introduced=30 AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30 + AChoreographer_postExtendedFrameCallback; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33 + AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineDeadline; # apex # introduced=33 AChoreographer_create; # apex # introduced=30 AChoreographer_destroy; # apex # introduced=30 AChoreographer_getFd; # apex # introduced=30 @@ -28,6 +35,13 @@ LIBNATIVEDISPLAY_PLATFORM { android::AChoreographer_routePostFrameCallbackDelayed64*; android::AChoreographer_routeRegisterRefreshRateCallback*; android::AChoreographer_routeUnregisterRefreshRateCallback*; + android::AChoreographer_routePostExtendedFrameCallback*; + android::AChoreographerFrameCallbackData_routeGetFrameTimeNanos*; + android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*; + android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*; + android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*; + android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime*; + android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline*; android::AChoreographer_signalRefreshRateCallbacks*; android::AChoreographer_getVsyncId*; android::AChoreographer_getFrameDeadline*; -- cgit v1.2.3-59-g8ed1b From b5cb957254201f19a434898c249d59752e2a88b7 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 24 Sep 2021 06:35:16 -0700 Subject: VerifiedMotionEvent: Sign transformed raw values The values for axes X/Y that are stored in MotionEvent are transformed to values used for its getRaw API based on the source. This is because non-pointer sources should not have translation applied to them. We need to ensure that we use the same raw coordinates when we sign a VerifiedMotionEvent in InputDispatcher that we would get with the MotionEvent#getRaw API. To do this, we re-use the same logic used to transform the raw coordinates in MotionEvent in InputDispatcher. Bug: 179274888 Test: atest inputflinger_tests Test: atest VerifyInputEventTest Change-Id: I552f94064f15573ddda8f7c0b588cd3b984b6a94 --- include/input/Input.h | 2 ++ libs/input/Input.cpp | 29 +++++++++++----------- services/inputflinger/dispatcher/Entry.cpp | 11 ++++---- services/inputflinger/dispatcher/Entry.h | 3 ++- .../inputflinger/dispatcher/InputDispatcher.cpp | 16 ++++++------ .../inputflinger/tests/InputDispatcher_test.cpp | 16 +++++++++--- 6 files changed, 46 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index d397313ab6..5015e68121 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -801,6 +801,8 @@ public: static std::string actionToString(int32_t action); + static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); + protected: int32_t mAction; int32_t mActionButton; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index a1542c8793..1bc244c653 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -65,8 +65,8 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return result; } -vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { - const vec2 transformedXy = transform.transform(x, y); +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); const vec2 transformedOrigin = transform.transform(0, 0); return transformedXy - transformedOrigin; } @@ -501,21 +501,16 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - // For compatibility, convert raw coordinates into logical display space. - const vec2 xy = shouldDisregardTranslation(mSource) - ? transformWithoutTranslation(mRawTransform, coords->getX(), coords->getY()) - : mRawTransform.transform(coords->getX(), coords->getY()); + const vec2 xy = calculateTransformedXY(mSource, mRawTransform, coords->getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - // For compatibility, since we report raw coordinates in logical display space, we - // need to convert the relative axes into the same orientation for consistency. const vec2 relativeXy = transformWithoutTranslation(mRawTransform, - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; } @@ -527,9 +522,7 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = shouldDisregardTranslation(mSource) - ? transformWithoutTranslation(mTransform, coords->getX(), coords->getY()) - : mTransform.transform(coords->getXYValue()); + const vec2 xy = calculateTransformedXY(mSource, mTransform, coords->getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } @@ -537,8 +530,8 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { const vec2 relativeXy = transformWithoutTranslation(mTransform, - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; } @@ -815,6 +808,12 @@ std::string MotionEvent::actionToString(int32_t action) { return android::base::StringPrintf("%" PRId32, action); } +vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform, + const vec2& xy) { + return shouldDisregardTranslation(source) ? transformWithoutTranslation(transform, xy) + : transform.transform(xy); +} + // --- FocusEvent --- void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index bcb00719cd..c03581d8da 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -40,14 +40,15 @@ VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) { entry.repeatCount}; } -VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry) { - const float rawX = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X); - const float rawY = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y); +VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry, + const ui::Transform& rawTransform) { + const vec2 rawXY = MotionEvent::calculateTransformedXY(entry.source, rawTransform, + entry.pointerCoords[0].getXYValue()); const int actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK; return {{VerifiedInputEvent::Type::MOTION, entry.deviceId, entry.eventTime, entry.source, entry.displayId}, - rawX, - rawY, + rawXY.x, + rawXY.y, actionMasked, entry.downTime, entry.flags & VERIFIED_MOTION_EVENT_FLAGS, diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 7a121ce798..477781a2ad 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -254,7 +254,8 @@ private: }; VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry); -VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry); +VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry, + const ui::Transform& rawTransform); } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 695dd17d38..52a88d7f62 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3360,16 +3360,18 @@ std::array InputDispatcher::sign(const VerifiedInputEvent& event) c const std::array InputDispatcher::getSignature( const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const { - int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK; - if ((actionMasked == AMOTION_EVENT_ACTION_UP) || (actionMasked == AMOTION_EVENT_ACTION_DOWN)) { + const int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK; + if (actionMasked != AMOTION_EVENT_ACTION_UP && actionMasked != AMOTION_EVENT_ACTION_DOWN) { // Only sign events up and down events as the purely move events // are tied to their up/down counterparts so signing would be redundant. - VerifiedMotionEvent verifiedEvent = verifiedMotionEventFromMotionEntry(motionEntry); - verifiedEvent.actionMasked = actionMasked; - verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS; - return sign(verifiedEvent); + return INVALID_HMAC; } - return INVALID_HMAC; + + VerifiedMotionEvent verifiedEvent = + verifiedMotionEventFromMotionEntry(motionEntry, dispatchEntry.rawTransform); + verifiedEvent.actionMasked = actionMasked; + verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS; + return sign(verifiedEvent); } const std::array InputDispatcher::getSignature( diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 42d3e58545..ca77d7ac0a 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2801,7 +2801,14 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + ui::Transform transform; + transform.set({1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0, 0, 1}); + + gui::DisplayInfo displayInfo; + displayInfo.displayId = ADISPLAY_ID_DEFAULT; + displayInfo.transform = transform; + + mDispatcher->onWindowInfosChanged({*window->getInfo()}, {displayInfo}); NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -2822,8 +2829,11 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { const VerifiedMotionEvent& verifiedMotion = static_cast(*verified); - EXPECT_EQ(motionArgs.pointerCoords[0].getX(), verifiedMotion.rawX); - EXPECT_EQ(motionArgs.pointerCoords[0].getY(), verifiedMotion.rawY); + const vec2 rawXY = + MotionEvent::calculateTransformedXY(motionArgs.source, transform, + motionArgs.pointerCoords[0].getXYValue()); + EXPECT_EQ(rawXY.x, verifiedMotion.rawX); + EXPECT_EQ(rawXY.y, verifiedMotion.rawY); EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked); EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos); EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags); -- cgit v1.2.3-59-g8ed1b From 9eb02c0ae27754f7230b4cfbd1d34bd837223c6f Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 19 Oct 2021 14:02:20 -0700 Subject: MotionEvent: Report transformed orientation values Previously, the AXIS_ORIENTATION value reported by MotionEvent was unaffected by the window transform. This meant that whatever value that was generated by InputReader was the value reported to the window. This meant that if the window was rotated or scaled respective to the logical display and the window received an event, it could be the case that the 0 value no longer corresponds with the "up" direction of the window. Now that the input pipeline works in the display panel's coordinate system, we need the orientation value reported by MotionEvent to be affected by the window transform. This CL also refactors the shared logic by which transformed axis values are calculated into a common function. Bug: 179274888 Test: atest libinput_tests Test: atest inputflinger_tests Test: manual with test app and stylus Change-Id: Ibb6f135de47f7c1cbde3c023931a760dfbe08e45 --- include/input/Input.h | 3 + libs/input/Input.cpp | 71 +++++++++------------- libs/input/tests/InputEvent_test.cpp | 22 ++++--- .../input/tests/InputPublisherAndConsumer_test.cpp | 8 ++- 4 files changed, 53 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 5015e68121..54c71140eb 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -803,6 +803,9 @@ public: static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); + static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&, + const PointerCoords&); + protected: int32_t mAction; int32_t mActionButton; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index b4d9ab623c..d018800c90 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -493,44 +493,14 @@ const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { - const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); - - if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = calculateTransformedXY(mSource, mRawTransform, coords->getXYValue()); - static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); - return xy[axis]; - } - - if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - const vec2 relativeXy = - transformWithoutTranslation(mRawTransform, - {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); - return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; - } - - return coords->getAxisValue(axis); + const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex); + return calculateTransformedAxisValue(axis, mSource, mRawTransform, coords); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { - const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); - - if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = calculateTransformedXY(mSource, mTransform, coords->getXYValue()); - static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); - return xy[axis]; - } - - if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { - const vec2 relativeXy = - transformWithoutTranslation(mTransform, - {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); - return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; - } - - return coords->getAxisValue(axis); + const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex); + return calculateTransformedAxisValue(axis, mSource, mTransform, coords); } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { @@ -569,15 +539,6 @@ void MotionEvent::transform(const std::array& matrix) { ui::Transform newTransform; newTransform.set(matrix); mTransform = newTransform * mTransform; - - // We need to update the AXIS_ORIENTATION value here to maintain the old behavior where the - // orientation angle is not affected by the initial transformation set in the MotionEvent. - std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(), - [&newTransform](PointerCoords& c) { - float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, - transformAngle(newTransform, orientation)); - }); } void MotionEvent::applyTransform(const std::array& matrix) { @@ -809,6 +770,30 @@ vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& t : transform.transform(xy); } +float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, + const ui::Transform& transform, + const PointerCoords& coords) { + if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { + const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue()); + static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); + return xy[axis]; + } + + if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { + const vec2 relativeXy = + transformWithoutTranslation(transform, + {coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)}); + return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; + } + + if (axis == AMOTION_EVENT_AXIS_ORIENTATION) { + return transformAngle(transform, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + } + + return coords.getAxisValue(axis); +} + // --- FocusEvent --- void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index caf3a611e2..1b594f142e 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -444,12 +444,19 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(217, event->getToolMinor(0)); ASSERT_EQ(227, event->getToolMinor(1)); - ASSERT_EQ(18, event->getHistoricalOrientation(0, 0)); - ASSERT_EQ(28, event->getHistoricalOrientation(1, 0)); - ASSERT_EQ(118, event->getHistoricalOrientation(0, 1)); - ASSERT_EQ(128, event->getHistoricalOrientation(1, 1)); - ASSERT_EQ(218, event->getOrientation(0)); - ASSERT_EQ(228, event->getOrientation(1)); + // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is "up", + // and the positive y direction is "down". + auto toScaledOrientation = [](float angle) { + const float x = sinf(angle) * X_SCALE; + const float y = -cosf(angle) * Y_SCALE; + return atan2f(x, -y); + }; + ASSERT_EQ(toScaledOrientation(18), event->getHistoricalOrientation(0, 0)); + ASSERT_EQ(toScaledOrientation(28), event->getHistoricalOrientation(1, 0)); + ASSERT_EQ(toScaledOrientation(118), event->getHistoricalOrientation(0, 1)); + ASSERT_EQ(toScaledOrientation(128), event->getHistoricalOrientation(1, 1)); + ASSERT_EQ(toScaledOrientation(218), event->getOrientation(0)); + ASSERT_EQ(toScaledOrientation(228), event->getOrientation(1)); } TEST_F(MotionEventTest, Properties) { @@ -518,6 +525,7 @@ TEST_F(MotionEventTest, OffsetLocation) { TEST_F(MotionEventTest, Scale) { MotionEvent event; initializeEventWithHistory(&event); + const float unscaledOrientation = event.getOrientation(0); event.scale(2.0f); @@ -534,7 +542,7 @@ TEST_F(MotionEventTest, Scale) { ASSERT_EQ(215 * 2, event.getTouchMinor(0)); ASSERT_EQ(216 * 2, event.getToolMajor(0)); ASSERT_EQ(217 * 2, event.getToolMinor(0)); - ASSERT_EQ(218, event.getOrientation(0)); + ASSERT_EQ(unscaledOrientation, event.getOrientation(0)); } TEST_F(MotionEventTest, Parcel) { diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index d09f2ac748..973194c8f6 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -259,7 +259,13 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i)); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i)); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i)); - EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i)); + + // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is + // "up", and the positive y direction is "down". + const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); + const float x = sinf(unscaledOrientation) * xScale; + const float y = -cosf(unscaledOrientation) * yScale; + EXPECT_EQ(atan2f(x, -y), motionEvent->getOrientation(i)); } status = mConsumer->sendFinishedSignal(seq, false); -- cgit v1.2.3-59-g8ed1b From a64c272fa2fac03883ec858fcd5ceabcc6b0b1d1 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 1 Sep 2021 16:39:16 +0100 Subject: Give access to the native InputQueue to all native applications. Bug: 116830907 Test: atest android.view.cts.InputQueueTest#testNativeInputQueue Change-Id: Ia92de418fe3407d0fa074f9fcb45d8844acbdf59 --- include/android/input.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/android/input.h b/include/android/input.h index 6d2c1b3015..27587ce483 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -1385,6 +1385,14 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); */ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); +/** + * Supplies the AInputQueue* object associated with the supplied Java InputQueue + * object. + * + * Available since API level 33. + */ +AInputQueue* AInputQueue_fromJava(jobject inputQueue) __INTRODUCED_IN(33); + #ifdef __cplusplus } #endif -- cgit v1.2.3-59-g8ed1b From 7e1ee565b3fe4738e6771bceb2e9679562232992 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 26 Oct 2021 10:19:49 -0700 Subject: Move Joystick and Touchpad event transformation logic to MotionEvent We would like to have all source and axis based transformations calculated in the same place, which will be in the MotionEvent class. This has the added benefit that MotionEvents created by developers through MotionEvent.obtain() in Java will behave like motion events generated from input devices in terms of how they're affected by transformations. Since axes from joysticks and touchpads should never be transfomred, we previously solved this by using identity matrices for them in InputDispatcher. Now, we move that logic to MotionEvent when applying the transform. Bug: 179274888 Test: atest libinput_test Test: atest inputflinger_tests Change-Id: Ic02466e01f2ba3131aca73bd10933ff81cb38cc9 --- include/input/Input.h | 5 +- libs/input/Input.cpp | 36 +++++++++++--- libs/input/tests/InputEvent_test.cpp | 57 ++++++++++++++++------ .../inputflinger/dispatcher/InputDispatcher.cpp | 12 ----- .../inputflinger/tests/InputDispatcher_test.cpp | 53 -------------------- 5 files changed, 77 insertions(+), 86 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 54c71140eb..7cc595a264 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -801,8 +801,11 @@ public: static std::string actionToString(int32_t action); + // MotionEvent will transform various axes in different ways, based on the source. For + // example, the x and y axes will not have any offsets/translations applied if it comes from a + // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods + // are used to apply these transformations for different axes. static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy); - static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&, const PointerCoords&); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index d018800c90..24a77209c4 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -66,11 +66,21 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) return transformedXy - transformedOrigin; } -bool shouldDisregardTranslation(uint32_t source) { +bool isFromSource(uint32_t source, uint32_t test) { + return (source & test) == test; +} + +bool shouldDisregardTransformation(uint32_t source) { + // Do not apply any transformations to axes from joysticks or touchpads. + return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || + isFromSource(source, AINPUT_SOURCE_CLASS_POSITION); +} + +bool shouldDisregardOffset(uint32_t source) { // Pointer events are the only type of events that refer to absolute coordinates on the display, // so we should apply the entire window transform. For other types of events, we should make // sure to not apply the window translation/offset. - return (source & AINPUT_SOURCE_CLASS_POINTER) == 0; + return !isFromSource(source, AINPUT_SOURCE_CLASS_POINTER); } } // namespace @@ -707,7 +717,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { #endif bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) { - if (source & AINPUT_SOURCE_CLASS_POINTER) { + if (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER)) { // Specifically excludes HOVER_MOVE and SCROLL. switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: @@ -764,17 +774,31 @@ std::string MotionEvent::actionToString(int32_t action) { return android::base::StringPrintf("%" PRId32, action); } +// Apply the given transformation to the point without checking whether the entire transform +// should be disregarded altogether for the provided source. +static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform, + const vec2& xy) { + return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy) + : transform.transform(xy); +} + vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform, const vec2& xy) { - return shouldDisregardTranslation(source) ? transformWithoutTranslation(transform, xy) - : transform.transform(xy); + if (shouldDisregardTransformation(source)) { + return xy; + } + return calculateTransformedXYUnchecked(source, transform, xy); } float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform& transform, const PointerCoords& coords) { + if (shouldDisregardTransformation(source)) { + return coords.getAxisValue(axis); + } + if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue()); + const vec2 xy = calculateTransformedXYUnchecked(source, transform, coords.getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 1b594f142e..a92016ba3b 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -647,9 +647,8 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } -MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, - const ui::Transform& transform, - const ui::Transform& rawTransform) { +MotionEvent createMotionEvent(int32_t source, uint32_t action, float x, float y, float dx, float dy, + const ui::Transform& transform, const ui::Transform& rawTransform) { std::vector pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector pointerCoords; @@ -660,8 +659,8 @@ MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy); nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); MotionEvent event; - event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN, - /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, + event.initialize(InputEvent::nextId(), /* deviceId */ 1, source, + /* displayId */ 0, INVALID_HMAC, action, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, @@ -670,6 +669,13 @@ MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, return event; } +MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, + const ui::Transform& transform, + const ui::Transform& rawTransform) { + return createMotionEvent(AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, x, y, dx, dy, + transform, rawTransform); +} + TEST_F(MotionEventTest, ApplyTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform identity; @@ -708,16 +714,39 @@ TEST_F(MotionEventTest, ApplyTransform) { changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001); } +TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) { + constexpr static std::array kNonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, + AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_JOYSTICK, + AMOTION_EVENT_ACTION_MOVE)}; + // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + + for (const auto& [source, action] : kNonTransformedSources) { + const MotionEvent event = + createMotionEvent(source, action, 60, 100, 0, 0, transform, transform); + + // These events should not be transformed in any way. + ASSERT_EQ(60, event.getX(0)); + ASSERT_EQ(100, event.getY(0)); + ASSERT_EQ(event.getRawX(0), event.getX(0)); + ASSERT_EQ(event.getRawY(0), event.getY(0)); + } +} + TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { - constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL, - AINPUT_SOURCE_MOUSE_RELATIVE, - AINPUT_SOURCE_JOYSTICK}; - for (uint32_t source : NON_POINTER_SOURCES) { - // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). - ui::Transform transform(ui::Transform::ROT_90, 800, 400); - transform.set(transform.tx() + 20, transform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, transform); - event.setSource(source); + constexpr static std::array kNonPointerSources = {std::pair(AINPUT_SOURCE_TRACKBALL, + AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_MOUSE_RELATIVE, + AMOTION_EVENT_ACTION_MOVE)}; + // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). + ui::Transform transform(ui::Transform::ROT_90, 800, 400); + transform.set(transform.tx() + 20, transform.ty() + 40); + + for (const auto& [source, action] : kNonPointerSources) { + const MotionEvent event = + createMotionEvent(source, action, 60, 100, 42, 96, transform, transform); // Since this event comes from a non-pointer source, it should include rotation but not // translation/offset. diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 176cf8943a..1b19311b2f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -342,18 +342,6 @@ bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) { std::unique_ptr createDispatchEntry(const InputTarget& inputTarget, std::shared_ptr eventEntry, int32_t inputTargetFlags) { - if (eventEntry->type == EventEntry::Type::MOTION) { - const MotionEntry& motionEntry = static_cast(*eventEntry); - if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) || - (motionEntry.source & AINPUT_SOURCE_CLASS_POSITION)) { - const ui::Transform identityTransform; - // Use identity transform for joystick and position-based (touchpad) events because they - // don't depend on the window transform. - return std::make_unique(eventEntry, inputTargetFlags, identityTransform, - identityTransform, 1.0f /*globalScaleFactor*/); - } - } - if (inputTarget.useDefaultPointerTransform()) { const ui::Transform& transform = inputTarget.getDefaultPointerTransform(); return std::make_unique(eventEntry, inputTargetFlags, transform, diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ba0ce95458..d8fd16c5e6 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3012,59 +3012,6 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } -TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickAndTouchpadNotTransformed) { - std::shared_ptr application = std::make_shared(); - sp window = - new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - const std::string name = window->getName(); - - // Window gets transformed by offset values. - window->setWindowOffset(500.0f, 500.0f); - - mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - window->setFocusable(true); - - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - - // First, we set focused window so that focusedWindowHandle is not null. - setFocusedWindow(window); - - // Second, we consume focus event if it is right or wrong according to onFocusChangedLocked. - window->consumeFocusEvent(true); - - constexpr const std::array nonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, - AMOTION_EVENT_ACTION_DOWN), - std::pair(AINPUT_SOURCE_JOYSTICK, - AMOTION_EVENT_ACTION_MOVE)}; - for (const auto& [source, action] : nonTransformedSources) { - const NotifyMotionArgs motionArgs = generateMotionArgs(action, source, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); - - MotionEvent* event = window->consumeMotion(); - ASSERT_NE(event, nullptr); - - const MotionEvent& motionEvent = *event; - EXPECT_EQ(action, motionEvent.getAction()); - EXPECT_EQ(motionArgs.pointerCount, motionEvent.getPointerCount()); - - float expectedX = motionArgs.pointerCoords[0].getX(); - float expectedY = motionArgs.pointerCoords[0].getY(); - - // Ensure the axis values from the final motion event are not transformed. - EXPECT_EQ(expectedX, motionEvent.getX(0)) - << "expected " << expectedX << " for x coord of " << name.c_str() << ", got " - << motionEvent.getX(0); - EXPECT_EQ(expectedY, motionEvent.getY(0)) - << "expected " << expectedY << " for y coord of " << name.c_str() << ", got " - << motionEvent.getY(0); - // Ensure the raw and transformed axis values for the motion event are the same. - EXPECT_EQ(motionEvent.getRawX(0), motionEvent.getX(0)) - << "expected raw and transformed X-axis values to be equal"; - EXPECT_EQ(motionEvent.getRawY(0), motionEvent.getY(0)) - << "expected raw and transformed Y-axis values to be equal"; - } -} - /** * Ensure that separate calls to sign the same data are generating the same key. * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance -- cgit v1.2.3-59-g8ed1b From 406c8abeff595432782740345abad06280d18032 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Wed, 10 Nov 2021 19:20:40 -0500 Subject: Performance hint ndk APIs Test: atest PerformanceHintNativeTestCases Change-Id: I46644adc4e07f668dd82d261da0aabeeb5403e86 --- include/android/performance_hint.h | 164 +++++++++++++++++++++++++++++ include/private/performance_hint_private.h | 116 -------------------- 2 files changed, 164 insertions(+), 116 deletions(-) create mode 100644 include/android/performance_hint.h (limited to 'include') diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h new file mode 100644 index 0000000000..5fa47f64be --- /dev/null +++ b/include/android/performance_hint.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef ANDROID_NATIVE_PERFORMANCE_HINT_H +#define ANDROID_NATIVE_PERFORMANCE_HINT_H + +#include + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +#include +#include + +__BEGIN_DECLS + +struct APerformanceHintManager; +struct APerformanceHintSession; + +/** + * An opaque type representing a handle to a performance hint manager. + * It must be released after use. + * + *

To use:

    + *
  • Obtain the performance hint manager instance by calling + * {@link APerformanceHint_getManager} function.
  • + *
  • Create an {@link APerformanceHintSession} with + * {@link APerformanceHint_createSession}.
  • + *
  • Get the preferred update rate in nanoseconds with + * {@link APerformanceHint_getPreferredUpdateRateNanos}.
  • + */ +typedef struct APerformanceHintManager APerformanceHintManager; + +/** + * An opaque type representing a handle to a performance hint session. + * A session can only be acquired from a {@link APerformanceHintManager} + * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be + * freed with {@link APerformanceHint_closeSession} after use. + * + * A Session represents a group of threads with an inter-related workload such that hints for + * their performance should be considered as a unit. The threads in a given session should be + * long-life and not created or destroyed dynamically. + * + *

    Each session is expected to have a periodic workload with a target duration for each + * cycle. The cycle duration is likely greater than the target work duration to allow other + * parts of the pipeline to run within the available budget. For example, a renderer thread may + * work at 60hz in order to produce frames at the display's frame but have a target work + * duration of only 6ms.

    + * + *

    After each cycle of work, the client is expected to use + * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to + * complete.

    + * + *

    To use:

      + *
    • Update a sessions target duration for each cycle of work + * with {@link APerformanceHint_updateTargetWorkDuration}.
    • + *
    • Report the actual duration for the last cycle of work with + * {@link APerformanceHint_reportActualWorkDuration}.
    • + *
    • Release the session instance with + * {@link APerformanceHint_closeSession}.

    + */ +typedef struct APerformanceHintSession APerformanceHintSession; + +/** + * Acquire an instance of the performance hint manager. + * + * @return manager instance on success, nullptr on failure. + */ +APerformanceHintManager* APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Creates a session for the given set of threads and sets their initial target work + * duration. + * @param manager The performance hint manager instance. + * @param threadIds The list of threads to be associated with this session. They must be part of + * this app's thread group. + * @param size the size of threadIds. + * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. + * This must be positive. + * @return manager instance on success, nullptr on failure. + */ +APerformanceHintSession* APerformanceHint_createSession( + APerformanceHintManager* manager, + const int32_t* threadIds, size_t size, + int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Get preferred update rate information for this device. + * + * @param manager The performance hint manager instance. + * @return the preferred update rate supported by device software. + */ +int64_t APerformanceHint_getPreferredUpdateRateNanos( + APerformanceHintManager* manager) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Updates this session's target duration for each cycle of work. + * + * @param session The performance hint session instance to update. + * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. + * @return 0 on success + * EINVAL if targetDurationNanos is not positive. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_updateTargetWorkDuration( + APerformanceHintSession* session, + int64_t targetDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Reports the actual duration for the last cycle of work. + * + *

    The system will attempt to adjust the core placement of the threads within the thread + * group and/or the frequency of the core on which they are run to bring the actual duration + * close to the target duration.

    + * + * @param session The performance hint session instance to update. + * @param actualDurationNanos how long the thread group took to complete its last task in + * nanoseconds. This must be positive. + * @return 0 on success + * EINVAL if actualDurationNanos is not positive. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_reportActualWorkDuration( + APerformanceHintSession* session, + int64_t actualDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__); + +/** + * Release the performance hint manager pointer acquired via + * {@link APerformanceHint_createSession}. + * + * @param session The performance hint session instance to release. + */ +void APerformanceHint_closeSession( + APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__); + +__END_DECLS + +#endif // ANDROID_NATIVE_PERFORMANCE_HINT_H diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index 5832bf49bd..f27f5f150f 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -17,124 +17,8 @@ #ifndef ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H #define ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H -#include - __BEGIN_DECLS -struct APerformanceHintManager; -struct APerformanceHintSession; - -/** - * An opaque type representing a handle to a performance hint manager. - * It must be released after use. - * - *

    To use:

      - *
    • Obtain the performance hint manager instance by calling - * {@link APerformanceHint_getManager} function.
    • - *
    • Create an {@link APerformanceHintSession} with - * {@link APerformanceHint_createSession}.
    • - *
    • Get the preferred update rate in nanoseconds with - * {@link APerformanceHint_getPreferredUpdateRateNanos}.
    • - */ -typedef struct APerformanceHintManager APerformanceHintManager; - -/** - * An opaque type representing a handle to a performance hint session. - * A session can only be acquired from a {@link APerformanceHintManager} - * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be - * freed with {@link APerformanceHint_closeSession} after use. - * - * A Session represents a group of threads with an inter-related workload such that hints for - * their performance should be considered as a unit. The threads in a given session should be - * long-life and not created or destroyed dynamically. - * - *

      Each session is expected to have a periodic workload with a target duration for each - * cycle. The cycle duration is likely greater than the target work duration to allow other - * parts of the pipeline to run within the available budget. For example, a renderer thread may - * work at 60hz in order to produce frames at the display's frame but have a target work - * duration of only 6ms.

      - * - *

      After each cycle of work, the client is expected to use - * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to - * complete.

      - * - *

      To use:

        - *
      • Update a sessions target duration for each cycle of work - * with {@link APerformanceHint_updateTargetWorkDuration}.
      • - *
      • Report the actual duration for the last cycle of work with - * {@link APerformanceHint_reportActualWorkDuration}.
      • - *
      • Release the session instance with - * {@link APerformanceHint_closeSession}.

      - */ -typedef struct APerformanceHintSession APerformanceHintSession; - -/** - * Acquire an instance of the performance hint manager. - * - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintManager* APerformanceHint_getManager(); - -/** - * Creates a session for the given set of threads and sets their initial target work - * duration. - * @param manager The performance hint manager instance. - * @param threadIds The list of threads to be associated with this session. They must be part of - * this app's thread group. - * @param size the size of threadIds. - * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. - * This must be positive. - * @return manager instance on success, nullptr on failure. - */ -APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager, - const int32_t* threadIds, size_t size, - int64_t initialTargetWorkDurationNanos); - -/** - * Get preferred update rate information for this device. - * - * @param manager The performance hint manager instance. - * @return the preferred update rate supported by device software. - */ -int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager); - -/** - * Updates this session's target duration for each cycle of work. - * - * @param session The performance hint session instance to update. - * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. - * @return 0 on success - * EINVAL if targetDurationNanos is not positive. - * EPIPE if communication with the system service has failed. - */ -int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session, - int64_t targetDurationNanos); - -/** - * Reports the actual duration for the last cycle of work. - * - *

      The system will attempt to adjust the core placement of the threads within the thread - * group and/or the frequency of the core on which they are run to bring the actual duration - * close to the target duration.

      - * - * @param session The performance hint session instance to update. - * @param actualDurationNanos how long the thread group took to complete its last task in - * nanoseconds. This must be positive. - * @return 0 on success - * EINVAL if actualDurationNanos is not positive. - * EPIPE if communication with the system service has failed. - */ -int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session, - int64_t actualDurationNanos); - -/** - * Release the performance hint manager pointer acquired via - * {@link APerformanceHint_createSession}. - * - * @param session The performance hint session instance to release. - */ -void APerformanceHint_closeSession(APerformanceHintSession* session); - /** * For testing only. */ -- cgit v1.2.3-59-g8ed1b From 3cfec7b162d40a53880f3cbaf863b0b39027db3d Mon Sep 17 00:00:00 2001 From: Antonio Kantek Date: Fri, 5 Nov 2021 18:26:17 -0700 Subject: TouchMode (6.2/n) Fully detaching touch mode from focus event (native) Bug: 193718270 Test: atest inputflinger_tests Test: atest libinput_tests Test: atest FrameworksCoreTests Test: atest CtsInputMethodTestCases Test: atest CtsInputTestCases Test: atest CtsSecurityTestCases Test: atest CtsWindowManagerDeviceTestCases Change-Id: I334c63d781ee8e8c13d21cc4a6cf323d885fc985 --- include/input/Input.h | 5 +---- include/input/InputTransport.h | 7 +++---- libs/input/Input.cpp | 4 +--- libs/input/InputTransport.cpp | 19 ++++++------------- libs/input/tests/InputPublisherAndConsumer_test.cpp | 4 +--- libs/input/tests/StructLayout_test.cpp | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 3 +-- services/inputflinger/tests/InputDispatcher_test.cpp | 1 - 8 files changed, 14 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 7cc595a264..ce9cefed8b 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -840,15 +840,12 @@ public: inline bool getHasFocus() const { return mHasFocus; } - inline bool getInTouchMode() const { return mInTouchMode; } - - void initialize(int32_t id, bool hasFocus, bool inTouchMode); + void initialize(int32_t id, bool hasFocus); void initialize(const FocusEvent& from); protected: bool mHasFocus; - bool mInTouchMode; }; /* diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index d655b28278..edcb615491 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -178,10 +178,9 @@ struct InputMessage { struct Focus { int32_t eventId; - // The following 3 fields take up 4 bytes total + // The following 2 fields take up 4 bytes total bool hasFocus; - bool inTouchMode; - uint8_t empty[2]; + uint8_t empty[3]; inline size_t size() const { return sizeof(Focus); } } focus; @@ -381,7 +380,7 @@ public: * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode); + status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus); /* Publishes a capture event to the input channel. * diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 24a77209c4..c7f77d42fe 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -820,17 +820,15 @@ float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, // --- FocusEvent --- -void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { +void FocusEvent::initialize(int32_t id, bool hasFocus) { InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN, ADISPLAY_ID_NONE, INVALID_HMAC); mHasFocus = hasFocus; - mInTouchMode = inTouchMode; } void FocusEvent::initialize(const FocusEvent& from) { InputEvent::initialize(from); mHasFocus = from.mHasFocus; - mInTouchMode = from.mInTouchMode; } // --- CaptureEvent --- diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 02a5a0807b..a065ce25f7 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -278,7 +278,6 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { case InputMessage::Type::FOCUS: { msg->body.focus.eventId = body.focus.eventId; msg->body.focus.hasFocus = body.focus.hasFocus; - msg->body.focus.inTouchMode = body.focus.inTouchMode; break; } case InputMessage::Type::CAPTURE: { @@ -622,13 +621,10 @@ status_t InputPublisher::publishMotionEvent( return mChannel->sendMessage(&msg); } -status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, - bool inTouchMode) { +status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus) { if (ATRACE_ENABLED()) { - std::string message = - StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s, inTouchMode=%s)", - mChannel->getName().c_str(), toString(hasFocus), - toString(inTouchMode)); + std::string message = StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s)", + mChannel->getName().c_str(), toString(hasFocus)); ATRACE_NAME(message.c_str()); } @@ -637,7 +633,6 @@ status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool h msg.header.seq = seq; msg.body.focus.eventId = eventId; msg.body.focus.hasFocus = hasFocus; - msg.body.focus.inTouchMode = inTouchMode; return mChannel->sendMessage(&msg); } @@ -1371,8 +1366,7 @@ void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) } void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) { - event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus, - msg->body.focus.inTouchMode); + event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus); } void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) { @@ -1491,9 +1485,8 @@ std::string InputConsumer::dump() const { break; } case InputMessage::Type::FOCUS: { - out += android::base::StringPrintf("hasFocus=%s inTouchMode=%s", - toString(msg.body.focus.hasFocus), - toString(msg.body.focus.inTouchMode)); + out += android::base::StringPrintf("hasFocus=%s", + toString(msg.body.focus.hasFocus)); break; } case InputMessage::Type::CAPTURE: { diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 973194c8f6..05bc0bcbe8 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -290,10 +290,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { constexpr uint32_t seq = 15; int32_t eventId = InputEvent::nextId(); constexpr bool hasFocus = true; - constexpr bool inTouchMode = true; const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC); - status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode); + status = mPublisher->publishFocusEvent(seq, eventId, hasFocus); ASSERT_EQ(OK, status) << "publisher publishFocusEvent should return OK"; uint32_t consumeSeq; @@ -309,7 +308,6 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { EXPECT_EQ(seq, consumeSeq); EXPECT_EQ(eventId, focusEvent->getId()); EXPECT_EQ(hasFocus, focusEvent->getHasFocus()); - EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode()); status = mConsumer->sendFinishedSignal(seq, true); ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK"; diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 2f88704d63..b6a94764e5 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -84,8 +84,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); - CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 5); - CHECK_OFFSET(InputMessage::Body::Focus, empty, 6); + CHECK_OFFSET(InputMessage::Body::Focus, empty, 5); CHECK_OFFSET(InputMessage::Body::Capture, eventId, 0); CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 695258759b..5c56e842db 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3234,8 +3234,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const FocusEntry& focusEntry = static_cast(eventEntry); status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq, focusEntry.id, - focusEntry.hasFocus, - mInTouchMode); + focusEntry.hasFocus); break; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d8fd16c5e6..515a01e137 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -842,7 +842,6 @@ public: FocusEvent* focusEvent = static_cast(event); EXPECT_EQ(hasFocus, focusEvent->getHasFocus()); - EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode()); } void consumeCaptureEvent(bool hasCapture) { -- cgit v1.2.3-59-g8ed1b From d948957b396a9301e6e247023d8509f44f6cf87c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 12 Nov 2021 20:08:38 -0800 Subject: Look up source using & instead of equality Source for an input device may be composite. On some devices, the source is specified as TOUCHSCREEN | STYLUS. That means a regular lookup of a MotionRange using just SOURCE_TOUCHSCREEN fails. Update the code to allow composite sources. Also, improve the source dump by printing words instead of numbers. Bug: 198472780 Test: adb shell dumpsys input Change-Id: I8d395f2bb5a6db031e5c2aa6c1f5152ff067a2bb --- include/input/Input.h | 4 ++ libs/input/Input.cpp | 47 ++++++++++++++++++++-- libs/input/InputDevice.cpp | 6 +-- services/inputflinger/InputClassifier.cpp | 3 +- services/inputflinger/dispatcher/Entry.cpp | 20 ++++----- .../inputflinger/dispatcher/InputDispatcher.cpp | 4 -- 6 files changed, 62 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 7cc595a264..263ade40fb 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -203,6 +203,10 @@ class Parcel; const char* inputEventTypeToString(int32_t type); +std::string inputEventSourceToString(int32_t source); + +bool isFromSource(uint32_t source, uint32_t test); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 24a77209c4..a1d75d5fb1 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -66,10 +66,6 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) return transformedXy - transformedOrigin; } -bool isFromSource(uint32_t source, uint32_t test) { - return (source & test) == test; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -148,6 +144,49 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } +std::string inputEventSourceToString(int32_t source) { + if (source == AINPUT_SOURCE_UNKNOWN) { + return "UNKNOWN"; + } + if (source == static_cast(AINPUT_SOURCE_ANY)) { + return "ANY"; + } + static const std::map SOURCES{ + {AINPUT_SOURCE_KEYBOARD, "KEYBOARD"}, + {AINPUT_SOURCE_DPAD, "DPAD"}, + {AINPUT_SOURCE_GAMEPAD, "GAMEPAD"}, + {AINPUT_SOURCE_TOUCHSCREEN, "TOUCHSCREEN"}, + {AINPUT_SOURCE_MOUSE, "MOUSE"}, + {AINPUT_SOURCE_STYLUS, "STYLUS"}, + {AINPUT_SOURCE_BLUETOOTH_STYLUS, "BLUETOOTH_STYLUS"}, + {AINPUT_SOURCE_TRACKBALL, "TRACKBALL"}, + {AINPUT_SOURCE_MOUSE_RELATIVE, "MOUSE_RELATIVE"}, + {AINPUT_SOURCE_TOUCHPAD, "TOUCHPAD"}, + {AINPUT_SOURCE_TOUCH_NAVIGATION, "TOUCH_NAVIGATION"}, + {AINPUT_SOURCE_JOYSTICK, "JOYSTICK"}, + {AINPUT_SOURCE_HDMI, "HDMI"}, + {AINPUT_SOURCE_SENSOR, "SENSOR"}, + {AINPUT_SOURCE_ROTARY_ENCODER, "ROTARY_ENCODER"}, + }; + std::string result; + for (const auto& [source_entry, str] : SOURCES) { + if ((source & source_entry) == source_entry) { + if (!result.empty()) { + result += " | "; + } + result += str; + } + } + if (result.empty()) { + result = StringPrintf("0x%08x", source); + } + return result; +} + +bool isFromSource(uint32_t source, uint32_t test) { + return (source & test) == test; +} + VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), event.getSource(), event.getDisplayId()}, diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 015bd81361..ac84627b3f 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -208,10 +208,8 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( int32_t axis, uint32_t source) const { - size_t numRanges = mMotionRanges.size(); - for (size_t i = 0; i < numRanges; i++) { - const MotionRange& range = mMotionRanges[i]; - if (range.axis == axis && range.source == source) { + for (const MotionRange& range : mMotionRanges) { + if (range.axis == axis && isFromSource(range.source, source)) { return ⦥ } } diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 29d8a0f441..19cad7b9ad 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -68,7 +68,8 @@ static MotionClassification getMotionClassification(common::V1_0::Classification } static bool isTouchEvent(const NotifyMotionArgs& args) { - return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN; + return isFromSource(args.source, AINPUT_SOURCE_TOUCHPAD) || + isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN); } // --- ClassifierEvent --- diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index c03581d8da..1674afd02e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -175,13 +175,13 @@ std::string KeyEntry::getDescription() const { if (!GetBoolProperty("ro.debuggable", false)) { return "KeyEvent"; } - return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 - ", source=0x%08x, displayId=%" PRId32 ", action=%s, " + return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=%s, displayId=%" PRId32 + ", action=%s, " "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", - deviceId, eventTime, source, displayId, KeyEvent::actionToString(action), - flags, KeyEvent::getLabel(keyCode), keyCode, scanCode, metaState, - repeatCount, policyFlags); + deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, + KeyEvent::actionToString(action), flags, KeyEvent::getLabel(keyCode), + keyCode, scanCode, metaState, repeatCount, policyFlags); } void KeyEntry::recycle() { @@ -249,12 +249,12 @@ std::string MotionEntry::getDescription() const { } std::string msg; msg += StringPrintf("MotionEvent(deviceId=%d, eventTime=%" PRIu64 - ", source=0x%08x, displayId=%" PRId32 + ", source=%s, displayId=%" PRId32 ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " "buttonState=0x%08x, " "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", - deviceId, eventTime, source, displayId, + deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState, buttonState, motionClassificationToString(classification), edgeFlags, xPrecision, yPrecision, xCursorPosition, yCursorPosition); @@ -289,9 +289,11 @@ SensorEntry::~SensorEntry() {} std::string SensorEntry::getDescription() const { std::string msg; - msg += StringPrintf("SensorEntry(deviceId=%d, source=0x%08x, sensorType=0x%08x, " + std::string sensorTypeStr(ftl::enum_name(sensorType).value_or("?")); + msg += StringPrintf("SensorEntry(deviceId=%d, source=%s, sensorType=%s, " "accuracy=0x%08x, hwTimestamp=%" PRId64, - deviceId, source, sensorType, accuracy, hwTimestamp); + deviceId, inputEventSourceToString(source).c_str(), sensorTypeStr.c_str(), + accuracy, hwTimestamp); if (!GetBoolProperty("ro.debuggable", false)) { for (size_t i = 0; i < values.size(); i++) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1b19311b2f..44409a262e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -516,10 +516,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -bool isFromSource(uint32_t source, uint32_t test) { - return (source & test) == test; -} - vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { const vec2 transformedXy = transform.transform(x, y); const vec2 transformedOrigin = transform.transform(0, 0); -- cgit v1.2.3-59-g8ed1b From 6b430413d07b6afca1a4146ea91809567b5cfe9a Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 4 Nov 2021 16:51:29 -0700 Subject: Change PointerController to display space PointerController used to work in the logical display space, so TouchInputMapper and CursorInputMapper would need to transform the coordinates before interacting with it. This CL makes PointerController work in the display space. It will transform incoming and outgoing coordinates to stay in the display space using the DisplayInfo provided by SurfaceFlinger. Using info provided by SF also means that there will be better synchonization between the pointers and display changes like rotation. Bug: 188939842 Bug: 144544464 Test: manual: ensure mouse and touch spots work in different display orientations and sizes set using "adb shell wm size" Change-Id: I764c070adef7e9f26c0062f1b3466c7115a305ac --- include/input/Input.h | 5 + libs/input/Input.cpp | 12 +-- .../include/PointerControllerInterface.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 17 +--- .../inputflinger/reader/mapper/CursorInputMapper.h | 2 - .../reader/mapper/TouchCursorInputMapperCommon.h | 20 ---- .../reader/mapper/TouchInputMapper.cpp | 110 +++++++-------------- .../inputflinger/reader/mapper/TouchInputMapper.h | 8 -- 8 files changed, 47 insertions(+), 130 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..5242dcb476 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -201,6 +201,11 @@ namespace android { class Parcel; #endif +/* + * Apply the given transform to the point without applying any translation/offset. + */ +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); + const char* inputEventTypeToString(int32_t type); std::string inputEventSourceToString(int32_t source); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..cb93c92310 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -60,12 +60,6 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return atan2f(transformedPoint.x, -transformedPoint.y); } -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { - const vec2 transformedXy = transform.transform(xy); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -120,6 +114,12 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + const char* inputEventTypeToString(int32_t type) { switch (type) { case AINPUT_EVENT_TYPE_KEY: { diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index b1069497d3..db4228d862 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -30,7 +30,8 @@ namespace android { * fingers * * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. + * display orientation changes if needed. It works in the display panel's coordinate space, which + * is the same coordinate space used by InputReader. */ class PointerControllerInterface { protected: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 15ba45945a..fcb56ef05c 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,8 +188,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; - mDisplayWidth = 0; - mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -203,8 +201,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); - mDisplayWidth = internalViewport->deviceWidth; - mDisplayHeight = internalViewport->deviceHeight; } } @@ -335,14 +331,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); if (moved) { - float dx = deltaX; - float dy = deltaY; - // Rotate the delta from InputReader's un-rotated coordinate space to - // PointerController's rotated coordinate space that is oriented with the - // viewport. - rotateDelta(getInverseRotation(mOrientation), &dx, &dy); - - mPointerController->move(dx, dy); + mPointerController->move(deltaX, deltaY); } if (buttonsChanged) { @@ -353,10 +342,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); - // Rotate the cursor position that is in PointerController's rotated coordinate space - // to InputReader's un-rotated coordinate space. - rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, - mDisplayWidth, mDisplayHeight); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 88e947f7d5..9a8ca01294 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,8 +105,6 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; std::shared_ptr mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 8c30e38908..31a3d2e172 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -64,26 +64,6 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { } } -// Rotates the given point (x, y) by the supplied orientation. The width and height are the -// dimensions of the surface prior to this rotation being applied. -static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { - rotateDelta(orientation, &x, &y); - switch (orientation) { - case DISPLAY_ORIENTATION_90: - y += width; - break; - case DISPLAY_ORIENTATION_180: - x += width; - y += height; - break; - case DISPLAY_ORIENTATION_270: - x += height; - break; - default: - break; - } -} - // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 3fe6fd130f..913c666a4a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1668,9 +1668,10 @@ void TouchInputMapper::updateTouchSpots() { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); - setTouchSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, mViewport.displayId); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, + mViewport.displayId); } bool TouchInputMapper::isTouchScreen() { @@ -2410,9 +2411,10 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { - setTouchSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, mPointerController->getDisplayId()); + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, + mPointerController->getDisplayId()); } } else { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -2562,7 +2564,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); PointerProperties pointerProperties; pointerProperties.clear(); @@ -2819,12 +2822,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); @@ -2850,7 +2854,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES @@ -2918,7 +2923,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; @@ -2952,7 +2958,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -2974,7 +2980,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi down = false; } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); @@ -3047,9 +3054,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); - auto [x, y] = getMouseCursorPosition(); - mPointerGesture.referenceGestureX = x; - mPointerGesture.referenceGestureY = y; + mPointerController->getPosition(&mPointerGesture.referenceGestureX, + &mPointerGesture.referenceGestureY); } // Clear the reference deltas for fingers not yet included in the reference calculation. @@ -3387,13 +3393,15 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uin if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - setMouseCursorPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), - mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); + mPointerController + ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), + mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3434,7 +3442,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -3442,7 +3450,8 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3482,7 +3491,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uin } int32_t displayId = mPointerController->getDisplayId(); - auto [xCursorPosition, yCursorPosition] = getMouseCursorPosition(); + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); if (mPointerSimple.down && !down) { mPointerSimple.down = false; @@ -3648,9 +3658,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - auto [x, y] = getMouseCursorPosition(); - xCursorPosition = x; - yCursorPosition = y; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); @@ -3999,56 +4007,4 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { return std::nullopt; } -void TouchInputMapper::moveMouseCursor(float dx, float dy) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate - // space that is oriented with the viewport. - rotateDelta(mViewport.orientation, &dx, &dy); - - mPointerController->move(dx, dy); -} - -std::pair TouchInputMapper::getMouseCursorPosition() const { - float x = 0; - float y = 0; - mPointerController->getPosition(&x, &y); - - if (!mViewport.isValid()) return {x, y}; - - // Convert from PointerController's rotated coordinate space that is oriented with the viewport - // to InputReader's un-rotated coordinate space. - const int32_t orientation = getInverseRotation(mViewport.orientation); - rotatePoint(orientation, x, y, mViewport.deviceWidth, mViewport.deviceHeight); - return {x, y}; -} - -void TouchInputMapper::setMouseCursorPosition(float x, float y) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space that is oriented with the viewport. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - mPointerController->setPosition(x, y); -} - -void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId) { - std::array outSpotCoords{}; - - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { - const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; - float x = spotCoords[index].getX(); - float y = spotCoords[index].getY(); - float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - } - - mPointerController->setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits, displayId); -} - } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 496491b62d..9b020a609a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -803,14 +803,6 @@ private: const char* modeToString(DeviceMode deviceMode); void rotateAndScale(float& x, float& y) const; - - // Wrapper methods for interfacing with PointerController. These are used to convert points - // between the coordinate spaces used by InputReader and PointerController, if they differ. - void moveMouseCursor(float dx, float dy) const; - std::pair getMouseCursorPosition() const; - void setMouseCursorPosition(float x, float y) const; - void setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 259a2122aeafea0f20bfcc7c9bcd089511a5aa56 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 17 Nov 2021 21:48:11 +0000 Subject: Revert "Change PointerController to display space" Revert submission 16194643-pointer-controller-in-display-space Reason for revert: b/206817973 Reverted Changes: I764c070ad:Change PointerController to display space I5e9e19c36:Change PointerController to display space Change-Id: If6e96f41873dd9601f49fc9f9f514a95394f3c58 --- include/input/Input.h | 5 - libs/input/Input.cpp | 12 +-- .../include/PointerControllerInterface.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 17 +++- .../inputflinger/reader/mapper/CursorInputMapper.h | 2 + .../reader/mapper/TouchCursorInputMapperCommon.h | 20 ++++ .../reader/mapper/TouchInputMapper.cpp | 110 ++++++++++++++------- .../inputflinger/reader/mapper/TouchInputMapper.h | 8 ++ 8 files changed, 130 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 5242dcb476..1e06257591 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -201,11 +201,6 @@ namespace android { class Parcel; #endif -/* - * Apply the given transform to the point without applying any translation/offset. - */ -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); - const char* inputEventTypeToString(int32_t type); std::string inputEventSourceToString(int32_t source); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index cb93c92310..8974b22c86 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -60,6 +60,12 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return atan2f(transformedPoint.x, -transformedPoint.y); } +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -114,12 +120,6 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { - const vec2 transformedXy = transform.transform(xy); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - const char* inputEventTypeToString(int32_t type) { switch (type) { case AINPUT_EVENT_TYPE_KEY: { diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index db4228d862..b1069497d3 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -30,8 +30,7 @@ namespace android { * fingers * * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. It works in the display panel's coordinate space, which - * is the same coordinate space used by InputReader. + * display orientation changes if needed. */ class PointerControllerInterface { protected: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index fcb56ef05c..15ba45945a 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,6 +188,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; + mDisplayWidth = 0; + mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -201,6 +203,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); + mDisplayWidth = internalViewport->deviceWidth; + mDisplayHeight = internalViewport->deviceHeight; } } @@ -331,7 +335,14 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); if (moved) { - mPointerController->move(deltaX, deltaY); + float dx = deltaX; + float dy = deltaY; + // Rotate the delta from InputReader's un-rotated coordinate space to + // PointerController's rotated coordinate space that is oriented with the + // viewport. + rotateDelta(getInverseRotation(mOrientation), &dx, &dy); + + mPointerController->move(dx, dy); } if (buttonsChanged) { @@ -342,6 +353,10 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + // Rotate the cursor position that is in PointerController's rotated coordinate space + // to InputReader's un-rotated coordinate space. + rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, + mDisplayWidth, mDisplayHeight); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 9a8ca01294..88e947f7d5 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,6 +105,8 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; + int32_t mDisplayWidth; + int32_t mDisplayHeight; std::shared_ptr mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 31a3d2e172..8c30e38908 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -64,6 +64,26 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { } } +// Rotates the given point (x, y) by the supplied orientation. The width and height are the +// dimensions of the surface prior to this rotation being applied. +static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { + rotateDelta(orientation, &x, &y); + switch (orientation) { + case DISPLAY_ORIENTATION_90: + y += width; + break; + case DISPLAY_ORIENTATION_180: + x += width; + y += height; + break; + case DISPLAY_ORIENTATION_270: + x += height; + break; + default: + break; + } +} + // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 913c666a4a..3fe6fd130f 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1668,10 +1668,9 @@ void TouchInputMapper::updateTouchSpots() { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, - mViewport.displayId); + setTouchSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, mViewport.displayId); } bool TouchInputMapper::isTouchScreen() { @@ -2411,10 +2410,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, - mPointerController->getDisplayId()); + setTouchSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, mPointerController->getDisplayId()); } } else { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -2564,8 +2562,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); PointerProperties pointerProperties; pointerProperties.clear(); @@ -2822,13 +2819,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); + moveMouseCursor(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); @@ -2854,8 +2850,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES @@ -2923,8 +2918,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; @@ -2958,7 +2952,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); + moveMouseCursor(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -2980,8 +2974,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi down = false; } - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); @@ -3054,8 +3047,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); + auto [x, y] = getMouseCursorPosition(); + mPointerGesture.referenceGestureX = x; + mPointerGesture.referenceGestureY = y; } // Clear the reference deltas for fingers not yet included in the reference calculation. @@ -3393,15 +3387,13 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uin if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - mPointerController - ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), - mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); + setMouseCursorPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), + mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3442,7 +3434,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); - mPointerController->move(deltaX, deltaY); + moveMouseCursor(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -3450,8 +3442,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; - float x, y; - mPointerController->getPosition(&x, &y); + auto [x, y] = getMouseCursorPosition(); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3491,8 +3482,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uin } int32_t displayId = mPointerController->getDisplayId(); - float xCursorPosition, yCursorPosition; - mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + auto [xCursorPosition, yCursorPosition] = getMouseCursorPosition(); if (mPointerSimple.down && !down) { mPointerSimple.down = false; @@ -3658,7 +3648,9 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + auto [x, y] = getMouseCursorPosition(); + xCursorPosition = x; + yCursorPosition = y; } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); @@ -4007,4 +3999,56 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { return std::nullopt; } +void TouchInputMapper::moveMouseCursor(float dx, float dy) const { + // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate + // space that is oriented with the viewport. + rotateDelta(mViewport.orientation, &dx, &dy); + + mPointerController->move(dx, dy); +} + +std::pair TouchInputMapper::getMouseCursorPosition() const { + float x = 0; + float y = 0; + mPointerController->getPosition(&x, &y); + + if (!mViewport.isValid()) return {x, y}; + + // Convert from PointerController's rotated coordinate space that is oriented with the viewport + // to InputReader's un-rotated coordinate space. + const int32_t orientation = getInverseRotation(mViewport.orientation); + rotatePoint(orientation, x, y, mViewport.deviceWidth, mViewport.deviceHeight); + return {x, y}; +} + +void TouchInputMapper::setMouseCursorPosition(float x, float y) const { + // Convert from InputReader's un-rotated coordinate space to PointerController's rotated + // coordinate space that is oriented with the viewport. + rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); + + mPointerController->setPosition(x, y); +} + +void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId) { + std::array outSpotCoords{}; + + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { + const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; + float x = spotCoords[index].getX(); + float y = spotCoords[index].getY(); + float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + + // Convert from InputReader's un-rotated coordinate space to PointerController's rotated + // coordinate space. + rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); + + outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); + outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + } + + mPointerController->setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits, displayId); +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 9b020a609a..496491b62d 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -803,6 +803,14 @@ private: const char* modeToString(DeviceMode deviceMode); void rotateAndScale(float& x, float& y) const; + + // Wrapper methods for interfacing with PointerController. These are used to convert points + // between the coordinate spaces used by InputReader and PointerController, if they differ. + void moveMouseCursor(float dx, float dy) const; + std::pair getMouseCursorPosition() const; + void setMouseCursorPosition(float x, float y) const; + void setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 5e6b390919a9786a50f9d5cbd539e9dc53ad78c2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 18 Nov 2021 07:54:09 -0800 Subject: Remove x/y offset from MotionEntry Window or display offsets are now captured in the various transforms, so we can remove the ability to specify the offset by itself. Bug: 188939842 Test: presubmit Test: atest inputflinger_tests Change-Id: Ifd359ebb03850bb30efb358e84f0a7e77260a8b2 --- include/input/Input.h | 5 ++--- libs/input/Input.cpp | 5 ----- services/inputflinger/dispatcher/Entry.cpp | 5 +---- services/inputflinger/dispatcher/Entry.h | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++---- 6 files changed, 11 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..1c79c4a21c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,7 +377,6 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -567,7 +566,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -583,7 +582,7 @@ public: void setCursorPosition(float x, float y); - ui::Transform getRawTransform() const { return mRawTransform; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..69ea7dfcb5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,11 +343,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } -void PointerCoords::applyOffset(float xOffset, float yOffset) { - setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); - setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -} - #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 1674afd02e..3d0818b738 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) + const PointerCoords* pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,9 +235,6 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 477781a2ad..0f792967eb 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,8 +184,7 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3fd1c8aa27..04ff599f13 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); + pointerCoords.data()); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + args->pointerProperties, args->pointerCoords); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, 0, 0); + pointerProperties, samplePointerCoords); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, 0, 0); + samplePointerCoords); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 3bb0bc995c..ad3c6159ef 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,8 +296,7 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); + memento.pointerCoords)); } } return events; @@ -349,8 +348,7 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + pointerCount, pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From 2b80b386c4ed5a1b3240da32080280b0a1ec9cef Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Fri, 19 Nov 2021 17:26:26 +0000 Subject: Revert "Remove x/y offset from MotionEntry" Revert submission 16295572 Reason for revert: DroidMonitor-triggered revert due to breakage bug http://b/207128427. BUG: 207128427 Reverted Changes: I65c284e5e:Input injection: Assume transformed values are in ... Ifd359ebb0:Remove x/y offset from MotionEntry Change-Id: Iab395d41d49db17c0a682bdd6c77fe2aacc004f4 --- include/input/Input.h | 5 +++-- libs/input/Input.cpp | 5 +++++ services/inputflinger/dispatcher/Entry.cpp | 5 ++++- services/inputflinger/dispatcher/Entry.h | 3 ++- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++++-- 6 files changed, 23 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1c79c4a21c..1e06257591 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,6 +377,7 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); + void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -566,7 +567,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline const ui::Transform& getTransform() const { return mTransform; } + inline ui::Transform getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -582,7 +583,7 @@ public: void setCursorPosition(float x, float y); - inline const ui::Transform& getRawTransform() const { return mRawTransform; } + ui::Transform getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 69ea7dfcb5..8974b22c86 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,6 +343,11 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } +void PointerCoords::applyOffset(float xOffset, float yOffset) { + setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); + setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); +} + #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 3d0818b738..1674afd02e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) + const PointerCoords* pointerCoords, float xOffset, float yOffset) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,6 +235,9 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); + if (xOffset || yOffset) { + this->pointerCoords[i].applyOffset(xOffset, yOffset); + } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 0f792967eb..477781a2ad 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,7 +184,8 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 04ff599f13..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data()); + pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords); + splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); + args->pointerProperties, args->pointerCoords, 0, 0); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords); + pointerProperties, samplePointerCoords, 0, 0); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords); + samplePointerCoords, 0, 0); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index ad3c6159ef..3bb0bc995c 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,7 +296,8 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords)); + memento.pointerCoords, 0 /*xOffset*/, + 0 /*yOffset*/)); } } return events; @@ -348,7 +349,8 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords)); + pointerCount, pointerProperties, pointerCoords, + 0 /*xOffset*/, 0 /*yOffset*/)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From de69f8ae323ccfbf150a368145525b619568469c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 18 Nov 2021 16:40:34 +0000 Subject: Reland "Change PointerController to display space" 259a2122aeafea0f20bfcc7c9bcd089511a5aa56 Bug: 188939842 Bug: 144544464 Bug: 206817973 Test: forrest run - CtsHardwareTestCases Change-Id: I8f0312a502ec5c79038ef1697cf2d5b23db9fcfc --- include/input/Input.h | 5 + libs/input/Input.cpp | 12 +-- .../include/PointerControllerInterface.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 17 +--- .../inputflinger/reader/mapper/CursorInputMapper.h | 2 - .../reader/mapper/TouchCursorInputMapperCommon.h | 20 ---- .../reader/mapper/TouchInputMapper.cpp | 110 +++++++-------------- .../inputflinger/reader/mapper/TouchInputMapper.h | 8 -- 8 files changed, 47 insertions(+), 130 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..5242dcb476 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -201,6 +201,11 @@ namespace android { class Parcel; #endif +/* + * Apply the given transform to the point without applying any translation/offset. + */ +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); + const char* inputEventTypeToString(int32_t type); std::string inputEventSourceToString(int32_t source); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..cb93c92310 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -60,12 +60,6 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return atan2f(transformedPoint.x, -transformedPoint.y); } -vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { - const vec2 transformedXy = transform.transform(xy); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -120,6 +114,12 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- +vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { + const vec2 transformedXy = transform.transform(xy); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + const char* inputEventTypeToString(int32_t type) { switch (type) { case AINPUT_EVENT_TYPE_KEY: { diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index b1069497d3..db4228d862 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -30,7 +30,8 @@ namespace android { * fingers * * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. + * display orientation changes if needed. It works in the display panel's coordinate space, which + * is the same coordinate space used by InputReader. */ class PointerControllerInterface { protected: diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 15ba45945a..fcb56ef05c 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,8 +188,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; - mDisplayWidth = 0; - mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -203,8 +201,6 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); - mDisplayWidth = internalViewport->deviceWidth; - mDisplayHeight = internalViewport->deviceHeight; } } @@ -335,14 +331,7 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); if (moved) { - float dx = deltaX; - float dy = deltaY; - // Rotate the delta from InputReader's un-rotated coordinate space to - // PointerController's rotated coordinate space that is oriented with the - // viewport. - rotateDelta(getInverseRotation(mOrientation), &dx, &dy); - - mPointerController->move(dx, dy); + mPointerController->move(deltaX, deltaY); } if (buttonsChanged) { @@ -353,10 +342,6 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); - // Rotate the cursor position that is in PointerController's rotated coordinate space - // to InputReader's un-rotated coordinate space. - rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, - mDisplayWidth, mDisplayHeight); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 88e947f7d5..9a8ca01294 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,8 +105,6 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; - int32_t mDisplayWidth; - int32_t mDisplayHeight; std::shared_ptr mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 8c30e38908..31a3d2e172 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -64,26 +64,6 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { } } -// Rotates the given point (x, y) by the supplied orientation. The width and height are the -// dimensions of the surface prior to this rotation being applied. -static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { - rotateDelta(orientation, &x, &y); - switch (orientation) { - case DISPLAY_ORIENTATION_90: - y += width; - break; - case DISPLAY_ORIENTATION_180: - x += width; - y += height; - break; - case DISPLAY_ORIENTATION_270: - x += height; - break; - default: - break; - } -} - // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 3fe6fd130f..913c666a4a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1668,9 +1668,10 @@ void TouchInputMapper::updateTouchSpots() { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); mPointerController->setButtonState(mCurrentRawState.buttonState); - setTouchSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, mViewport.displayId); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, + mViewport.displayId); } bool TouchInputMapper::isTouchScreen() { @@ -2410,9 +2411,10 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { - setTouchSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, mPointerController->getDisplayId()); + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, + mPointerController->getDisplayId()); } } else { mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -2562,7 +2564,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); PointerProperties pointerProperties; pointerProperties.clear(); @@ -2819,12 +2822,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIdBits.clear(); @@ -2850,7 +2854,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES @@ -2918,7 +2923,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG; @@ -2952,7 +2958,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -2974,7 +2980,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi down = false; } - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); @@ -3047,9 +3054,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mCurrentRawState.rawPointerData .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); - auto [x, y] = getMouseCursorPosition(); - mPointerGesture.referenceGestureX = x; - mPointerGesture.referenceGestureY = y; + mPointerController->getPosition(&mPointerGesture.referenceGestureX, + &mPointerGesture.referenceGestureY); } // Clear the reference deltas for fingers not yet included in the reference calculation. @@ -3387,13 +3393,15 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uin if (!mCurrentCookedState.stylusIdBits.isEmpty()) { uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - setMouseCursorPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), - mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); + mPointerController + ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(), + mCurrentCookedState.cookedPointerData.pointerCoords[index].getY()); hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3434,7 +3442,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); - moveMouseCursor(deltaX, deltaY); + mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } @@ -3442,7 +3450,8 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime, uint down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; - auto [x, y] = getMouseCursorPosition(); + float x, y; + mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); @@ -3482,7 +3491,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uin } int32_t displayId = mPointerController->getDisplayId(); - auto [xCursorPosition, yCursorPosition] = getMouseCursorPosition(); + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); if (mPointerSimple.down && !down) { mPointerSimple.down = false; @@ -3648,9 +3658,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t p float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mDeviceMode == DeviceMode::POINTER) { - auto [x, y] = getMouseCursorPosition(); - xCursorPosition = x; - yCursorPosition = y; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); @@ -3999,56 +4007,4 @@ std::optional TouchInputMapper::getAssociatedDisplayId() { return std::nullopt; } -void TouchInputMapper::moveMouseCursor(float dx, float dy) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate - // space that is oriented with the viewport. - rotateDelta(mViewport.orientation, &dx, &dy); - - mPointerController->move(dx, dy); -} - -std::pair TouchInputMapper::getMouseCursorPosition() const { - float x = 0; - float y = 0; - mPointerController->getPosition(&x, &y); - - if (!mViewport.isValid()) return {x, y}; - - // Convert from PointerController's rotated coordinate space that is oriented with the viewport - // to InputReader's un-rotated coordinate space. - const int32_t orientation = getInverseRotation(mViewport.orientation); - rotatePoint(orientation, x, y, mViewport.deviceWidth, mViewport.deviceHeight); - return {x, y}; -} - -void TouchInputMapper::setMouseCursorPosition(float x, float y) const { - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space that is oriented with the viewport. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - mPointerController->setPosition(x, y); -} - -void TouchInputMapper::setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId) { - std::array outSpotCoords{}; - - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { - const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()]; - float x = spotCoords[index].getX(); - float y = spotCoords[index].getY(); - float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - - // Convert from InputReader's un-rotated coordinate space to PointerController's rotated - // coordinate space. - rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight); - - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - } - - mPointerController->setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits, displayId); -} - } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 496491b62d..9b020a609a 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -803,14 +803,6 @@ private: const char* modeToString(DeviceMode deviceMode); void rotateAndScale(float& x, float& y) const; - - // Wrapper methods for interfacing with PointerController. These are used to convert points - // between the coordinate spaces used by InputReader and PointerController, if they differ. - void moveMouseCursor(float dx, float dy) const; - std::pair getMouseCursorPosition() const; - void setMouseCursorPosition(float x, float y) const; - void setTouchSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId); }; } // namespace android -- cgit v1.2.3-59-g8ed1b From d6a7f22182d88888c6ac2824a888766203d33dfc Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 24 Nov 2021 15:36:43 +0000 Subject: Reland "Remove x/y offset from MotionEntry" 2b80b386c4ed5a1b3240da32080280b0a1ec9cef Change-Id: I5afb6f7fd25cd13e42a9b4368fa387bf574e5ec0 --- include/input/Input.h | 5 ++--- libs/input/Input.cpp | 5 ----- services/inputflinger/dispatcher/Entry.cpp | 5 +---- services/inputflinger/dispatcher/Entry.h | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++---- 6 files changed, 11 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..1c79c4a21c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,7 +377,6 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -567,7 +566,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -583,7 +582,7 @@ public: void setCursorPosition(float x, float y); - ui::Transform getRawTransform() const { return mRawTransform; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..69ea7dfcb5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,11 +343,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } -void PointerCoords::applyOffset(float xOffset, float yOffset) { - setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); - setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -} - #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 1674afd02e..3d0818b738 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) + const PointerCoords* pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,9 +235,6 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 477781a2ad..0f792967eb 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,8 +184,7 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3fd1c8aa27..04ff599f13 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); + pointerCoords.data()); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + args->pointerProperties, args->pointerCoords); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, 0, 0); + pointerProperties, samplePointerCoords); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, 0, 0); + samplePointerCoords); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 3bb0bc995c..ad3c6159ef 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,8 +296,7 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); + memento.pointerCoords)); } } return events; @@ -349,8 +348,7 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + pointerCount, pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From 092f3a9b75b1fd465373730ca8d6038c89ed9220 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 25 Nov 2021 10:53:27 -0800 Subject: Add getSurfaceRotation API to MotionEvent Add an API to get the current rotation value of the transform of the MotionEvent. Bug: 207771136 Test: atest MotionEventTest Change-Id: I05fb4455d0dcfc0de8c8564473ee8d43ac86c0bd --- include/input/Input.h | 2 ++ libs/input/Input.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 5242dcb476..29503af65f 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -574,6 +574,8 @@ public: inline ui::Transform getTransform() const { return mTransform; } + int getSurfaceRotation() const; + inline float getXPrecision() const { return mXPrecision; } inline float getYPrecision() const { return mYPrecision; } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index cb93c92310..44487c3a85 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -506,6 +507,24 @@ void MotionEvent::addSample( mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); } +int MotionEvent::getSurfaceRotation() const { + // The surface rotation is the rotation from the window's coordinate space to that of the + // display. Since the event's transform takes display space coordinates to window space, the + // returned surface rotation is the inverse of the rotation for the surface. + switch (mTransform.getOrientation()) { + case ui::Transform::ROT_0: + return DISPLAY_ORIENTATION_0; + case ui::Transform::ROT_90: + return DISPLAY_ORIENTATION_270; + case ui::Transform::ROT_180: + return DISPLAY_ORIENTATION_180; + case ui::Transform::ROT_270: + return DISPLAY_ORIENTATION_90; + default: + return -1; + } +} + float MotionEvent::getXCursorPosition() const { vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition()); return vals.x; -- cgit v1.2.3-59-g8ed1b From f7c99f3f2404f9605c2801caa20b236a595afa3d Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Fri, 3 Dec 2021 10:37:54 +0000 Subject: Revert "Reland "Remove x/y offset from MotionEntry"" Revert submission 16336498-revert-16306432-revert-16295572-ORWQJPYRMQ-IQBEBXXQNX Reason for revert: b/208849306 Reverted Changes: I5afb6f7fd:Reland "Remove x/y offset from MotionEntry" I68b5619bf:Reland "Input injection: Assume transformed values... Change-Id: Id944e4eb39b26e3ffd51998b315a06e87a2af3d5 --- include/input/Input.h | 5 +++-- libs/input/Input.cpp | 5 +++++ services/inputflinger/dispatcher/Entry.cpp | 5 ++++- services/inputflinger/dispatcher/Entry.h | 3 ++- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++++-- 6 files changed, 23 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1c79c4a21c..1e06257591 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,6 +377,7 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); + void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -566,7 +567,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline const ui::Transform& getTransform() const { return mTransform; } + inline ui::Transform getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -582,7 +583,7 @@ public: void setCursorPosition(float x, float y); - inline const ui::Transform& getRawTransform() const { return mRawTransform; } + ui::Transform getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 69ea7dfcb5..8974b22c86 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,6 +343,11 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } +void PointerCoords::applyOffset(float xOffset, float yOffset) { + setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); + setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); +} + #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 3d0818b738..1674afd02e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) + const PointerCoords* pointerCoords, float xOffset, float yOffset) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,6 +235,9 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); + if (xOffset || yOffset) { + this->pointerCoords[i].applyOffset(xOffset, yOffset); + } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 0f792967eb..477781a2ad 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,7 +184,8 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 04ff599f13..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data()); + pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords); + splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); + args->pointerProperties, args->pointerCoords, 0, 0); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords); + pointerProperties, samplePointerCoords, 0, 0); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords); + samplePointerCoords, 0, 0); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index ad3c6159ef..3bb0bc995c 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,7 +296,8 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords)); + memento.pointerCoords, 0 /*xOffset*/, + 0 /*yOffset*/)); } } return events; @@ -348,7 +349,8 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords)); + pointerCount, pointerProperties, pointerCoords, + 0 /*xOffset*/, 0 /*yOffset*/)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From 559361b67ec27a30e8dc52537833feb55f06f3a2 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Mon, 29 Nov 2021 00:07:39 +0000 Subject: Game Loading Time improvement by boosting CPU via ADPF Bug: 201769701 Test: atest android.gamemanager.cts.GameManagerTest Change-Id: I7b6d0a892281360afcdcf3c2cb60e3f9640dd518 --- include/powermanager/PowerHalWrapper.h | 4 +--- services/powermanager/Android.bp | 14 +++++++------- services/powermanager/benchmarks/Android.bp | 2 +- services/powermanager/tests/Android.bp | 2 +- services/powermanager/tests/PowerHalWrapperAidlTest.cpp | 4 ++++ 5 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 2c6eacbfaa..dfb0ff59a0 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -201,10 +201,8 @@ private: std::array, static_cast(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; - // Android framework only sends mode upto DISPLAY_INACTIVE. - // Need to increase the array if more mode supported. std::array, - static_cast(hardware::power::Mode::DISPLAY_INACTIVE) + 1> + static_cast(*(android::enum_range().end() - 1)) + 1> mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN}; }; diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index d828aa97a0..6fbba3f568 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -24,11 +24,11 @@ cc_library_shared { ], aidl: { - local_include_dirs: ["include"], - include_dirs: [ - "frameworks/base/core/java/android/os", - ], - export_aidl_headers: true + local_include_dirs: ["include"], + include_dirs: [ + "frameworks/base/core/java/android/os", + ], + export_aidl_headers: true, }, shared_libs: [ @@ -38,7 +38,7 @@ cc_library_shared { "libutils", "android.hardware.power@1.0", "android.hardware.power@1.1", - "android.hardware.power-V2-cpp", + "android.hardware.power-V3-cpp", ], cflags: [ @@ -50,6 +50,6 @@ cc_library_shared { local_include_dirs: ["include"], export_include_dirs: [ - "include", + "include", ], } diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp index 3997929053..fcb012fc75 100644 --- a/services/powermanager/benchmarks/Android.bp +++ b/services/powermanager/benchmarks/Android.bp @@ -38,7 +38,7 @@ cc_benchmark { "libutils", "android.hardware.power@1.0", "android.hardware.power@1.1", - "android.hardware.power-V2-cpp", + "android.hardware.power-V3-cpp", ], static_libs: [ "libtestUtil", diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp index 659b2d273a..2d1558a33f 100644 --- a/services/powermanager/tests/Android.bp +++ b/services/powermanager/tests/Android.bp @@ -46,7 +46,7 @@ cc_test { "libutils", "android.hardware.power@1.0", "android.hardware.power@1.1", - "android.hardware.power-V2-cpp", + "android.hardware.power-V3-cpp", ], static_libs: [ "libgmock", diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp index d890f5c332..cb1a77a45f 100644 --- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -183,6 +183,10 @@ TEST_F(PowerHalWrapperAidlTest, TestSetModeUnsupported) { auto result = mWrapper->setMode(Mode::LAUNCH, true); ASSERT_TRUE(result.isUnsupported()); + + EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::CAMERA_STREAMING_HIGH), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status()))); result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); ASSERT_TRUE(result.isUnsupported()); } -- cgit v1.2.3-59-g8ed1b From f355bf982478381f838e8d3318aa67cede2daf10 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 9 Dec 2021 10:43:21 -0800 Subject: Reorder VerifiedKey/MotionEvent structs for hwasan Now, the 'nsecs_t' fields of this struct will no longer be falling on 4-byte boundaries. This prevents a hwasan crash. Bug: 209991446 Test: atest inputflinger_tests Change-Id: If28c7ff66b9495a3d61f590464d2b995afbe0c2b --- include/input/Input.h | 4 ++-- libs/input/Input.cpp | 4 ++-- services/inputflinger/dispatcher/Entry.cpp | 4 ++-- services/inputflinger/tests/InputDispatcher_test.cpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 29503af65f..e1cacac273 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -945,8 +945,8 @@ struct __attribute__((__packed__)) VerifiedInputEvent { */ struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent { int32_t action; - nsecs_t downTimeNanos; int32_t flags; + nsecs_t downTimeNanos; int32_t keyCode; int32_t scanCode; int32_t metaState; @@ -961,8 +961,8 @@ struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEve float rawX; float rawY; int32_t actionMasked; - nsecs_t downTimeNanos; int32_t flags; + nsecs_t downTimeNanos; int32_t metaState; int32_t buttonState; }; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 44487c3a85..f0b97a7ba8 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -192,8 +192,8 @@ VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), event.getSource(), event.getDisplayId()}, event.getAction(), - event.getDownTime(), event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, + event.getDownTime(), event.getKeyCode(), event.getScanCode(), event.getMetaState(), @@ -206,8 +206,8 @@ VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) event.getRawX(0), event.getRawY(0), event.getActionMasked(), - event.getDownTime(), event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, + event.getDownTime(), event.getMetaState(), event.getButtonState()}; } diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index f6bb6a63a7..936ecf9889 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -32,8 +32,8 @@ VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) { return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source, entry.displayId}, entry.action, - entry.downTime, entry.flags & VERIFIED_KEY_EVENT_FLAGS, + entry.downTime, entry.keyCode, entry.scanCode, entry.metaState, @@ -50,8 +50,8 @@ VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry, rawXY.x, rawXY.y, actionMasked, - entry.downTime, entry.flags & VERIFIED_MOTION_EVENT_FLAGS, + entry.downTime, entry.metaState, entry.buttonState}; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 39c52628d4..2c64271cca 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3145,8 +3145,8 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { const VerifiedKeyEvent& verifiedKey = static_cast(*verified); ASSERT_EQ(keyArgs.action, verifiedKey.action); - ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos); ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags); + ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos); ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode); ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode); ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState); @@ -3194,8 +3194,8 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(rawXY.x, verifiedMotion.rawX); EXPECT_EQ(rawXY.y, verifiedMotion.rawY); EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked); - EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos); EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags); + EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos); EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState); EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } @@ -4179,7 +4179,7 @@ protected: } } - void touchAndAssertPositions(int32_t action, std::vector touchedPoints, + void touchAndAssertPositions(int32_t action, const std::vector& touchedPoints, std::vector expectedPoints) { NotifyMotionArgs motionArgs = generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, touchedPoints); -- cgit v1.2.3-59-g8ed1b From ed511efbdfac3408cb3ae237016f095fd64cebec Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Mon, 11 Oct 2021 15:09:51 -0700 Subject: Add frame timeline method to ASurfaceControl NDK. Bug: 198192003 Test: atest ASurfaceControlTest perfetto trace Change-Id: I04310bd9190cfc227ff5ba892c7187d3b8a20463 --- include/android/surface_control.h | 9 +++++++++ libs/gui/FrameTimelineInfo.cpp | 5 +++++ libs/gui/Surface.cpp | 3 ++- libs/gui/include/gui/FrameTimelineInfo.h | 3 +++ libs/nativewindow/include/system/window.h | 9 +++++---- services/surfaceflinger/FrameTimeline/FrameTimeline.cpp | 3 ++- services/surfaceflinger/Layer.cpp | 2 ++ 7 files changed, 28 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 059bc41f9a..3a131045e8 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -595,6 +595,15 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, bool enableBackPressure) __INTRODUCED_IN(31); +/** + * Sets the frame timeline to use. + * + * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to + * the corresponding expected present time and deadline from the frame to be rendered. + */ +void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction, + int64_t vsyncId) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp index 9231a570fc..3800b88ab0 100644 --- a/libs/gui/FrameTimelineInfo.cpp +++ b/libs/gui/FrameTimelineInfo.cpp @@ -33,12 +33,14 @@ namespace android { status_t FrameTimelineInfo::write(Parcel& output) const { SAFE_PARCEL(output.writeInt64, vsyncId); SAFE_PARCEL(output.writeInt32, inputEventId); + SAFE_PARCEL(output.writeInt64, startTimeNanos); return NO_ERROR; } status_t FrameTimelineInfo::read(const Parcel& input) { SAFE_PARCEL(input.readInt64, &vsyncId); SAFE_PARCEL(input.readInt32, &inputEventId); + SAFE_PARCEL(input.readInt64, &startTimeNanos); return NO_ERROR; } @@ -48,16 +50,19 @@ void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { if (other.vsyncId > vsyncId) { vsyncId = other.vsyncId; inputEventId = other.inputEventId; + startTimeNanos = other.startTimeNanos; } } else if (vsyncId == INVALID_VSYNC_ID) { vsyncId = other.vsyncId; inputEventId = other.inputEventId; + startTimeNanos = other.startTimeNanos; } } void FrameTimelineInfo::clear() { vsyncId = INVALID_VSYNC_ID; inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; + startTimeNanos = 0; } }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 353a91d062..20c41460d4 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1846,9 +1846,10 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); auto inputEventId = static_cast(va_arg(args, int32_t)); + auto startTimeNanos = static_cast(va_arg(args, int64_t)); ALOGV("Surface::%s", __func__); - return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); + return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos}); } bool Surface::transformToDisplayInverse() const { diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h index a23c20248c..255ce568d2 100644 --- a/libs/gui/include/gui/FrameTimelineInfo.h +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -36,6 +36,9 @@ struct FrameTimelineInfo { // not directly vendor available. int32_t inputEventId = 0; + // The current time in nanoseconds the application started to render the frame. + int64_t startTimeNanos = 0; + status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 0bc2b5d312..a319769148 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1025,10 +1025,11 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo } static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, - int64_t frameTimelineVsyncId, - int32_t inputEventId) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, - frameTimelineVsyncId, inputEventId); + int64_t frameTimelineVsyncId, + int32_t inputEventId, + int64_t startTimeNanos) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineVsyncId, + inputEventId, startTimeNanos); } // ------------------------------------------------------------------------------------------------ diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 0c4e1120fc..86e96d769c 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -667,7 +667,8 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken) const { packet->set_timestamp( static_cast(endTime - kPredictionExpiredStartTimeDelta)); } else { - packet->set_timestamp(static_cast(mPredictions.startTime)); + packet->set_timestamp(static_cast( + mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime)); } auto* event = packet->set_frame_timeline_event(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 495d585509..c3b2fa598f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1253,6 +1253,7 @@ std::shared_ptr Layer::createSurfaceFrameForTransac getSequence(), mName, mTransactionName, /*isBuffer*/ false, getGameMode()); + surfaceFrame->setActualStartTime(info.startTimeNanos); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); @@ -1270,6 +1271,7 @@ std::shared_ptr Layer::createSurfaceFrameForBuffer( mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, /*isBuffer*/ true, getGameMode()); + surfaceFrame->setActualStartTime(info.startTimeNanos); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); -- cgit v1.2.3-59-g8ed1b From b1e1e3914c8be41c83d3f6e7c71e53dffcd43f16 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 16 Dec 2021 03:28:20 -0800 Subject: Pass JNIEnv explicitly into AInputQueue_fromJava Instead of assuming a JNIEnv*, the method should have the env passed into it, which is the standard practice for native APIs. Bug: 210727635 Test: atest InputQueueTest Change-Id: I94d168e9370aed2081912971b82c472e18c65f12 --- include/android/input.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/android/input.h b/include/android/input.h index 27587ce483..447f8fa842 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -1391,7 +1391,7 @@ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled * * Available since API level 33. */ -AInputQueue* AInputQueue_fromJava(jobject inputQueue) __INTRODUCED_IN(33); +AInputQueue* AInputQueue_fromJava(JNIEnv* env, jobject inputQueue) __INTRODUCED_IN(33); #ifdef __cplusplus } -- cgit v1.2.3-59-g8ed1b From 9d43974f4d7110552d5ca39d0a8576b8c87fdb6f Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 16 Dec 2021 03:32:30 -0800 Subject: Add lifecycle information to docs for AInputQueue_fromJava Add documentation to AInputQueue_fromJava to make it explicit that the returned native object is only valid as long as the java object has not yet been disposed. Test: None Bug: 210727408 Change-Id: I20ec68afba0ec79477d57b8a110d55220b7c01ff --- include/android/input.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/android/input.h b/include/android/input.h index 447f8fa842..fbd61b53f4 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -1386,8 +1386,11 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); /** - * Supplies the AInputQueue* object associated with the supplied Java InputQueue - * object. + * Returns the AInputQueue* object associated with the supplied Java InputQueue + * object. The returned native object holds a weak reference to the Java object, + * and is only valid as long as the Java object has not yet been disposed. You + * should ensure that there is a strong reference to the Java object and that it + * has not been disposed before using the returned object. * * Available since API level 33. */ -- cgit v1.2.3-59-g8ed1b From 5beda769594b8a86439ae5969a8448f7b4c5e522 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 10 Dec 2021 09:30:08 +0000 Subject: Reland^2 "Remove x/y offset from MotionEntry" f7c99f3f2404f9605c2801caa20b236a595afa3d Bug: 206842332 Change-Id: Id42790e6c1d562c61efb6673407a2861927df40b --- include/input/Input.h | 5 ++--- libs/input/Input.cpp | 5 ----- services/inputflinger/dispatcher/Entry.cpp | 5 +---- services/inputflinger/dispatcher/Entry.h | 3 +-- services/inputflinger/dispatcher/InputDispatcher.cpp | 10 +++++----- services/inputflinger/dispatcher/InputState.cpp | 6 ++---- 6 files changed, 11 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index 1e06257591..1c79c4a21c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -377,7 +377,6 @@ struct PointerCoords { // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR // axes, however the window scaling will not. void scale(float globalScale, float windowXScale, float windowYScale); - void applyOffset(float xOffset, float yOffset); void transform(const ui::Transform& transform); @@ -567,7 +566,7 @@ public: inline float getYOffset() const { return mTransform.ty(); } - inline ui::Transform getTransform() const { return mTransform; } + inline const ui::Transform& getTransform() const { return mTransform; } inline float getXPrecision() const { return mXPrecision; } @@ -583,7 +582,7 @@ public: void setCursorPosition(float x, float y); - ui::Transform getRawTransform() const { return mRawTransform; } + inline const ui::Transform& getRawTransform() const { return mRawTransform; } static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8974b22c86..69ea7dfcb5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -343,11 +343,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } -void PointerCoords::applyOffset(float xOffset, float yOffset) { - setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset); - setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset); -} - #ifdef __linux__ status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 1674afd02e..3d0818b738 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -214,7 +214,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset) + const PointerCoords* pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -235,9 +235,6 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); - if (xOffset || yOffset) { - this->pointerCoords[i].applyOffset(xOffset, yOffset); - } } } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 477781a2ad..0f792967eb 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -184,8 +184,7 @@ struct MotionEntry : EventEntry { int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3fd1c8aa27..04ff599f13 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -378,7 +378,7 @@ std::unique_ptr createDispatchEntry(const InputTarget& inputTarge motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */); + pointerCoords.data()); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -3752,7 +3752,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords, 0, 0); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -3978,7 +3978,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->xPrecision, args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords, 0, 0); + args->pointerProperties, args->pointerCoords); if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && @@ -4208,7 +4208,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, 0, 0); + pointerProperties, samplePointerCoords); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { @@ -4228,7 +4228,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, 0, 0); + samplePointerCoords); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 3bb0bc995c..ad3c6159ef 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -296,8 +296,7 @@ std::vector> InputState::synthesizeCancelationEvents memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, memento.pointerCount, memento.pointerProperties, - memento.pointerCoords, 0 /*xOffset*/, - 0 /*yOffset*/)); + memento.pointerCoords)); } } return events; @@ -349,8 +348,7 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + pointerCount, pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; -- cgit v1.2.3-59-g8ed1b From 90bc949048f2b91fa841cb8272381af8c301c055 Mon Sep 17 00:00:00 2001 From: Philip Junker Date: Fri, 10 Dec 2021 18:39:42 +0100 Subject: Fix KeyCharacterMap overlays by reloading base overlay before applying another overlay. Add all fields to parcel (mLoadFileName, mLayoutOverlayApplied, mKeysByScanCode, mKeysByUsageCode). Add all fields to equality operator. Add tests to libinput_tests. Bug: 210090260 Test: Manually verified that layout changes correctly. Test: atest libinput_tests Change-Id: I1777b87e5c2ce8a0dbd42ad48748ea9e669c9139 --- include/input/KeyCharacterMap.h | 18 +- libs/input/KeyCharacterMap.cpp | 136 +++++++++--- libs/input/tests/Android.bp | 3 +- libs/input/tests/InputDevice_test.cpp | 50 +++++ libs/input/tests/data/english_us.kcm | 311 +++++++++++++++++++++++++++ libs/input/tests/data/french.kcm | 336 ++++++++++++++++++++++++++++++ libs/input/tests/data/german.kcm | 336 ++++++++++++++++++++++++++++++ services/inputflinger/reader/EventHub.cpp | 9 +- 8 files changed, 1163 insertions(+), 36 deletions(-) create mode 100644 libs/input/tests/data/english_us.kcm create mode 100644 libs/input/tests/data/french.kcm create mode 100644 libs/input/tests/data/german.kcm (limited to 'include') diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 451ca3c6cd..f6f8939b7a 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -84,7 +84,7 @@ public: const std::string getLoadFileName() const; - /* Combines this key character map with an overlay. */ + /* Combines this key character map with the provided overlay. */ void combine(const KeyCharacterMap& overlay); /* Gets the keyboard type. */ @@ -144,6 +144,8 @@ public: bool operator==(const KeyCharacterMap& other) const; + bool operator!=(const KeyCharacterMap& other) const; + KeyCharacterMap(const KeyCharacterMap& other); virtual ~KeyCharacterMap(); @@ -230,11 +232,12 @@ private: KeyedVector mKeys; KeyboardType mType; std::string mLoadFileName; + bool mLayoutOverlayApplied; KeyedVector mKeysByScanCode; KeyedVector mKeysByUsageCode; - KeyCharacterMap(); + KeyCharacterMap(const std::string& filename); bool getKey(int32_t keyCode, const Key** outKey) const; bool getKeyBehavior(int32_t keyCode, int32_t metaState, @@ -243,8 +246,6 @@ private: bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; - static base::Result> load(Tokenizer* tokenizer, Format format); - static void addKey(Vector& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); static void addMetaKeys(Vector& outEvents, @@ -264,6 +265,15 @@ private: int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); + + /* Clears all data stored in this key character map */ + void clear(); + + /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */ + status_t load(Tokenizer* tokenizer, Format format); + + /* Reloads the data from mLoadFileName and unapplies any overlay. */ + status_t reloadBaseFromFile(); }; } // namespace android diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 3baeb55009..2039fa6553 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -86,10 +86,13 @@ static String8 toString(const char16_t* chars, size_t numChars) { // --- KeyCharacterMap --- -KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {} +KeyCharacterMap::KeyCharacterMap(const std::string& filename) + : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {} KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : mType(other.mType), + mLoadFileName(other.mLoadFileName), + mLayoutOverlayApplied(other.mLayoutOverlayApplied), mKeysByScanCode(other.mKeysByScanCode), mKeysByUsageCode(other.mKeysByUsageCode) { for (size_t i = 0; i < other.mKeys.size(); i++) { @@ -98,16 +101,19 @@ KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) } KeyCharacterMap::~KeyCharacterMap() { - for (size_t i = 0; i < mKeys.size(); i++) { - Key* key = mKeys.editValueAt(i); - delete key; - } + clear(); } bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const { if (mType != other.mType) { return false; } + if (mLoadFileName != other.mLoadFileName) { + return false; + } + if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) { + return false; + } if (mKeys.size() != other.mKeys.size() || mKeysByScanCode.size() != other.mKeysByScanCode.size() || mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) { @@ -146,6 +152,10 @@ bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const { return true; } +bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const { + return !(*this == other); +} + base::Result> KeyCharacterMap::load(const std::string& filename, Format format) { Tokenizer* tokenizer; @@ -153,12 +163,18 @@ base::Result> KeyCharacterMap::load(const std:: if (status) { return Errorf("Error {} opening key character map file {}.", status, filename.c_str()); } + std::shared_ptr map = + std::shared_ptr(new KeyCharacterMap(filename)); + if (!map.get()) { + ALOGE("Error allocating key character map."); + return Errorf("Error allocating key character map."); + } std::unique_ptr t(tokenizer); - auto ret = load(t.get(), format); - if (ret.ok()) { - (*ret)->mLoadFileName = filename; + status = map->load(t.get(), format); + if (status == OK) { + return map; } - return ret; + return Errorf("Load KeyCharacterMap failed {}.", status); } base::Result> KeyCharacterMap::loadContents( @@ -169,40 +185,67 @@ base::Result> KeyCharacterMap::loadContents( ALOGE("Error %d opening key character map.", status); return Errorf("Error {} opening key character map.", status); } + std::shared_ptr map = + std::shared_ptr(new KeyCharacterMap(filename)); + if (!map.get()) { + ALOGE("Error allocating key character map."); + return Errorf("Error allocating key character map."); + } std::unique_ptr t(tokenizer); - auto ret = load(t.get(), format); - if (ret.ok()) { - (*ret)->mLoadFileName = filename; + status = map->load(t.get(), format); + if (status == OK) { + return map; } - return ret; + return Errorf("Load KeyCharacterMap failed {}.", status); } -base::Result> KeyCharacterMap::load(Tokenizer* tokenizer, - Format format) { +status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) { status_t status = OK; - std::shared_ptr map = std::shared_ptr(new KeyCharacterMap()); - if (!map.get()) { - ALOGE("Error allocating key character map."); - return Errorf("Error allocating key character map."); - } #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif - Parser parser(map.get(), tokenizer, format); + Parser parser(this, tokenizer, format); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif - if (status == OK) { - return map; + if (status != OK) { + ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str()); } + return status; +} - return Errorf("Load KeyCharacterMap failed {}.", status); +void KeyCharacterMap::clear() { + mKeysByScanCode.clear(); + mKeysByUsageCode.clear(); + for (size_t i = 0; i < mKeys.size(); i++) { + Key* key = mKeys.editValueAt(i); + delete key; + } + mKeys.clear(); + mLayoutOverlayApplied = false; + mType = KeyboardType::UNKNOWN; +} + +status_t KeyCharacterMap::reloadBaseFromFile() { + clear(); + Tokenizer* tokenizer; + status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer); + if (status) { + ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(), + mLoadFileName.c_str()); + return status; + } + std::unique_ptr t(tokenizer); + return load(t.get(), KeyCharacterMap::Format::BASE); } void KeyCharacterMap::combine(const KeyCharacterMap& overlay) { + if (mLayoutOverlayApplied) { + reloadBaseFromFile(); + } for (size_t i = 0; i < overlay.mKeys.size(); i++) { int32_t keyCode = overlay.mKeys.keyAt(i); Key* key = overlay.mKeys.valueAt(i); @@ -224,7 +267,7 @@ void KeyCharacterMap::combine(const KeyCharacterMap& overlay) { mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i), overlay.mKeysByUsageCode.valueAt(i)); } - mLoadFileName = overlay.mLoadFileName; + mLayoutOverlayApplied = true; } KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const { @@ -636,8 +679,11 @@ std::shared_ptr KeyCharacterMap::readFromParcel(Parcel* parcel) ALOGE("%s: Null parcel", __func__); return nullptr; } - std::shared_ptr map = std::shared_ptr(new KeyCharacterMap()); + std::string loadFileName = parcel->readCString(); + std::shared_ptr map = + std::shared_ptr(new KeyCharacterMap(loadFileName)); map->mType = static_cast(parcel->readInt32()); + map->mLayoutOverlayApplied = parcel->readBool(); size_t numKeys = parcel->readInt32(); if (parcel->errorCheck()) { return nullptr; @@ -687,6 +733,30 @@ std::shared_ptr KeyCharacterMap::readFromParcel(Parcel* parcel) return nullptr; } } + size_t numKeysByScanCode = parcel->readInt32(); + if (parcel->errorCheck()) { + return nullptr; + } + for (size_t i = 0; i < numKeysByScanCode; i++) { + int32_t key = parcel->readInt32(); + int32_t value = parcel->readInt32(); + map->mKeysByScanCode.add(key, value); + if (parcel->errorCheck()) { + return nullptr; + } + } + size_t numKeysByUsageCode = parcel->readInt32(); + if (parcel->errorCheck()) { + return nullptr; + } + for (size_t i = 0; i < numKeysByUsageCode; i++) { + int32_t key = parcel->readInt32(); + int32_t value = parcel->readInt32(); + map->mKeysByUsageCode.add(key, value); + if (parcel->errorCheck()) { + return nullptr; + } + } return map; } @@ -695,7 +765,9 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { ALOGE("%s: Null parcel", __func__); return; } + parcel->writeCString(mLoadFileName.c_str()); parcel->writeInt32(static_cast(mType)); + parcel->writeBool(mLayoutOverlayApplied); size_t numKeys = mKeys.size(); parcel->writeInt32(numKeys); @@ -715,6 +787,18 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const { } parcel->writeInt32(0); } + size_t numKeysByScanCode = mKeysByScanCode.size(); + parcel->writeInt32(numKeysByScanCode); + for (size_t i = 0; i < numKeysByScanCode; i++) { + parcel->writeInt32(mKeysByScanCode.keyAt(i)); + parcel->writeInt32(mKeysByScanCode.valueAt(i)); + } + size_t numKeysByUsageCode = mKeysByUsageCode.size(); + parcel->writeInt32(numKeysByUsageCode); + for (size_t i = 0; i < numKeysByUsageCode; i++) { + parcel->writeInt32(mKeysByUsageCode.keyAt(i)); + parcel->writeInt32(mKeysByUsageCode.valueAt(i)); + } } #endif // __linux__ diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 18ab1cb522..6ffe8518b6 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -37,6 +37,7 @@ cc_test { "libui", "libutils", ], + data: ["data/*.kcm"], test_suites: ["device-tests"], } @@ -59,5 +60,5 @@ cc_library_static { "libbinder", "libui", "libbase", - ] + ], } diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp index f8f2f4e931..61e88df11d 100644 --- a/libs/input/tests/InputDevice_test.cpp +++ b/libs/input/tests/InputDevice_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include "android-base/file.h" namespace android { @@ -82,4 +83,53 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) { ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); } +TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) { + Parcel parcel; + std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; + base::Result> 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 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> frenchOverlay = + KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath; + base::Result> englishOverlay = + KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath; + base::Result> 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 frenchOverlaidKeyCharacterMap = + std::make_shared(*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); +} + } // namespace android diff --git a/libs/input/tests/data/english_us.kcm b/libs/input/tests/data/english_us.kcm new file mode 100644 index 0000000000..d0ef027f85 --- /dev/null +++ b/libs/input/tests/data/english_us.kcm @@ -0,0 +1,311 @@ +# Copyright (C) 2021 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. + +# +# English (US) keyboard layout. +# Unlike the default (generic) keyboard layout, English (US) does not contain any +# special ALT characters. +# + +type OVERLAY + +### ROW 1 + +key GRAVE { + label: '`' + base: '`' + shift: '~' +} + +key 1 { + label: '1' + base: '1' + shift: '!' +} + +key 2 { + label: '2' + base: '2' + shift: '@' +} + +key 3 { + label: '3' + base: '3' + shift: '#' +} + +key 4 { + label: '4' + base: '4' + shift: '$' +} + +key 5 { + label: '5' + base: '5' + shift: '%' +} + +key 6 { + label: '6' + base: '6' + shift: '^' +} + +key 7 { + label: '7' + base: '7' + shift: '&' +} + +key 8 { + label: '8' + base: '8' + shift: '*' +} + +key 9 { + label: '9' + base: '9' + shift: '(' +} + +key 0 { + label: '0' + base: '0' + shift: ')' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' +} + +key EQUALS { + label: '=' + base: '=' + shift: '+' +} + +### ROW 2 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '[' + base: '[' + shift: '{' +} + +key RIGHT_BRACKET { + label: ']' + base: ']' + shift: '}' +} + +key BACKSLASH { + label: '\\' + base: '\\' + shift: '|' +} + +### ROW 3 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: ';' + base: ';' + shift: ':' +} + +key APOSTROPHE { + label: '\'' + base: '\'' + shift: '"' +} + +### ROW 4 + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key COMMA { + label: ',' + base: ',' + shift: '<' +} + +key PERIOD { + label: '.' + base: '.' + shift: '>' +} + +key SLASH { + label: '/' + base: '/' + shift: '?' +} \ No newline at end of file diff --git a/libs/input/tests/data/french.kcm b/libs/input/tests/data/french.kcm new file mode 100644 index 0000000000..db69ea0430 --- /dev/null +++ b/libs/input/tests/data/french.kcm @@ -0,0 +1,336 @@ +# Copyright (C) 2021 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. + +# +# French keyboard layout, AZERTY style. +# + +type OVERLAY + +map key 16 A +map key 17 Z +map key 30 Q +map key 39 M +map key 44 W +map key 50 COMMA +map key 51 SEMICOLON +map key 86 PLUS + +### ROW 1 + +key GRAVE { + label: '\u00b2' + base: '\u00b2' +} + +key 1 { + label: '1' + base: '&' + shift: '1' +} + +key 2 { + label: '2' + base: '\u00e9' + shift: '2' + ralt: '~' +} + +key 3 { + label: '3' + base: '"' + shift: '3' + ralt: '#' +} + +key 4 { + label: '4' + base: '\'' + shift: '4' + ralt: '{' +} + +key 5 { + label: '5' + base: '(' + shift: '5' + ralt: '[' +} + +key 6 { + label: '6' + base: '-' + shift: '6' + ralt: '|' +} + +key 7 { + label: '7' + base: '\u00e8' + shift: '7' + ralt: '`' +} + +key 8 { + label: '8' + base: '_' + shift: '8' + ralt: '\\' +} + +key 9 { + label: '9' + base: '\u00e7' + shift: '9' + ralt: '^' +} + +key 0 { + label: '0' + base: '\u00e0' + shift: '0' + ralt: '@' +} + +key MINUS { + label: ')' + base: ')' + shift: '\u00b0' + ralt: ']' +} + +key EQUALS { + label: '=' + base: '=' + shift: '+' + ralt: '}' +} + +### ROW 2 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '\u02c6' + base: '\u0302' + shift: '\u0308' +} + +key RIGHT_BRACKET { + label: '$' + base: '$' + shift: '\u00a3' + ralt: '\u00a4' +} + +### ROW 3 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key APOSTROPHE { + label: '\u00f9' + base: '\u00f9' + shift: '%' +} + +key BACKSLASH { + label: '*' + base: '*' + shift: '\u00b5' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key COMMA { + label: ',' + base: ',' + shift: '?' +} + +key SEMICOLON { + label: ';' + base: ';' + shift: '.' +} + +key PERIOD { + label: ':' + base: ':' + shift: '/' +} + +key SLASH { + label: '!' + base: '!' + shift: '\u00a7' +} \ No newline at end of file diff --git a/libs/input/tests/data/german.kcm b/libs/input/tests/data/german.kcm new file mode 100644 index 0000000000..2fbc5e54e3 --- /dev/null +++ b/libs/input/tests/data/german.kcm @@ -0,0 +1,336 @@ +# Copyright (C) 2021 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. + +# +# German keyboard layout, QWERTZ style. +# + +type OVERLAY + +map key 12 SLASH # � ? \ +map key 21 Z +map key 44 Y +map key 53 MINUS # - _ +map key 86 PLUS # < > | + +map key usage 32 A # for testing purposes only +map key usage 67 B # for testing purposes only + +### ROW 1 + +key GRAVE { + label: '^' + base: '^' + shift: '\u00b0' +} + +key 1 { + label: '1' + base: '1' + shift: '!' +} + +key 2 { + label: '2' + base: '2' + shift: '"' + ralt: '\u00b2' +} + +key 3 { + label: '3' + base: '3' + shift: '\u00a7' + ralt: '\u00b3' +} + +key 4 { + label: '4' + base: '4' + shift: '$' +} + +key 5 { + label: '5' + base: '5' + shift: '%' +} + +key 6 { + label: '6' + base: '6' + shift: '&' +} + +key 7 { + label: '7' + base: '7' + shift: '/' + ralt: '{' +} + +key 8 { + label: '8' + base: '8' + shift: '(' + ralt: '[' +} + +key 9 { + label: '9' + base: '9' + shift: ')' + ralt: ']' +} + +key 0 { + label: '0' + base: '0' + shift: '=' + ralt: '}' +} + +key SLASH { + label: '\u00df' + base: '\u00df' + shift: '?' + ralt: '\\' +} + +key EQUALS { + label: '\u00b4' + base: '\u0301' + shift: '\u0300' +} + +### ROW 2 + +key Q { + label: 'Q' + base: 'q' + shift, capslock: 'Q' + ralt: '@' +} + +key W { + label: 'W' + base: 'w' + shift, capslock: 'W' +} + +key E { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key R { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key T { + label: 'T' + base: 't' + shift, capslock: 'T' +} + +key Z { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key U { + label: 'U' + base: 'u' + shift, capslock: 'U' +} + +key I { + label: 'I' + base: 'i' + shift, capslock: 'I' +} + +key O { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' +} + +key LEFT_BRACKET { + label: '\u00dc' + base: '\u00fc' + shift, capslock: '\u00dc' +} + +key RIGHT_BRACKET { + label: '+' + base: '+' + shift: '*' + ralt: '~' +} + +### ROW 3 + +key A { + label: 'A' + base: 'a' + shift, capslock: 'A' +} + +key S { + label: 'S' + base: 's' + shift, capslock: 'S' +} + +key D { + label: 'D' + base: 'd' + shift, capslock: 'D' +} + +key F { + label: 'F' + base: 'f' + shift, capslock: 'F' +} + +key G { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key H { + label: 'H' + base: 'h' + shift, capslock: 'H' +} + +key J { + label: 'J' + base: 'j' + shift, capslock: 'J' +} + +key K { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: '\u00d6' + base: '\u00f6' + shift, capslock: '\u00d6' +} + +key APOSTROPHE { + label: '\u00c4' + base: '\u00e4' + shift, capslock: '\u00c4' +} + +key BACKSLASH { + label: '#' + base: '#' + shift: '\'' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' + ralt: '|' +} + +key Y { + label: 'Y' + base: 'y' + shift, capslock: 'Y' +} + +key X { + label: 'X' + base: 'x' + shift, capslock: 'X' +} + +key C { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key V { + label: 'V' + base: 'v' + shift, capslock: 'V' +} + +key B { + label: 'B' + base: 'b' + shift, capslock: 'B' +} + +key N { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key M { + label: 'M' + base: 'm' + shift, capslock: 'M' + ralt: '\u00b5' +} + +key COMMA { + label: ',' + base: ',' + shift: ';' +} + +key PERIOD { + label: '.' + base: '.' + shift: ':' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' +} diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index d10f8b6605..110f5f7f12 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -1262,12 +1262,11 @@ const std::shared_ptr EventHub::getKeyCharacterMap(int32_t devi bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr map) { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) { - device->keyMap.keyCharacterMap->combine(*map); - device->keyMap.keyCharacterMapFile = device->keyMap.keyCharacterMap->getLoadFileName(); - return true; + if (device == nullptr || map == nullptr || device->keyMap.keyCharacterMap == nullptr) { + return false; } - return false; + device->keyMap.keyCharacterMap->combine(*map); + return true; } static std::string generateDescriptor(InputDeviceIdentifier& identifier) { -- cgit v1.2.3-59-g8ed1b From c74e9e21d569956eb4e132f0521f785c29af3223 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 2 Dec 2021 09:49:12 -0800 Subject: FTL: Add variadic concatenation For now, the arguments can only be integers, string literals, and truncated string views, as this will mainly be used for tracing. Bug: 185536303 Test: ftl_test Change-Id: I3141992c6c9438710f04b056e67a5e8811d39f78 --- include/ftl/concat.h | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/ftl/details/concat.h | 62 ++++++++++++++++++++++++++++++++ libs/ftl/Android.bp | 1 + libs/ftl/concat_test.cpp | 55 +++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 include/ftl/concat.h create mode 100644 include/ftl/details/concat.h create mode 100644 libs/ftl/concat_test.cpp (limited to 'include') diff --git a/include/ftl/concat.h b/include/ftl/concat.h new file mode 100644 index 0000000000..ded48f7c8c --- /dev/null +++ b/include/ftl/concat.h @@ -0,0 +1,84 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include + +namespace android::ftl { + +// Lightweight (not allocating nor sprintf-based) concatenation. +// +// std::string_view name = "Volume"; +// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); +// +// assert(string.str() == "Vol: -3 dB"); +// assert(string.c_str()[string.size()] == '\0'); +// +template +struct Concat; + +template +struct Concat : Concat::N, Ts...> { + explicit constexpr Concat(T v, Ts... args) { append(v, args...); } + + protected: + constexpr Concat() = default; + + constexpr void append(T v, Ts... args) { + using Str = details::StaticString; + const Str str(v); + + // TODO: Replace with constexpr std::copy in C++20. + for (auto it = str.view.begin(); it != str.view.end();) { + *this->end_++ = *it++; + } + + using Base = Concat; + this->Base::append(args...); + } +}; + +template +struct Concat { + static constexpr std::size_t max_size() { return N; } + constexpr std::size_t size() const { return end_ - buffer_; } + + constexpr const char* c_str() const { return buffer_; } + + constexpr std::string_view str() const { + // TODO: Replace with {buffer_, end_} in C++20. + return {buffer_, size()}; + } + + protected: + constexpr Concat() : end_(buffer_) {} + constexpr void append() { *end_ = '\0'; } + + char buffer_[N + 1]; + char* end_; +}; + +// Deduction guide. +template +Concat(Ts&&...) -> Concat<0, Ts...>; + +template +constexpr auto truncated(std::string_view v) { + return details::Truncated{v}; +} + +} // namespace android::ftl diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h new file mode 100644 index 0000000000..8ce949ef05 --- /dev/null +++ b/include/ftl/details/concat.h @@ -0,0 +1,62 @@ +/* + * Copyright 2021 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. + */ + +#pragma once + +#include +#include + +#include + +namespace android::ftl::details { + +template +struct StaticString; + +template +struct StaticString>> { + static constexpr std::size_t N = to_chars_length_v; + + explicit StaticString(T v) : view(to_chars(buffer, v)) {} + + to_chars_buffer_t buffer; + const std::string_view view; +}; + +template +struct StaticString { + static constexpr std::size_t N = M - 1; + + explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {} + + const std::string_view view; +}; + +template +struct Truncated { + std::string_view view; +}; + +template +struct StaticString, void> { + static constexpr std::size_t N = M; + + explicit constexpr StaticString(Truncated str) : view(str.view.substr(0, N)) {} + + const std::string_view view; +}; + +} // namespace android::ftl::details diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 5a80ad067c..bc2eb23677 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -16,6 +16,7 @@ cc_test { srcs: [ "Flags_test.cpp", "cast_test.cpp", + "concat_test.cpp", "enum_test.cpp", "future_test.cpp", "small_map_test.cpp", diff --git a/libs/ftl/concat_test.cpp b/libs/ftl/concat_test.cpp new file mode 100644 index 0000000000..8ecb1b252d --- /dev/null +++ b/libs/ftl/concat_test.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2021 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 +#include + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(Concat, Example) { + std::string_view name = "Volume"; + ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); + + EXPECT_EQ(string.str(), "Vol: -3 dB"); + EXPECT_EQ(string.c_str()[string.size()], '\0'); +} + +namespace { + +static_assert(ftl::Concat{"foo"}.str() == "foo"); +static_assert(ftl::Concat{ftl::truncated<3>("foobar")}.str() == "foo"); + +constexpr ftl::Concat kConcat{"po", "trz", "ebie"}; + +static_assert(kConcat.size() == 9); +static_assert(kConcat.max_size() == 9); +static_assert(kConcat.str() == "potrzebie"); +static_assert(kConcat.str() == std::string_view(kConcat.c_str())); + +constexpr auto concat() { + return ftl::Concat{ftl::truncated<1>("v???"), ftl::truncated<2>("ee??"), + ftl::truncated<3>("ble?"), ftl::truncated<4>("fetz"), + ftl::truncated<90>("er")}; +} + +static_assert(concat().size() == 12); +static_assert(concat().max_size() == 100); +static_assert(concat().str() == "veeblefetzer"); +static_assert(concat().str() == std::string_view(concat().c_str())); + +} // namespace +} // namespace android::test -- cgit v1.2.3-59-g8ed1b From 573da3b0f1d4381c2be5544709ad0cbec88fb982 Mon Sep 17 00:00:00 2001 From: Brian Duddie Date: Fri, 10 Dec 2021 14:34:07 -0800 Subject: Add NDK support for new head tracker sensor type Bug: 210156629 Test: presubmit (definitions only) Change-Id: Ie93f3a99a3215690ab585b2e248edf096712c8c0 --- include/android/sensor.h | 40 +++++++++++++++++++++++++++ libs/sensor/Sensor.cpp | 4 +++ services/sensorservice/SensorServiceUtils.cpp | 3 ++ 3 files changed, 47 insertions(+) (limited to 'include') diff --git a/include/android/sensor.h b/include/android/sensor.h index 9dc6983e50..45e8afc7de 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -256,6 +256,13 @@ enum { * The hinge angle sensor value is returned in degrees. */ ASENSOR_TYPE_HINGE_ANGLE = 36, + /** + * {@link ASENSOR_TYPE_HEAD_TRACKER} + * reporting-mode: continuous + * + * Measures the orientation and rotational velocity of a user's head. + */ + ASENSOR_TYPE_HEAD_TRACKER = 37, }; /** @@ -440,6 +447,38 @@ typedef struct AAdditionalInfoEvent { }; } AAdditionalInfoEvent; +typedef struct AHeadTrackerEvent { + /** + * The fields rx, ry, rz are an Euler vector (rotation vector, i.e. a vector + * whose direction indicates the axis of rotation and magnitude indicates + * the angle to rotate around that axis) representing the transform from + * the (arbitrary, possibly slowly drifting) reference frame to the + * head frame. Expressed in radians. Magnitude of the vector must be + * in the range [0, pi], while the value of individual axes are + * in the range [-pi, pi]. + */ + float rx; + float ry; + float rz; + + /** + * The fields vx, vy, vz are an Euler vector (rotation vector) representing + * the angular velocity of the head (relative to itself), in radians per + * second. The direction of this vector indicates the axis of rotation, and + * the magnitude indicates the rate of rotation. + */ + float vx; + float vy; + float vz; + + /** + * This value changes each time the reference frame is suddenly and + * significantly changed, for example if an orientation filter algorithm + * used for determining the orientation has had its state reset. + */ + int32_t discontinuity_count; +} AHeadTrackerEvent; + /** * Information that describes a sensor event, refer to * SensorEvent for additional @@ -476,6 +515,7 @@ typedef struct ASensorEvent { AHeartRateEvent heart_rate; ADynamicSensorEvent dynamic_sensor_meta; AAdditionalInfoEvent additional_info; + AHeadTrackerEvent head_tracker; }; union { uint64_t data[8]; diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp index 0a49008584..e1560c0740 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -276,6 +276,10 @@ Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersi mStringType = SENSOR_STRING_TYPE_HINGE_ANGLE; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; break; + case SENSOR_TYPE_HEAD_TRACKER: + mStringType = SENSOR_STRING_TYPE_HEAD_TRACKER; + mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; + break; default: // Only pipe the stringType, requiredPermission and flags for custom sensors. if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) { diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp index fdd56b364d..baa01c9ce3 100644 --- a/services/sensorservice/SensorServiceUtils.cpp +++ b/services/sensorservice/SensorServiceUtils.cpp @@ -58,6 +58,9 @@ size_t eventSizeBySensorType(int type) { case SENSOR_TYPE_HINGE_ANGLE: return 1; + case SENSOR_TYPE_HEAD_TRACKER: + return 7; + default: return 3; } -- cgit v1.2.3-59-g8ed1b From 2825fa2979c783b879e2fe251baf37a139607ac0 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 12 Jan 2022 17:35:16 -0800 Subject: Rename AChoreographer frame timeline methods. Test: atest ChoreographerNativeTest Bug: 214303753 Change-Id: Id7c6ddcf7e0d46fb0b6eff35e46b4f937b59a058 --- include/android/choreographer.h | 4 ++-- libs/nativedisplay/AChoreographer.cpp | 12 ++++++------ .../include-private/private/android/choreographer.h | 4 ++-- libs/nativedisplay/libnativedisplay.map.txt | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/android/choreographer.h b/include/android/choreographer.h index 0389e573a2..6f579ca0af 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -209,13 +209,13 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( /** * The time in nanoseconds which the frame at given index is expected to be presented. */ -int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( +int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos( const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); /** * The time in nanoseconds which the frame at given index needs to be ready by. */ -int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( +int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); __END_DECLS diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index fc9680babb..84daea09f0 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -556,13 +556,13 @@ int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) { return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index); } -int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime( +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos( const AChoreographerFrameCallbackData* data, size_t index) { - return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(data, index); + return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(data, index); } -int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline( +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos( const AChoreographerFrameCallbackData* data, size_t index) { - return AChoreographerFrameCallbackData_getFrameTimelineDeadline(data, index); + return AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(data, index); } int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer) { @@ -653,7 +653,7 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); return frameCallbackData->frameTimelines[index].id; } -int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( +int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos( const AChoreographerFrameCallbackData* data, size_t index) { const ChoreographerFrameCallbackDataImpl* frameCallbackData = AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); @@ -662,7 +662,7 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); return frameCallbackData->frameTimelines[index].expectedPresentTime; } -int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( +int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( const AChoreographerFrameCallbackData* data, size_t index) { const ChoreographerFrameCallbackDataImpl* frameCallbackData = AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h index 4aa7e69097..0a1fcbeb94 100644 --- a/libs/nativedisplay/include-private/private/android/choreographer.h +++ b/libs/nativedisplay/include-private/private/android/choreographer.h @@ -67,9 +67,9 @@ size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data); int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index); -int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime( +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos( const AChoreographerFrameCallbackData* data, size_t index); -int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline( +int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos( const AChoreographerFrameCallbackData* data, size_t index); } // namespace android diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt index 4dbfde83cd..b1b6498fe9 100644 --- a/libs/nativedisplay/libnativedisplay.map.txt +++ b/libs/nativedisplay/libnativedisplay.map.txt @@ -12,8 +12,8 @@ LIBNATIVEDISPLAY { AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33 AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33 AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime; # apex # introduced=33 - AChoreographerFrameCallbackData_getFrameTimelineDeadline; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos; # apex # introduced=33 + AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # apex # introduced=33 AChoreographer_create; # apex # introduced=30 AChoreographer_destroy; # apex # introduced=30 AChoreographer_getFd; # apex # introduced=30 @@ -40,8 +40,8 @@ LIBNATIVEDISPLAY_PLATFORM { android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*; android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*; android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*; - android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime*; - android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline*; + android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos*; + android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos*; android::AChoreographer_signalRefreshRateCallbacks*; android::AChoreographer_getFrameInterval*; android::ADisplay_acquirePhysicalDisplays*; -- cgit v1.2.3-59-g8ed1b From 6dbd0ce22d86e487b000d4eac75af35c1ffec58e Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 13 Jan 2022 01:24:14 -0800 Subject: Use std::vector in Input.h Convert old code from android's Vector to std::vector. Bug: 167946763 Test: atest libinput_tests Change-Id: I5c53583f6f1e5d577882d94d356f23bdd516be1e --- include/input/Input.h | 12 +++++------ libs/input/Input.cpp | 33 +++++++++++++++++-------------- services/inputflinger/InputClassifier.cpp | 2 -- services/inputflinger/InputManager.h | 1 - 4 files changed, 23 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/include/input/Input.h b/include/input/Input.h index ddff144954..f4147a0409 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -31,10 +31,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -88,7 +86,7 @@ enum { */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, -#ifdef __linux__ +#if defined(__linux__) /** * This event was generated or modified by accessibility service. */ @@ -799,11 +797,11 @@ public: // Low-level accessors. inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); + return mPointerProperties.data(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); } inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); + return mSamplePointerCoords.data(); } static const char* getLabel(int32_t axis); @@ -834,9 +832,9 @@ protected: float mRawYCursorPosition; ui::Transform mRawTransform; nsecs_t mDownTime; - Vector mPointerProperties; + std::vector mPointerProperties; std::vector mSampleEventTimes; - Vector mSamplePointerCoords; + std::vector mSamplePointerCoords; }; /* diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 84dba84e2b..3073d94dbe 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -456,7 +456,8 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mRawTransform = rawTransform; mDownTime = downTime; mPointerProperties.clear(); - mPointerProperties.appendArray(pointerProperties, pointerCount); + mPointerProperties.insert(mPointerProperties.end(), &pointerProperties[0], + &pointerProperties[pointerCount]); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); @@ -490,8 +491,10 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mSamplePointerCoords.clear(); size_t pointerCount = other->getPointerCount(); size_t historySize = other->getHistorySize(); - mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() - + (historySize * pointerCount), pointerCount); + mSamplePointerCoords + .insert(mSamplePointerCoords.end(), + &other->mSamplePointerCoords[historySize * pointerCount], + &other->mSamplePointerCoords[historySize * pointerCount + pointerCount]); } } @@ -499,7 +502,8 @@ void MotionEvent::addSample( int64_t eventTime, const PointerCoords* pointerCoords) { mSampleEventTimes.push_back(eventTime); - mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); + mSamplePointerCoords.insert(mSamplePointerCoords.end(), &pointerCoords[0], + &pointerCoords[getPointerCount()]); } int MotionEvent::getSurfaceRotation() const { @@ -569,7 +573,7 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { - if (mPointerProperties.itemAt(i).id == pointerId) { + if (mPointerProperties[i].id == pointerId) { return i; } } @@ -591,8 +595,7 @@ void MotionEvent::scale(float globalScaleFactor) { size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { - mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor, globalScaleFactor, - globalScaleFactor); + mSamplePointerCoords[i].scale(globalScaleFactor, globalScaleFactor, globalScaleFactor); } } @@ -686,15 +689,15 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mDownTime = parcel->readInt64(); mPointerProperties.clear(); - mPointerProperties.setCapacity(pointerCount); + mPointerProperties.reserve(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.reserve(sampleCount); mSamplePointerCoords.clear(); - mSamplePointerCoords.setCapacity(sampleCount * pointerCount); + mSamplePointerCoords.reserve(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { - mPointerProperties.push(); - PointerProperties& properties = mPointerProperties.editTop(); + mPointerProperties.push_back({}); + PointerProperties& properties = mPointerProperties.back(); properties.id = parcel->readInt32(); properties.toolType = parcel->readInt32(); } @@ -703,8 +706,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { sampleCount--; mSampleEventTimes.push_back(parcel->readInt64()); for (size_t i = 0; i < pointerCount; i++) { - mSamplePointerCoords.push(); - status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); + mSamplePointerCoords.push_back({}); + status_t status = mSamplePointerCoords.back().readFromParcel(parcel); if (status) { return status; } @@ -750,12 +753,12 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { - const PointerProperties& properties = mPointerProperties.itemAt(i); + const PointerProperties& properties = mPointerProperties[i]; parcel->writeInt32(properties.id); parcel->writeInt32(properties.toolType); } - const PointerCoords* pc = mSamplePointerCoords.array(); + const PointerCoords* pc = mSamplePointerCoords.data(); for (size_t h = 0; h < sampleCount; h++) { parcel->writeInt64(mSampleEventTimes[h]); for (size_t i = 0; i < pointerCount; i++) { diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 19cad7b9ad..6c4b11e0e5 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -29,8 +29,6 @@ #endif #include -#include - #define INDENT1 " " #define INDENT2 " " #define INDENT3 " " diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index a6baf2f56d..e00028364a 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -33,7 +33,6 @@ #include #include #include -#include using android::os::BnInputFlinger; -- cgit v1.2.3-59-g8ed1b From 1fb2ddcb4cfb3c848b69ae2fe27b6c1b66ae792c Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 12 Jan 2022 14:33:07 -0800 Subject: Improve ASurfaceTransaction_setFrameTimeline docs. Also use a new typedef AVsyncId shared in AChoreographer and ASurfaceControl. Test: atest ASurfaceControlTest; atest ChoreographerNativeTest Bug: 214063411 Change-Id: If24f144404038064de2ba72cca44572aca507e44 --- include/android/choreographer.h | 8 +++++++- include/android/surface_control.h | 17 ++++++++++++++--- libs/nativedisplay/AChoreographer.cpp | 4 ++-- .../include-private/private/android/choreographer.h | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/android/choreographer.h b/include/android/choreographer.h index 0389e573a2..889ecffd56 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -39,6 +39,12 @@ struct AChoreographer; */ typedef struct AChoreographer AChoreographer; + +/** + * The identifier of a frame timeline. + */ +typedef int64_t AVsyncId; + struct AChoreographerFrameCallbackData; /** * Opaque type that provides access to an AChoreographerFrameCallbackData object. @@ -203,7 +209,7 @@ size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( /** * The vsync ID token used to map Choreographer data. */ -int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( +AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); /** diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 3a131045e8..9a36ecb537 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -28,6 +28,7 @@ #include +#include #include #include #include @@ -596,13 +597,23 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, __INTRODUCED_IN(31); /** - * Sets the frame timeline to use. + * Sets the frame timeline to use in Surface Flinger. + * + * A frame timeline should be chosen based on what frame deadline the application + * can meet when rendering the frame and the application's desired present time. + * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding + * expected present time. + * + * To receive frame timelines, a callback must be posted to Choreographer using + * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the + * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId(). * * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to - * the corresponding expected present time and deadline from the frame to be rendered. + * the corresponding expected present time and deadline from the frame to be rendered. A stale or + * invalid value will be ignored. */ void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction, - int64_t vsyncId) __INTRODUCED_IN(33); + AVsyncId vsyncId) __INTRODUCED_IN(33); __END_DECLS diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index fc9680babb..17c1ccc7de 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -552,7 +552,7 @@ size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { return AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(data); } -int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( +AVsyncId AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) { return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index); } @@ -644,7 +644,7 @@ size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( "Data is only valid in callback"); return frameCallbackData->preferredFrameTimelineIndex; } -int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( +AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) { const ChoreographerFrameCallbackDataImpl* frameCallbackData = AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h index 4aa7e69097..5069e7471c 100644 --- a/libs/nativedisplay/include-private/private/android/choreographer.h +++ b/libs/nativedisplay/include-private/private/android/choreographer.h @@ -65,7 +65,7 @@ size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength( const AChoreographerFrameCallbackData* data); size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data); -int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( +AVsyncId AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index); int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime( const AChoreographerFrameCallbackData* data, size_t index); -- cgit v1.2.3-59-g8ed1b From 04667b7f2d792ee498bde06af63cc3771849a3c3 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 15 Dec 2021 13:14:54 -0800 Subject: FTL: Tidy up API Move array_traits.h to details, and rename enum_cast to its proposed C++23 counterpart. Bug: 185536303 Test: ftl_test Change-Id: I432448d388d388491066ef37db05c5b9d67550bc --- include/ftl/Flags.h | 4 +- include/ftl/array_traits.h | 135 ------------------------------------- include/ftl/details/array_traits.h | 135 +++++++++++++++++++++++++++++++++++++ include/ftl/enum.h | 30 +++++---- include/ftl/small_vector.h | 12 ++-- include/ftl/static_vector.h | 12 ++-- libs/ftl/enum_test.cpp | 2 +- 7 files changed, 166 insertions(+), 164 deletions(-) delete mode 100644 include/ftl/array_traits.h create mode 100644 include/ftl/details/array_traits.h (limited to 'include') diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h index ae708313fd..932af2d9f9 100644 --- a/include/ftl/Flags.h +++ b/include/ftl/Flags.h @@ -209,12 +209,12 @@ namespace flag_operators { template >> inline Flags operator~(F f) { - return static_cast(~ftl::enum_cast(f)); + return static_cast(~ftl::to_underlying(f)); } template >> Flags operator|(F lhs, F rhs) { - return static_cast(ftl::enum_cast(lhs) | ftl::enum_cast(rhs)); + return static_cast(ftl::to_underlying(lhs) | ftl::to_underlying(rhs)); } } // namespace flag_operators diff --git a/include/ftl/array_traits.h b/include/ftl/array_traits.h deleted file mode 100644 index 1265fa15fe..0000000000 --- a/include/ftl/array_traits.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2020 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. - */ - -#pragma once - -#include -#include -#include -#include - -#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits::U - -namespace android::ftl { - -template -struct ArrayTraits { - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - using pointer = value_type*; - using reference = value_type&; - using iterator = pointer; - using reverse_iterator = std::reverse_iterator; - - using const_pointer = const value_type*; - using const_reference = const value_type&; - using const_iterator = const_pointer; - using const_reverse_iterator = std::reverse_iterator; - - template - static pointer construct_at(const_iterator it, Args&&... args) { - void* const ptr = const_cast(static_cast(it)); - if constexpr (std::is_constructible_v) { - // TODO: Replace with std::construct_at in C++20. - return new (ptr) value_type(std::forward(args)...); - } else { - // Fall back to list initialization. - return new (ptr) value_type{std::forward(args)...}; - } - } -}; - -// CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end. -template -class ArrayIterators { - FTL_ARRAY_TRAIT(T, size_type); - - FTL_ARRAY_TRAIT(T, reference); - FTL_ARRAY_TRAIT(T, iterator); - FTL_ARRAY_TRAIT(T, reverse_iterator); - - FTL_ARRAY_TRAIT(T, const_reference); - FTL_ARRAY_TRAIT(T, const_iterator); - FTL_ARRAY_TRAIT(T, const_reverse_iterator); - - Self& self() const { return *const_cast(static_cast(this)); } - - public: - const_iterator begin() const { return cbegin(); } - const_iterator cbegin() const { return self().begin(); } - - const_iterator end() const { return cend(); } - const_iterator cend() const { return self().end(); } - - reverse_iterator rbegin() { return std::make_reverse_iterator(self().end()); } - const_reverse_iterator rbegin() const { return crbegin(); } - const_reverse_iterator crbegin() const { return self().rbegin(); } - - reverse_iterator rend() { return std::make_reverse_iterator(self().begin()); } - const_reverse_iterator rend() const { return crend(); } - const_reverse_iterator crend() const { return self().rend(); } - - iterator last() { return self().end() - 1; } - const_iterator last() const { return self().last(); } - - reference front() { return *self().begin(); } - const_reference front() const { return self().front(); } - - reference back() { return *last(); } - const_reference back() const { return self().back(); } - - reference operator[](size_type i) { return *(self().begin() + i); } - const_reference operator[](size_type i) const { return self()[i]; } -}; - -// Mixin to define comparison operators for an array-like template. -// TODO: Replace with operator<=> in C++20. -template