Merge "libs/input: make parameter comment style consistent" into udc-dev
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index a737bd3..bdd5172 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -167,12 +167,6 @@
}
prebuilt_etc {
- name: "android.hardware.telephony.satellite.prebuilt.xml",
- src: "android.hardware.telephony.satellite.xml",
- defaults: ["frameworks_native_data_etc_defaults"],
-}
-
-prebuilt_etc {
name: "android.hardware.usb.accessory.prebuilt.xml",
src: "android.hardware.usb.accessory.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.satellite.xml b/data/etc/android.hardware.telephony.satellite.xml
deleted file mode 100644
index 5966cba..0000000
--- a/data/etc/android.hardware.telephony.satellite.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 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.
--->
-
-<!-- Feature for devices that support Satellite communication via Satellite HAL APIs. -->
-<permissions>
- <feature name="android.hardware.telephony.satellite" />
-</permissions>
diff --git a/include/ftl/details/optional.h b/include/ftl/details/optional.h
index bff7c1e..e45c1f5 100644
--- a/include/ftl/details/optional.h
+++ b/include/ftl/details/optional.h
@@ -54,5 +54,15 @@
template <typename F, typename T>
using and_then_result_t = typename and_then_result<F, T>::type;
+template <typename F, typename T>
+struct or_else_result {
+ using type = remove_cvref_t<std::invoke_result_t<F>>;
+ static_assert(std::is_same_v<type, std::optional<T>> || std::is_same_v<type, Optional<T>>,
+ "or_else function must return an optional T");
+};
+
+template <typename F, typename T>
+using or_else_result_t = typename or_else_result<F, T>::type;
+
} // namespace details
} // namespace android::ftl
diff --git a/include/ftl/optional.h b/include/ftl/optional.h
index a818128..94d8e3d 100644
--- a/include/ftl/optional.h
+++ b/include/ftl/optional.h
@@ -96,13 +96,25 @@
return R();
}
+ // Returns this Optional<T> if not nullopt, or else the Optional<T> returned by the function F.
+ template <typename F>
+ constexpr auto or_else(F&& f) const& -> details::or_else_result_t<F, T> {
+ if (has_value()) return *this;
+ return std::forward<F>(f)();
+ }
+
+ template <typename F>
+ constexpr auto or_else(F&& f) && -> details::or_else_result_t<F, T> {
+ if (has_value()) return std::move(*this);
+ return std::forward<F>(f)();
+ }
+
// Delete new for this class. Its base doesn't have a virtual destructor, and
// if it got deleted via base class pointer, it would cause undefined
// behavior. There's not a good reason to allocate this object on the heap
// anyway.
static void* operator new(size_t) = delete;
static void* operator new[](size_t) = delete;
-
};
template <typename T, typename U>
diff --git a/include/input/Input.h b/include/input/Input.h
index 608519b..e8af5f7 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -855,6 +855,8 @@
const PointerCoords&);
static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&,
const PointerCoords&);
+ // The rounding precision for transformed motion events.
+ static constexpr float ROUNDING_PRECISION = 0.001f;
protected:
int32_t mAction;
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index 18ce16d..28e4816 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -18,10 +18,7 @@
#include <android-base/result.h>
#include <utils/Tokenizer.h>
-
-#include <string>
#include <unordered_map>
-#include <unordered_set>
namespace android {
@@ -60,9 +57,6 @@
*/
void addProperty(const std::string& key, const std::string& value);
- /* Returns a set of all property keys starting with the given prefix. */
- std::unordered_set<std::string> getKeysWithPrefix(const std::string& prefix) const;
-
/* Gets the value of a property and parses it.
* Returns true and sets outValue if the key was found and its value was parsed successfully.
* Otherwise returns false and does not modify outValue. (Also logs a warning.)
@@ -71,7 +65,6 @@
bool tryGetProperty(const std::string& key, bool& outValue) const;
bool tryGetProperty(const std::string& key, int32_t& outValue) const;
bool tryGetProperty(const std::string& key, float& outValue) const;
- bool tryGetProperty(const std::string& key, double& outValue) const;
/* Adds all values from the specified property map. */
void addAll(const PropertyMap* map);
diff --git a/libs/ftl/optional_test.cpp b/libs/ftl/optional_test.cpp
index 6b3b6c4..91bf7bc 100644
--- a/libs/ftl/optional_test.cpp
+++ b/libs/ftl/optional_test.cpp
@@ -164,6 +164,46 @@
}));
}
+TEST(Optional, OrElse) {
+ // Non-empty.
+ {
+ const Optional opt = false;
+ EXPECT_EQ(false, opt.or_else([] { return Optional(true); }));
+ EXPECT_EQ('x', Optional('x').or_else([] { return std::make_optional('y'); }));
+ }
+
+ // Empty.
+ {
+ const Optional<int> opt;
+ EXPECT_EQ(123, opt.or_else([]() -> Optional<int> { return 123; }));
+ EXPECT_EQ("abc"s, Optional<std::string>().or_else([] { return Optional("abc"s); }));
+ }
+ {
+ bool empty = false;
+ EXPECT_EQ(Optional<float>(), Optional<float>().or_else([&empty]() -> Optional<float> {
+ empty = true;
+ return std::nullopt;
+ }));
+ EXPECT_TRUE(empty);
+ }
+
+ // Chaining.
+ using StringVector = StaticVector<std::string, 3>;
+ EXPECT_EQ(999, Optional(StaticVector{"1"s, "0"s, "0"s})
+ .and_then([](StringVector&& v) -> Optional<StringVector> {
+ if (v.push_back("0"s)) return v;
+ return {};
+ })
+ .or_else([] {
+ return Optional(StaticVector{"9"s, "9"s, "9"s});
+ })
+ .transform([](const StringVector& v) {
+ return std::accumulate(v.begin(), v.end(), std::string());
+ })
+ .and_then(parse_int)
+ .or_else([] { return Optional(-1); }));
+}
+
// Comparison.
namespace {
diff --git a/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
index fc809c4..e8c36ee 100644
--- a/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
+++ b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl
@@ -19,7 +19,9 @@
/** @hide */
oneway interface IHdrLayerInfoListener {
// Callback with the total number of HDR layers, the dimensions of the largest layer,
- // and a placeholder flags
+ // a placeholder flags, and the max desired HDR/SDR ratio. The max desired HDR/SDR
+ // ratio may be positive infinity to indicate an unbounded ratio.
// TODO (b/182312559): Define the flags (likely need an indicator that a UDFPS layer is present)
- void onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags);
+ void onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH,
+ int flags, float maxDesiredHdrSdrRatio);
}
\ No newline at end of file
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 869458c..f38dd98 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -167,7 +167,6 @@
cc_defaults {
name: "libinput_fuzz_defaults",
- cpp_std: "c++20",
host_supported: true,
shared_libs: [
"libutils",
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 133b260..53b22cb 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -151,10 +151,23 @@
// --- InputEvent ---
+// Due to precision limitations when working with floating points, transforming - namely
+// scaling - floating points can lead to minute errors. We round transformed values to approximately
+// three decimal places so that values like 0.99997 show up as 1.0.
+inline float roundTransformedCoords(float val) {
+ // Use a power to two to approximate three decimal places to potentially reduce some cycles.
+ // This should be at least as precise as MotionEvent::ROUNDING_PRECISION.
+ return std::round(val * 1024.f) / 1024.f;
+}
+
+inline vec2 roundTransformedCoords(vec2 p) {
+ return {roundTransformedCoords(p.x), roundTransformedCoords(p.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;
+ return roundTransformedCoords(transformedXy - transformedOrigin);
}
float transformAngle(const ui::Transform& transform, float angleRadians) {
@@ -606,12 +619,12 @@
float MotionEvent::getXCursorPosition() const {
vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition());
- return vals.x;
+ return roundTransformedCoords(vals.x);
}
float MotionEvent::getYCursorPosition() const {
vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition());
- return vals.y;
+ return roundTransformedCoords(vals.y);
}
void MotionEvent::setCursorPosition(float x, float y) {
@@ -933,7 +946,7 @@
static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform,
const vec2& xy) {
return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy)
- : transform.transform(xy);
+ : roundTransformedCoords(transform.transform(xy));
}
vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform,
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index 9a4f10b..ed9ac9f 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "PropertyMap"
-#include <cstdlib>
-
#include <input/PropertyMap.h>
#include <log/log.h>
@@ -46,16 +44,6 @@
mProperties.emplace(key, value);
}
-std::unordered_set<std::string> PropertyMap::getKeysWithPrefix(const std::string& prefix) const {
- std::unordered_set<std::string> keys;
- for (const auto& [key, _] : mProperties) {
- if (key.starts_with(prefix)) {
- keys.insert(key);
- }
- }
- return keys;
-}
-
bool PropertyMap::hasProperty(const std::string& key) const {
return mProperties.find(key) != mProperties.end();
}
@@ -114,23 +102,6 @@
return true;
}
-bool PropertyMap::tryGetProperty(const std::string& key, double& outValue) const {
- std::string stringValue;
- if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- double value = strtod(stringValue.c_str(), &end);
- if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected a double.", key.c_str(),
- stringValue.c_str());
- return false;
- }
- outValue = value;
- return true;
-}
-
void PropertyMap::addAll(const PropertyMap* map) {
for (const auto& [key, value] : map->mProperties) {
mProperties.emplace(key, value);
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 7f240f0..2132dc1 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -29,6 +29,8 @@
// Default display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
+
class BaseTest : public testing::Test {
protected:
static constexpr std::array<uint8_t, 32> HMAC = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
@@ -235,102 +237,110 @@
static constexpr float RAW_X_OFFSET = 12;
static constexpr float RAW_Y_OFFSET = -41.1;
+ void SetUp() override;
+
int32_t mId;
ui::Transform mTransform;
ui::Transform mRawTransform;
+ PointerProperties mPointerProperties[2];
+ struct Sample {
+ PointerCoords pointerCoords[2];
+ };
+ std::array<Sample, 3> mSamples{};
void initializeEventWithHistory(MotionEvent* event);
void assertEqualsEventWithHistory(const MotionEvent* event);
};
-void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
+void MotionEventTest::SetUp() {
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();
- pointerProperties[0].id = 1;
- pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- pointerProperties[1].clear();
- pointerProperties[1].id = 2;
- pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mPointerProperties[0].clear();
+ mPointerProperties[0].id = 1;
+ mPointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ mPointerProperties[1].clear();
+ mPointerProperties[1].id = 2;
+ mPointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
- PointerCoords pointerCoords[2];
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
- pointerCoords[0].isResampled = true;
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
+ mSamples[0].pointerCoords[0].clear();
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
+ mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
+ mSamples[0].pointerCoords[0].isResampled = true;
+ mSamples[0].pointerCoords[1].clear();
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
+ mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
+
+ mSamples[1].pointerCoords[0].clear();
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
+ mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
+ mSamples[1].pointerCoords[0].isResampled = true;
+ mSamples[1].pointerCoords[1].clear();
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
+ mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
+ mSamples[1].pointerCoords[1].isResampled = true;
+
+ mSamples[2].pointerCoords[0].clear();
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
+ mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
+ mSamples[2].pointerCoords[1].clear();
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
+ mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
+}
+
+void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
event->initialize(mId, 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC,
AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
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,
mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2,
- pointerProperties, pointerCoords);
-
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
- pointerCoords[0].isResampled = true;
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
- pointerCoords[1].isResampled = true;
- event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords);
-
- pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
- pointerCoords[1].clear();
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
- pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
- event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords);
+ mPointerProperties, mSamples[0].pointerCoords);
+ event->addSample(ARBITRARY_EVENT_TIME + 1, mSamples[1].pointerCoords);
+ event->addSample(ARBITRARY_EVENT_TIME + 2, mSamples[2].pointerCoords);
}
void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
@@ -367,51 +377,65 @@
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));
+ // Ensure the underlying PointerCoords are identical.
+ for (int sampleIdx = 0; sampleIdx < 3; sampleIdx++) {
+ for (int pointerIdx = 0; pointerIdx < 2; pointerIdx++) {
+ ASSERT_EQ(mSamples[sampleIdx].pointerCoords[pointerIdx],
+ event->getSamplePointerCoords()[sampleIdx * 2 + pointerIdx]);
+ }
+ }
- 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_NEAR(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EPSILON);
+ ASSERT_NEAR(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y), EPSILON);
+ ASSERT_NEAR(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y), EPSILON);
- 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_NEAR(RAW_Y_OFFSET + 11 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 21 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 111 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 121 * RAW_Y_SCALE,
+ event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0),
+ EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1),
+ EPSILON);
- 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_NEAR(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0), EPSILON);
+ ASSERT_NEAR(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1), EPSILON);
- ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0));
- ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0));
- ASSERT_EQ(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1));
- ASSERT_EQ(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1));
- ASSERT_EQ(X_OFFSET + 210 * X_SCALE, event->getX(0));
- ASSERT_EQ(X_OFFSET + 220 * X_SCALE, event->getX(1));
+ ASSERT_NEAR(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0), EPSILON);
+ ASSERT_NEAR(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1), EPSILON);
- ASSERT_EQ(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0));
- ASSERT_EQ(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0));
- ASSERT_EQ(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1));
- ASSERT_EQ(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1));
- ASSERT_EQ(Y_OFFSET + 211 * Y_SCALE, event->getY(0));
- ASSERT_EQ(Y_OFFSET + 221 * Y_SCALE, event->getY(1));
+ ASSERT_NEAR(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 210 * X_SCALE, event->getX(0), EPSILON);
+ ASSERT_NEAR(X_OFFSET + 220 * X_SCALE, event->getX(1), EPSILON);
+
+ ASSERT_NEAR(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 211 * Y_SCALE, event->getY(0), EPSILON);
+ ASSERT_NEAR(Y_OFFSET + 221 * Y_SCALE, event->getY(1), EPSILON);
ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
@@ -550,10 +574,10 @@
ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
- 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_NEAR((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0), EPSILON);
+ ASSERT_NEAR((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0), EPSILON);
+ ASSERT_NEAR((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0), EPSILON);
+ ASSERT_NEAR((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0), EPSILON);
ASSERT_EQ(212, event.getPressure(0));
ASSERT_EQ(213, event.getSize(0));
ASSERT_EQ(214 * 2, event.getTouchMajor(0));
@@ -791,18 +815,18 @@
// 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));
+ ASSERT_NEAR(newPoint.x, event.getX(0), EPSILON);
+ ASSERT_NEAR(newPoint.y, event.getY(0), EPSILON);
// 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));
+ ASSERT_NEAR(raw.x, event.getRawX(0), EPSILON);
+ ASSERT_NEAR(raw.y, event.getRawY(0), EPSILON);
// 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));
+ ASSERT_NEAR(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), EPSILON);
+ ASSERT_NEAR(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), EPSILON);
}
TEST_F(MotionEventTest, Initialize_SetsClassification) {
@@ -869,4 +893,42 @@
ASSERT_EQ(4, event.getYCursorPosition());
}
+TEST_F(MotionEventTest, CoordinatesAreRoundedAppropriately) {
+ // These are specifically integral values, since we are testing for rounding.
+ const vec2 EXPECTED{400.f, 700.f};
+
+ // Pick a transform such that transforming the point with its inverse and bringing that
+ // back to the original coordinate space results in a non-zero error amount due to the
+ // nature of floating point arithmetics. This can happen when the display is scaled.
+ // For example, the 'adb shell wm size' command can be used to set an override for the
+ // logical display size, which could result in the display being scaled.
+ constexpr float scale = 720.f / 1080.f;
+ ui::Transform transform;
+ transform.set(scale, 0, 0, scale);
+ ASSERT_NE(EXPECTED, transform.transform(transform.inverse().transform(EXPECTED)));
+
+ // Store the inverse-transformed values in the motion event.
+ const vec2 rawCoords = transform.inverse().transform(EXPECTED);
+ PointerCoords pc{};
+ pc.setAxisValue(AMOTION_EVENT_AXIS_X, rawCoords.x);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_Y, rawCoords.y);
+ PointerProperties pp{};
+ MotionEvent event;
+ event.initialize(InputEvent::nextId(), 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC,
+ AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
+ AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
+ MotionClassification::NONE, transform, 2.0f, 2.1f, rawCoords.x, rawCoords.y,
+ transform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 1, &pp, &pc);
+
+ // When using the getters from the MotionEvent to obtain the coordinates, the transformed
+ // values should be rounded by an appropriate amount so that they now precisely equal the
+ // original coordinates.
+ ASSERT_EQ(EXPECTED.x, event.getX(0));
+ ASSERT_EQ(EXPECTED.y, event.getY(0));
+ ASSERT_EQ(EXPECTED.x, event.getRawX(0));
+ ASSERT_EQ(EXPECTED.y, event.getRawY(0));
+ ASSERT_EQ(EXPECTED.x, event.getXCursorPosition());
+ ASSERT_EQ(EXPECTED.y, event.getYCursorPosition());
+}
+
} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 75a01a1..5d8b970 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -25,6 +25,8 @@
namespace android {
+constexpr static float EPSILON = MotionEvent::ROUNDING_PRECISION;
+
class InputPublisherAndConsumerTest : public testing::Test {
protected:
std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
@@ -226,10 +228,10 @@
EXPECT_EQ(yOffset, motionEvent->getYOffset());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
- EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition());
- EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
- EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
- EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
+ EXPECT_NEAR(xCursorPosition, motionEvent->getRawXCursorPosition(), EPSILON);
+ EXPECT_NEAR(yCursorPosition, motionEvent->getRawYCursorPosition(), EPSILON);
+ EXPECT_NEAR(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition(), EPSILON);
+ EXPECT_NEAR(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition(), EPSILON);
EXPECT_EQ(rawTransform, motionEvent->getRawTransform());
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(eventTime, motionEvent->getEventTime());
@@ -242,10 +244,12 @@
EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(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, motionEvent->getSamplePointerCoords()[i]);
+
+ EXPECT_NEAR(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i), EPSILON);
+ EXPECT_NEAR(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i), EPSILON);
+ EXPECT_NEAR(pc.getX() * xScale + xOffset, motionEvent->getX(i), EPSILON);
+ EXPECT_NEAR(pc.getY() * yScale + yOffset, motionEvent->getY(i), EPSILON);
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));
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
index a433e8a..9b2dde7 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
@@ -206,12 +206,14 @@
* @param output_format flag for setting output color format. if set to
* {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image
* which is SDR. Default value is JPEGR_OUTPUT_HDR_LINEAR.
+ * @param recovery_map destination of the decoded recovery map.
* @return NO_ERROR if decoding succeeds, error code if error occurs.
*/
status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
jr_exif_ptr exif = nullptr,
- jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR);
+ jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR,
+ jr_uncompressed_ptr recovery_map = nullptr);
/*
* Gets Info from JPEGR file without decoding it.
diff --git a/libs/jpegrecoverymap/jpegr.cpp b/libs/jpegrecoverymap/jpegr.cpp
index b115750..f8763c6 100644
--- a/libs/jpegrecoverymap/jpegr.cpp
+++ b/libs/jpegrecoverymap/jpegr.cpp
@@ -331,7 +331,8 @@
status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
jr_exif_ptr exif,
- jpegr_output_format output_format) {
+ jpegr_output_format output_format,
+ jr_uncompressed_ptr recovery_map) {
if (compressed_jpegr_image == nullptr || dest == nullptr) {
return ERROR_JPEGR_INVALID_NULL_PTR;
}
@@ -350,13 +351,46 @@
uncompressed_rgba_image.width * uncompressed_rgba_image.height * 4);
dest->width = uncompressed_rgba_image.width;
dest->height = uncompressed_rgba_image.height;
- return NO_ERROR;
+
+ if (recovery_map == nullptr && exif == nullptr) {
+ return NO_ERROR;
+ }
+
+ if (exif != nullptr) {
+ if (exif->data == nullptr) {
+ return ERROR_JPEGR_INVALID_NULL_PTR;
+ }
+ if (exif->length < jpeg_decoder.getEXIFSize()) {
+ return ERROR_JPEGR_BUFFER_TOO_SMALL;
+ }
+ memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize());
+ exif->length = jpeg_decoder.getEXIFSize();
+ }
+ if (recovery_map == nullptr) {
+ return NO_ERROR;
+ }
}
jpegr_compressed_struct compressed_map;
- jpegr_metadata metadata;
JPEGR_CHECK(extractRecoveryMap(compressed_jpegr_image, &compressed_map));
+ JpegDecoderHelper recovery_map_decoder;
+ if (!recovery_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
+
+ if (recovery_map != nullptr) {
+ recovery_map->width = recovery_map_decoder.getDecompressedImageWidth();
+ recovery_map->height = recovery_map_decoder.getDecompressedImageHeight();
+ int size = recovery_map->width * recovery_map->height;
+ recovery_map->data = malloc(size);
+ memcpy(recovery_map->data, recovery_map_decoder.getDecompressedImagePtr(), size);
+ }
+
+ if (output_format == JPEGR_OUTPUT_SDR) {
+ return NO_ERROR;
+ }
+
JpegDecoderHelper jpeg_decoder;
if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) {
return ERROR_JPEGR_DECODE_ERROR;
@@ -373,11 +407,6 @@
exif->length = jpeg_decoder.getEXIFSize();
}
- JpegDecoderHelper recovery_map_decoder;
- if (!recovery_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
-
jpegr_uncompressed_struct map;
map.data = recovery_map_decoder.getDecompressedImagePtr();
map.width = recovery_map_decoder.getDecompressedImageWidth();
@@ -388,6 +417,7 @@
uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
+ jpegr_metadata metadata;
if (!getMetadataFromXMP(static_cast<uint8_t*>(recovery_map_decoder.getXMPPtr()),
recovery_map_decoder.getXMPSize(), &metadata)) {
return ERROR_JPEGR_DECODE_ERROR;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 78cdd0d..cd427f0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -110,6 +110,8 @@
constexpr int LOGTAG_INPUT_FOCUS = 62001;
constexpr int LOGTAG_INPUT_CANCEL = 62003;
+const ui::Transform kIdentityTransform;
+
inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
@@ -475,8 +477,8 @@
}
// Returns true if the given window can accept pointer events at the given display location.
-bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
- bool isStylus) {
+bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, float x, float y,
+ bool isStylus, const ui::Transform& displayTransform) {
const auto inputConfig = windowInfo.inputConfig;
if (windowInfo.displayId != displayId ||
inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
@@ -486,7 +488,17 @@
if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
return false;
}
- if (!windowInfo.touchableRegionContainsPoint(x, y)) {
+
+ // Window Manager works in the logical display coordinate space. When it specifies bounds for a
+ // window as (l, t, r, b), the range of x in [l, r) and y in [t, b) are considered to be inside
+ // the window. Points on the right and bottom edges should not be inside the window, so we need
+ // to be careful about performing a hit test when the display is rotated, since the "right" and
+ // "bottom" of the window will be different in the display (un-rotated) space compared to in the
+ // logical display in which WM determined the bounds. Perform the hit test in the logical
+ // display space to ensure these edges are considered correctly in all orientations.
+ const auto touchableRegion = displayTransform.transform(windowInfo.touchableRegion);
+ const auto p = displayTransform.transform(x, y);
+ if (!touchableRegion.contains(std::floor(p.x), std::floor(p.y))) {
return false;
}
return true;
@@ -540,19 +552,16 @@
return {};
}
-Point resolveTouchedPosition(const MotionEntry& entry) {
+std::pair<float, float> resolveTouchedPosition(const MotionEntry& entry) {
const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
// Always dispatch mouse events to cursor position.
if (isFromMouse) {
- return Point(static_cast<int32_t>(entry.xCursorPosition),
- static_cast<int32_t>(entry.yCursorPosition));
+ return {entry.xCursorPosition, entry.yCursorPosition};
}
const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action);
- return Point(static_cast<int32_t>(
- entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)),
- static_cast<int32_t>(
- entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)));
+ return {entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X),
+ entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)};
}
std::optional<nsecs_t> getDownTime(const EventEntry& eventEntry) {
@@ -1159,7 +1168,7 @@
}
std::pair<sp<WindowInfoHandle>, std::vector<InputTarget>>
-InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, bool isStylus,
+InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus,
bool ignoreDragWindow) const {
// Traverse windows from front to back to find touched window.
std::vector<InputTarget> outsideTargets;
@@ -1170,7 +1179,8 @@
}
const WindowInfo& info = *windowHandle->getInfo();
- if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
+ if (!info.isSpy() &&
+ windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
return {windowHandle, outsideTargets};
}
@@ -1184,14 +1194,14 @@
}
std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(
- int32_t displayId, int32_t x, int32_t y, bool isStylus) const {
+ int32_t displayId, float x, float y, bool isStylus) const {
// Traverse windows from front to back and gather the touched spy windows.
std::vector<sp<WindowInfoHandle>> spyWindows;
const auto& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo& info = *windowHandle->getInfo();
- if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
+ if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
continue;
}
if (!info.isSpy()) {
@@ -2231,8 +2241,7 @@
}
// Handle the case where we did not find a window.
if (newTouchedWindowHandle == nullptr) {
- ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,
- displayId);
+ ALOGD("No new touched window at (%.1f, %.1f) in display %" PRId32, x, y, displayId);
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
@@ -2270,7 +2279,8 @@
}
if (newTouchedWindows.empty()) {
- ALOGI("Dropping event because there is no touchable window at (%d, %d) on display %d.",
+ ALOGI("Dropping event because there is no touchable window at (%.1f, %.1f) on display "
+ "%d.",
x, y, displayId);
outInjectionResult = InputEventInjectionResult::FAILED;
return {};
@@ -4764,6 +4774,12 @@
return getWindowHandleLocked(focusedToken, displayId);
}
+ui::Transform InputDispatcher::getTransformLocked(int32_t displayId) const {
+ auto displayInfoIt = mDisplayInfos.find(displayId);
+ return displayInfoIt != mDisplayInfos.end() ? displayInfoIt->second.transform
+ : kIdentityTransform;
+}
+
bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& window,
const MotionEntry& motionEntry) const {
const WindowInfo& info = *window->getInfo();
@@ -4801,7 +4817,7 @@
TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(window, x, y);
if (!isTouchTrustedLocked(occlusionInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
- ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+ ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x, y);
for (const auto& log : occlusionInfo.debugInfo) {
ALOGD("%s", log.c_str());
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index b94858b..2246d47 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -239,11 +239,11 @@
std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
std::pair<sp<android::gui::WindowInfoHandle>, std::vector<InputTarget>>
- findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, bool isStylus = false,
+ findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus = false,
bool ignoreDragWindow = false) const REQUIRES(mLock);
std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(
- int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock);
+ int32_t displayId, float x, float y, bool isStylus) const REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> findTouchedForegroundWindowLocked(int32_t displayId) const
REQUIRES(mLock);
@@ -374,6 +374,7 @@
int32_t displayId) const REQUIRES(mLock);
sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
const sp<IBinder>& windowHandleToken) const REQUIRES(mLock);
+ ui::Transform getTransformLocked(int32_t displayId) const REQUIRES(mLock);
// Same function as above, but faster. Since displayId is provided, this avoids the need
// to loop through all displays.
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index f797bc9..3d60bfd 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -218,7 +218,7 @@
transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
int32_t reportingMode = 0;
- if (!tryGetProperty(prefix + ".reportingMode", reportingMode)) {
+ if (tryGetProperty(prefix + ".reportingMode", reportingMode)) {
sensorInfo.flags |= (reportingMode & REPORTING_MODE_MASK) << REPORTING_MODE_SHIFT;
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b53fc73..96c163d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -805,40 +805,39 @@
};
}
- // Compute oriented precision, scales and ranges.
- // Note that the maximum value reported is an inclusive maximum value so it is one
- // unit less than the total width or height of the display.
- // TODO(b/20508709): Calculate the oriented ranges using the input device's raw frame.
- switch (mInputDeviceOrientation) {
- case ui::ROTATION_90:
- case ui::ROTATION_270:
- mOrientedRanges.x.min = 0;
- mOrientedRanges.x.max = mDisplayBounds.height - 1;
- mOrientedRanges.x.flat = 0;
- mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mRawToDisplay.getScaleY();
+ // Oriented X/Y range (in the rotated display's orientation)
+ const FloatRect rawFrame = Rect{mRawPointerAxes.x.minValue, mRawPointerAxes.y.minValue,
+ mRawPointerAxes.x.maxValue, mRawPointerAxes.y.maxValue}
+ .toFloatRect();
+ const auto orientedRangeRect = mRawToRotatedDisplay.transform(rawFrame);
+ mOrientedRanges.x.min = orientedRangeRect.left;
+ mOrientedRanges.y.min = orientedRangeRect.top;
+ mOrientedRanges.x.max = orientedRangeRect.right;
+ mOrientedRanges.y.max = orientedRangeRect.bottom;
- mOrientedRanges.y.min = 0;
- mOrientedRanges.y.max = mDisplayBounds.width - 1;
- mOrientedRanges.y.flat = 0;
- mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mRawToDisplay.getScaleX();
- break;
+ // Oriented flat (in the rotated display's orientation)
+ const auto orientedFlat =
+ transformWithoutTranslation(mRawToRotatedDisplay,
+ {static_cast<float>(mRawPointerAxes.x.flat),
+ static_cast<float>(mRawPointerAxes.y.flat)});
+ mOrientedRanges.x.flat = std::abs(orientedFlat.x);
+ mOrientedRanges.y.flat = std::abs(orientedFlat.y);
- default:
- mOrientedRanges.x.min = 0;
- mOrientedRanges.x.max = mDisplayBounds.width - 1;
- mOrientedRanges.x.flat = 0;
- mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mRawToDisplay.getScaleX();
+ // Oriented fuzz (in the rotated display's orientation)
+ const auto orientedFuzz =
+ transformWithoutTranslation(mRawToRotatedDisplay,
+ {static_cast<float>(mRawPointerAxes.x.fuzz),
+ static_cast<float>(mRawPointerAxes.y.fuzz)});
+ mOrientedRanges.x.fuzz = std::abs(orientedFuzz.x);
+ mOrientedRanges.y.fuzz = std::abs(orientedFuzz.y);
- mOrientedRanges.y.min = 0;
- mOrientedRanges.y.max = mDisplayBounds.height - 1;
- mOrientedRanges.y.flat = 0;
- mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mRawToDisplay.getScaleY();
- break;
- }
+ // Oriented resolution (in the rotated display's orientation)
+ const auto orientedRes =
+ transformWithoutTranslation(mRawToRotatedDisplay,
+ {static_cast<float>(mRawPointerAxes.x.resolution),
+ static_cast<float>(mRawPointerAxes.y.resolution)});
+ mOrientedRanges.x.resolution = std::abs(orientedRes.x);
+ mOrientedRanges.y.resolution = std::abs(orientedRes.y);
}
void TouchInputMapper::computeInputTransforms() {
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 3309767..d3af402 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -20,7 +20,6 @@
#include <optional>
#include <android/input.h>
-#include <ftl/enum.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
@@ -217,11 +216,6 @@
std::list<NotifyArgs> TouchpadInputMapper::configure(nsecs_t when,
const InputReaderConfiguration* config,
uint32_t changes) {
- if (!changes) {
- // First time configuration
- mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration());
- }
-
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
std::optional<int32_t> displayId = mPointerController->getDisplayId();
ui::Rotation orientation = ui::ROTATION_0;
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
index 3d88338..089f45a 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp
@@ -84,29 +84,6 @@
return dump;
}
-void PropertyProvider::loadPropertiesFromIdcFile(const PropertyMap& idcProperties) {
- // For compatibility with the configuration file syntax, gesture property names in IDC files are
- // prefixed with "gestureProp." and have spaces replaced by underscores. So, for example, the
- // configuration key "gestureProp.Palm_Width" refers to the "Palm Width" property.
- const std::string gesturePropPrefix = "gestureProp.";
- for (const std::string key : idcProperties.getKeysWithPrefix(gesturePropPrefix)) {
- std::string propertyName = key.substr(gesturePropPrefix.length());
- for (size_t i = 0; i < propertyName.length(); i++) {
- if (propertyName[i] == '_') {
- propertyName[i] = ' ';
- }
- }
-
- auto it = mProperties.find(propertyName);
- if (it != mProperties.end()) {
- it->second.trySetFromIdcProperty(idcProperties, key);
- } else {
- ALOGE("Gesture property \"%s\" specified in IDC file does not exist for this device.",
- propertyName.c_str());
- }
- }
-}
-
GesturesProp* PropertyProvider::createIntArrayProperty(const std::string& name, int* loc,
size_t count, const int* init) {
const auto [it, inserted] =
@@ -234,59 +211,6 @@
setValues(std::get<double*>(mDataPointer), values);
}
-namespace {
-
-// Helper to std::visit with lambdas.
-template <typename... V>
-struct Visitor : V... {};
-// explicit deduction guide (not needed as of C++20)
-template <typename... V>
-Visitor(V...) -> Visitor<V...>;
-
-} // namespace
-
-void GesturesProp::trySetFromIdcProperty(const android::PropertyMap& idcProperties,
- const std::string& propertyName) {
- if (mCount != 1) {
- ALOGE("Gesture property \"%s\" is an array, and so cannot be set in an IDC file.",
- mName.c_str());
- return;
- }
- bool parsedSuccessfully = false;
- Visitor setVisitor{
- [&](int*) {
- int32_t value;
- parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
- if (parsedSuccessfully) {
- setIntValues({value});
- }
- },
- [&](GesturesPropBool*) {
- bool value;
- parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
- if (parsedSuccessfully) {
- setBoolValues({value});
- }
- },
- [&](double*) {
- double value;
- parsedSuccessfully = idcProperties.tryGetProperty(propertyName, value);
- if (parsedSuccessfully) {
- setRealValues({value});
- }
- },
- [&](const char**) {
- ALOGE("Gesture property \"%s\" is a string, and so cannot be set in an IDC file.",
- mName.c_str());
- },
- };
- std::visit(setVisitor, mDataPointer);
-
- ALOGE_IF(!parsedSuccessfully, "Gesture property \"%s\" could set due to a type mismatch.",
- mName.c_str());
- return;
-}
-
template <typename T, typename U>
const std::vector<T> GesturesProp::getValues(U* dataPointer) const {
if (mGetter != nullptr) {
diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
index c7e0858..50451a3 100644
--- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
+++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.h
@@ -22,7 +22,6 @@
#include <vector>
#include "include/gestures.h"
-#include "input/PropertyMap.h"
namespace android {
@@ -36,8 +35,6 @@
GesturesProp& getProperty(const std::string& name);
std::string dump() const;
- void loadPropertiesFromIdcFile(const PropertyMap& idcProperties);
-
// Methods to be called by the gestures library:
GesturesProp* createIntArrayProperty(const std::string& name, int* loc, size_t count,
const int* init);
@@ -86,9 +83,6 @@
// Setting string values isn't supported since we don't have a use case yet and the memory
// management adds additional complexity.
- void trySetFromIdcProperty(const android::PropertyMap& idcProperties,
- const std::string& propertyName);
-
private:
// Two type parameters are required for these methods, rather than one, due to the gestures
// library using its own bool type.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e4ba241..e299643 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -230,10 +230,10 @@
const auto& motionEvent = static_cast<const MotionEvent&>(event);
EXPECT_EQ(motionEvent.getEventTime(), args.eventTime);
EXPECT_EQ(motionEvent.getAction(), args.action);
- EXPECT_EQ(motionEvent.getX(0), point.x);
- EXPECT_EQ(motionEvent.getY(0), point.y);
- EXPECT_EQ(motionEvent.getRawX(0), point.x);
- EXPECT_EQ(motionEvent.getRawY(0), point.y);
+ EXPECT_NEAR(motionEvent.getX(0), point.x, MotionEvent::ROUNDING_PRECISION);
+ EXPECT_NEAR(motionEvent.getY(0), point.y, MotionEvent::ROUNDING_PRECISION);
+ EXPECT_NEAR(motionEvent.getRawX(0), point.x, MotionEvent::ROUNDING_PRECISION);
+ EXPECT_NEAR(motionEvent.getRawY(0), point.y, MotionEvent::ROUNDING_PRECISION);
});
}
@@ -3938,8 +3938,7 @@
public:
void SetUp() override {
InputDispatcherTest::SetUp();
- mDisplayInfos.clear();
- mWindowInfos.clear();
+ removeAllWindowsAndDisplays();
}
void addDisplayInfo(int displayId, const ui::Transform& transform) {
@@ -3955,6 +3954,11 @@
mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
}
+ void removeAllWindowsAndDisplays() {
+ mDisplayInfos.clear();
+ mWindowInfos.clear();
+ }
+
// Set up a test scenario where the display has a scaled projection and there are two windows
// on the display.
std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
@@ -3987,11 +3991,11 @@
std::vector<gui::WindowInfo> mWindowInfos;
};
-TEST_F(InputDispatcherDisplayProjectionTest, HitTestsInDisplaySpace) {
+TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
// Send down to the first window. The point is represented in the display space. The point is
- // selected so that if the hit test was done with the transform applied to it, then it would
- // end up in the incorrect window.
+ // selected so that if the hit test was performed with the point and the bounds being in
+ // different coordinate spaces, the event would end up in the incorrect window.
NotifyMotionArgs downMotionArgs =
generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
ADISPLAY_ID_DEFAULT, {PointF{75, 55}});
@@ -4066,6 +4070,81 @@
EXPECT_EQ(80, event->getY(0));
}
+/** Ensure consistent behavior of InputDispatcher in all orientations. */
+class InputDispatcherDisplayOrientationFixture
+ : public InputDispatcherDisplayProjectionTest,
+ public ::testing::WithParamInterface<ui::Rotation> {};
+
+// This test verifies the touchable region of a window for all rotations of the display by tapping
+// in different locations on the display, specifically points close to the four corners of a
+// window.
+TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
+ constexpr static int32_t displayWidth = 400;
+ constexpr static int32_t displayHeight = 800;
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ const auto rotation = GetParam();
+
+ // Set up the display with the specified rotation.
+ const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
+ const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
+ const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
+ const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
+ logicalDisplayWidth, logicalDisplayHeight);
+ addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
+
+ // Create a window with its bounds determined in the logical display.
+ const Rect frameInLogicalDisplay(100, 100, 200, 300);
+ const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(frameInDisplay, displayTransform);
+ addWindow(window);
+
+ // The following points in logical display space should be inside the window.
+ static const std::array<vec2, 4> insidePoints{
+ {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
+ for (const auto pointInsideWindow : insidePoints) {
+ const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
+ const PointF pointInDisplaySpace{p.x, p.y};
+ const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&down);
+ window->consumeMotionDown();
+
+ const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&up);
+ window->consumeMotionUp();
+ }
+
+ // The following points in logical display space should be outside the window.
+ static const std::array<vec2, 5> outsidePoints{
+ {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
+ for (const auto pointOutsideWindow : outsidePoints) {
+ const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
+ const PointF pointInDisplaySpace{p.x, p.y};
+ const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&down);
+
+ const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
+ mDispatcher->notifyMotion(&up);
+ }
+ window->assertNoEvents();
+}
+
+// Run the precision tests for all rotations.
+INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
+ InputDispatcherDisplayOrientationFixture,
+ ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
+ ui::ROTATION_270),
+ [](const testing::TestParamInfo<ui::Rotation>& testParamInfo) {
+ return ftl::enum_string(testParamInfo.param);
+ });
+
using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder>, sp<IBinder>)>;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9732e8d..711cfbf 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6927,9 +6927,11 @@
// four times the resolution of the display in the Y axis.
prepareButtons();
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, PRECISION_RAW_X_MIN, PRECISION_RAW_X_MAX,
- 0, 0);
+ PRECISION_RAW_X_FLAT, PRECISION_RAW_X_FUZZ,
+ PRECISION_RAW_X_RES);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, PRECISION_RAW_Y_MIN, PRECISION_RAW_Y_MAX,
- 0, 0);
+ PRECISION_RAW_Y_FLAT, PRECISION_RAW_Y_FUZZ,
+ PRECISION_RAW_Y_RES);
}
static const int32_t PRECISION_RAW_X_MIN = TouchInputMapperTest::RAW_X_MIN;
@@ -6937,6 +6939,15 @@
static const int32_t PRECISION_RAW_Y_MIN = TouchInputMapperTest::RAW_Y_MIN;
static const int32_t PRECISION_RAW_Y_MAX = PRECISION_RAW_Y_MIN + DISPLAY_HEIGHT * 4 - 1;
+ static const int32_t PRECISION_RAW_X_RES = 50; // units per millimeter
+ static const int32_t PRECISION_RAW_Y_RES = 100; // units per millimeter
+
+ static const int32_t PRECISION_RAW_X_FLAT = 16;
+ static const int32_t PRECISION_RAW_Y_FLAT = 32;
+
+ static const int32_t PRECISION_RAW_X_FUZZ = 4;
+ static const int32_t PRECISION_RAW_Y_FUZZ = 8;
+
static const std::array<Point, 4> kRawCorners;
};
@@ -7094,6 +7105,41 @@
}
}
+TEST_P(TouchscreenPrecisionTestsFixture, MotionRangesAreOrientedInRotatedDisplay) {
+ const ui::Rotation displayRotation = GetParam();
+
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(displayRotation);
+
+ __attribute__((unused)) SingleTouchInputMapper& mapper =
+ addMapperAndConfigure<SingleTouchInputMapper>();
+
+ const InputDeviceInfo deviceInfo = mDevice->getDeviceInfo();
+ // MotionRanges use display pixels as their units
+ const auto* xRange = deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN);
+ const auto* yRange = deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN);
+
+ // The MotionRanges should be oriented in the rotated display's coordinate space
+ const bool displayRotated =
+ displayRotation == ui::ROTATION_90 || displayRotation == ui::ROTATION_270;
+
+ constexpr float MAX_X = 479.5;
+ constexpr float MAX_Y = 799.75;
+ EXPECT_EQ(xRange->min, 0.f);
+ EXPECT_EQ(yRange->min, 0.f);
+ EXPECT_EQ(xRange->max, displayRotated ? MAX_Y : MAX_X);
+ EXPECT_EQ(yRange->max, displayRotated ? MAX_X : MAX_Y);
+
+ EXPECT_EQ(xRange->flat, 8.f);
+ EXPECT_EQ(yRange->flat, 8.f);
+
+ EXPECT_EQ(xRange->fuzz, 2.f);
+ EXPECT_EQ(yRange->fuzz, 2.f);
+
+ EXPECT_EQ(xRange->resolution, 25.f); // pixels per millimeter
+ EXPECT_EQ(yRange->resolution, 25.f); // pixels per millimeter
+}
+
// Run the precision tests for all rotations.
INSTANTIATE_TEST_SUITE_P(TouchscreenPrecisionTests, TouchscreenPrecisionTestsFixture,
::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
diff --git a/services/inputflinger/tests/PropertyProvider_test.cpp b/services/inputflinger/tests/PropertyProvider_test.cpp
index 8a40e78..42a6a9f 100644
--- a/services/inputflinger/tests/PropertyProvider_test.cpp
+++ b/services/inputflinger/tests/PropertyProvider_test.cpp
@@ -18,7 +18,6 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "TestConstants.h"
#include "include/gestures.h"
namespace android {
@@ -284,68 +283,4 @@
EXPECT_FALSE(mProvider.hasProperty("Foo"));
}
-class PropertyProviderIdcLoadingTest : public testing::Test {
-protected:
- void SetUp() override {
- int initialInt = 0;
- GesturesPropBool initialBool = false;
- double initialReal = 0.0;
- gesturePropProvider.create_int_fn(&mProvider, "An Integer", &mIntData, 1, &initialInt);
- gesturePropProvider.create_bool_fn(&mProvider, "A Boolean", &mBoolData, 1, &initialBool);
- gesturePropProvider.create_real_fn(&mProvider, "A Real", &mRealData, 1, &initialReal);
- }
-
- PropertyProvider mProvider;
-
- int mIntData;
- GesturesPropBool mBoolData;
- double mRealData;
-};
-
-TEST_F(PropertyProviderIdcLoadingTest, AllCorrect) {
- PropertyMap idcProps;
- idcProps.addProperty("gestureProp.An_Integer", "42");
- idcProps.addProperty("gestureProp.A_Boolean", "1");
- idcProps.addProperty("gestureProp.A_Real", "3.14159");
-
- mProvider.loadPropertiesFromIdcFile(idcProps);
- EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(42));
- EXPECT_THAT(mProvider.getProperty("A Boolean").getBoolValues(), ElementsAre(true));
- EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
-}
-
-TEST_F(PropertyProviderIdcLoadingTest, InvalidPropsIgnored) {
- int intArrayData[2];
- int initialInts[2] = {0, 1};
- gesturePropProvider.create_int_fn(&mProvider, "Two Integers", intArrayData, 2, initialInts);
-
- PropertyMap idcProps;
- // Wrong type
- idcProps.addProperty("gestureProp.An_Integer", "37.25");
- // Wrong size
- idcProps.addProperty("gestureProp.Two_Integers", "42");
- // Doesn't exist
- idcProps.addProperty("gestureProp.Some_Nonexistent_Property", "1");
- // A valid assignment that should still be applied despite the others being invalid
- idcProps.addProperty("gestureProp.A_Real", "3.14159");
-
- mProvider.loadPropertiesFromIdcFile(idcProps);
- EXPECT_THAT(mProvider.getProperty("An Integer").getIntValues(), ElementsAre(0));
- EXPECT_THAT(mProvider.getProperty("Two Integers").getIntValues(), ElementsAre(0, 1));
- EXPECT_FALSE(mProvider.hasProperty("Some Nonexistent Property"));
- EXPECT_NEAR(mProvider.getProperty("A Real").getRealValues()[0], 3.14159, EPSILON);
-}
-
-TEST_F(PropertyProviderIdcLoadingTest, FunkyName) {
- int data;
- int initialData = 0;
- gesturePropProvider.create_int_fn(&mProvider, " I lOvE sNAKes ", &data, 1, &initialData);
-
- PropertyMap idcProps;
- idcProps.addProperty("gestureProp.__I_lOvE_sNAKes_", "42");
-
- mProvider.loadPropertiesFromIdcFile(idcProps);
- EXPECT_THAT(mProvider.getProperty(" I lOvE sNAKes ").getIntValues(), ElementsAre(42));
-}
-
} // namespace android
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index ad48b0f..27881f6 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -16,10 +16,6 @@
#pragma once
-#include <chrono>
-
-#include <utils/Timers.h>
-
namespace android {
using std::chrono_literals::operator""ms;
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
index 6659825..5efa394 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
@@ -65,6 +65,10 @@
}
}
+LayerCreationArgs::LayerCreationArgs(std::optional<uint32_t> id, bool internalLayer)
+ : LayerCreationArgs(nullptr, nullptr, /*name=*/"", /*flags=*/0, /*metadata=*/{}, id,
+ internalLayer) {}
+
LayerCreationArgs::LayerCreationArgs(const LayerCreationArgs& args)
: LayerCreationArgs(args.flinger, args.client, args.name, args.flags, args.metadata) {}
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
index 2cd6b55..8341e1d 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
@@ -41,6 +41,8 @@
LayerCreationArgs(android::SurfaceFlinger*, sp<android::Client>, std::string name,
uint32_t flags, gui::LayerMetadata, std::optional<uint32_t> id = std::nullopt,
bool internalLayer = false);
+ LayerCreationArgs(std::optional<uint32_t> id, bool internalLayer = false);
+
LayerCreationArgs(const LayerCreationArgs&);
android::SurfaceFlinger* flinger;
@@ -56,6 +58,8 @@
wp<IBinder> parentHandle = nullptr;
wp<IBinder> mirrorLayerHandle = nullptr;
ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t parentId = UNASSIGNED_LAYER_ID;
+ uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 33cc429..fe42422 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -20,8 +20,7 @@
#define LOG_TAG "LayerLifecycleManager"
#include "LayerLifecycleManager.h"
-#include "Layer.h" // temporarily needed for LayerHandle
-#include "LayerHandle.h"
+#include "Client.h" // temporarily needed for LayerCreationArgs
#include "LayerLog.h"
#include "SwapErase.h"
@@ -167,7 +166,7 @@
for (const auto& transaction : transactions) {
for (const auto& resolvedComposerState : transaction.states) {
const auto& clientState = resolvedComposerState.state;
- uint32_t layerId = LayerHandle::getLayerId(clientState.surface);
+ uint32_t layerId = resolvedComposerState.layerId;
if (layerId == UNASSIGNED_LAYER_ID) {
ALOGW("%s Handle %p is not valid", __func__, clientState.surface.get());
continue;
@@ -175,15 +174,14 @@
RequestedLayerState* layer = getLayerFromId(layerId);
if (layer == nullptr) {
- LOG_ALWAYS_FATAL("%s Layer with handle %p (layerid=%d) not found", __func__,
- clientState.surface.get(), layerId);
+ LOG_ALWAYS_FATAL("%s Layer with layerid=%d not found", __func__, layerId);
continue;
}
if (!layer->handleAlive) {
- LOG_ALWAYS_FATAL("%s Layer's handle %p (layerid=%d) is not alive. Possible out of "
+ LOG_ALWAYS_FATAL("%s Layer's with layerid=%d) is not alive. Possible out of "
"order LayerLifecycleManager updates",
- __func__, clientState.surface.get(), layerId);
+ __func__, layerId);
continue;
}
@@ -198,13 +196,11 @@
if (layer->what & layer_state_t::eBackgroundColorChanged) {
if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColor.a != 0) {
- LayerCreationArgs backgroundLayerArgs{nullptr,
- nullptr,
- layer->name + "BackgroundColorLayer",
- ISurfaceComposerClient::eFXSurfaceEffect,
- {},
- layer->id,
- /*internalLayer=*/true};
+ LayerCreationArgs backgroundLayerArgs(layer->id,
+ /*internalLayer=*/true);
+ backgroundLayerArgs.parentId = layer->id;
+ backgroundLayerArgs.name = layer->name + "BackgroundColorLayer";
+ backgroundLayerArgs.flags = ISurfaceComposerClient::eFXSurfaceEffect;
std::vector<std::unique_ptr<RequestedLayerState>> newLayers;
newLayers.emplace_back(
std::make_unique<RequestedLayerState>(backgroundLayerArgs));
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index e2cbe28..a5fdaf4 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -24,7 +24,6 @@
#include "Layer.h"
#include "LayerCreationArgs.h"
-#include "LayerHandle.h"
#include "LayerLog.h"
#include "RequestedLayerState.h"
@@ -33,14 +32,6 @@
using namespace ftl::flag_operators;
namespace {
-uint32_t getLayerIdFromSurfaceControl(sp<SurfaceControl> surfaceControl) {
- if (!surfaceControl) {
- return UNASSIGNED_LAYER_ID;
- }
-
- return LayerHandle::getLayerId(surfaceControl->getHandle());
-}
-
std::string layerIdToString(uint32_t layerId) {
return layerId == UNASSIGNED_LAYER_ID ? "none" : std::to_string(layerId);
}
@@ -64,17 +55,17 @@
layerCreationFlags(args.flags),
textureName(args.textureName),
ownerUid(args.ownerUid),
- ownerPid(args.ownerPid) {
+ ownerPid(args.ownerPid),
+ parentId(args.parentId),
+ layerIdToMirror(args.layerIdToMirror) {
layerId = static_cast<int32_t>(args.sequence);
changes |= RequestedLayerState::Changes::Created;
metadata.merge(args.metadata);
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
- parentId = LayerHandle::getLayerId(args.parentHandle.promote());
- if (args.parentHandle != nullptr) {
+ if (parentId != UNASSIGNED_LAYER_ID) {
canBeRoot = false;
}
- layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
if (layerIdToMirror != UNASSIGNED_LAYER_ID) {
changes |= RequestedLayerState::Changes::Mirror;
} else if (args.layerStackToMirror != ui::INVALID_LAYER_STACK) {
@@ -209,7 +200,7 @@
}
if (clientState.what & layer_state_t::eReparent) {
changes |= RequestedLayerState::Changes::Parent;
- parentId = getLayerIdFromSurfaceControl(clientState.parentSurfaceControlForChild);
+ parentId = resolvedComposerState.parentId;
parentSurfaceControlForChild = nullptr;
// Once a layer has be reparented, it cannot be placed at the root. It sounds odd
// but thats the existing logic and until we make this behavior more explicit, we need
@@ -218,7 +209,7 @@
}
if (clientState.what & layer_state_t::eRelativeLayerChanged) {
changes |= RequestedLayerState::Changes::RelativeParent;
- relativeParentId = getLayerIdFromSurfaceControl(clientState.relativeLayerSurfaceControl);
+ relativeParentId = resolvedComposerState.relativeParentId;
isRelativeOf = true;
relativeLayerSurfaceControl = nullptr;
}
@@ -235,10 +226,8 @@
changes |= RequestedLayerState::Changes::RelativeParent;
}
if (clientState.what & layer_state_t::eInputInfoChanged) {
- wp<IBinder>& touchableRegionCropHandle =
- windowInfoHandle->editInfo()->touchableRegionCropHandle;
- touchCropId = LayerHandle::getLayerId(touchableRegionCropHandle.promote());
- touchableRegionCropHandle.clear();
+ touchCropId = resolvedComposerState.touchCropId;
+ windowInfoHandle->editInfo()->touchableRegionCropHandle.clear();
}
if (clientState.what & layer_state_t::eStretchChanged) {
stretchEffect.sanitize();
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 6f5485d..216e95f 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -105,17 +105,17 @@
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
gui::GameMode gameMode;
scheduler::LayerInfo::FrameRate requestedFrameRate;
- ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t parentId = UNASSIGNED_LAYER_ID;
+ uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID;
+ ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t touchCropId = UNASSIGNED_LAYER_ID;
+ uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID;
// book keeping states
bool handleAlive = true;
bool isRelativeOf = false;
- uint32_t parentId = UNASSIGNED_LAYER_ID;
- uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
std::vector<uint32_t> mirrorIds{};
- uint32_t touchCropId = UNASSIGNED_LAYER_ID;
- uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID;
ftl::Flags<RequestedLayerState::Changes> changes;
bool bgColorLayer = false;
};
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp
index c88554e..9eefbe4 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.cpp
+++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp
@@ -40,7 +40,8 @@
for (const auto& listener : toInvoke) {
ATRACE_NAME("invoking onHdrLayerInfoChanged");
- listener->onHdrLayerInfoChanged(info.numberOfHdrLayers, info.maxW, info.maxH, info.flags);
+ listener->onHdrLayerInfoChanged(info.numberOfHdrLayers, info.maxW, info.maxH, info.flags,
+ info.maxDesiredHdrSdrRatio);
}
}
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h
index 9b70c16..bf7c775 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.h
+++ b/services/surfaceflinger/HdrLayerInfoReporter.h
@@ -43,27 +43,18 @@
// With peak display brightnesses exceeding 1,000 nits currently, HLG's request could
// actually be satisfied in some ambient conditions such that limiting that max for that
// content in theory makes sense
- float maxDesiredSdrHdrRatio = 0.f;
+ float maxDesiredHdrSdrRatio = 0.f;
bool operator==(const HdrLayerInfo& other) const {
return numberOfHdrLayers == other.numberOfHdrLayers && maxW == other.maxW &&
- maxH == other.maxH && flags == other.flags;
+ maxH == other.maxH && flags == other.flags &&
+ maxDesiredHdrSdrRatio == other.maxDesiredHdrSdrRatio;
}
bool operator!=(const HdrLayerInfo& other) const { return !(*this == other); }
void mergeDesiredRatio(float update) {
- if (maxDesiredSdrHdrRatio == 0.f) {
- // If nothing is set, take the incoming value
- maxDesiredSdrHdrRatio = update;
- } else if (update == 1.f) {
- // If the request is to "go to max", then take it regardless
- maxDesiredSdrHdrRatio = 1.f;
- } else if (maxDesiredSdrHdrRatio != 1.f) {
- // If we're not currently asked to "go to max", then take the max
- // of the incoming requests
- maxDesiredSdrHdrRatio = std::max(maxDesiredSdrHdrRatio, update);
- }
+ maxDesiredHdrSdrRatio = std::max(maxDesiredHdrSdrRatio, update);
}
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index f6fe468..eec7c08 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -308,7 +308,7 @@
// significantly faster than the display rate, at it would cause a significant frame drop.
// It is more appropriate to choose a higher display rate even if
// a pull-down will be required.
- constexpr float kMinMultiplier = 0.25f;
+ constexpr float kMinMultiplier = 0.75f;
if (multiplier >= kMinMultiplier &&
isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) {
return kScoreForFractionalPairs;
@@ -958,7 +958,7 @@
}
const bool ascending = (refreshRateOrder == RefreshRateOrder::Ascending);
- const auto id = frameRateMode.modePtr->getId();
+ const auto id = modePtr->getId();
if (ascending && frameRateMode.fps < *maxRenderRateForMode.get(id)) {
// TODO(b/266481656): Once this bug is fixed, we can remove this workaround and actually
// use a lower frame rate when we want Ascending frame rates.
@@ -970,14 +970,20 @@
if (ascending) {
score = 1.0f / score;
}
+
+ constexpr float kScore = std::numeric_limits<float>::max();
if (preferredDisplayModeOpt) {
if (*preferredDisplayModeOpt == modePtr->getId()) {
- constexpr float kScore = std::numeric_limits<float>::max();
ranking.emplace_front(ScoredFrameRate{frameRateMode, kScore});
return;
}
constexpr float kNonPreferredModePenalty = 0.95f;
score *= kNonPreferredModePenalty;
+ } else if (ascending && id == getMinRefreshRateByPolicyLocked()->getId()) {
+ // TODO(b/266481656): Once this bug is fixed, we can remove this workaround
+ // and actually use a lower frame rate when we want Ascending frame rates.
+ ranking.emplace_front(ScoredFrameRate{frameRateMode, kScore});
+ return;
}
ALOGV("%s(%s) %s (%s) scored %.2f", whence, ftl::enum_string(refreshRateOrder).c_str(),
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index f18dfdc..6e33272 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -402,6 +402,7 @@
}
void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
+ ATRACE_CALL();
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 62a5fb2..74547d5 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -165,7 +165,7 @@
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
- const VsyncModulator& vsyncModulator() const { return *mVsyncModulator; }
+ VsyncModulator& vsyncModulator() { return *mVsyncModulator; }
// In some cases, we should only modulate for the pacesetter display. In those
// cases, the caller should pass in the relevant display, and the method
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index c9af4c2..586357f 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -187,9 +187,9 @@
static_cast<void>(updateVsyncConfigLocked());
}
-bool VsyncModulator::isVsyncConfigDefault() const {
+bool VsyncModulator::isVsyncConfigEarly() const {
std::lock_guard<std::mutex> lock(mMutex);
- return getNextVsyncConfigType() == VsyncConfigType::Late;
+ return getNextVsyncConfigType() != VsyncConfigType::Late;
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index dc4dafd..be0d334 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -53,8 +53,12 @@
explicit VsyncModulator(const VsyncConfigSet&, Now = Clock::now);
+ bool isVsyncConfigEarly() const EXCLUDES(mMutex);
+
VsyncConfig getVsyncConfig() const EXCLUDES(mMutex);
+ void cancelRefreshRateChange() { mRefreshRateChangePending = false; }
+
[[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);
// Changes offsets in response to transaction flags or commit.
@@ -72,8 +76,6 @@
[[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
- [[nodiscard]] bool isVsyncConfigDefault() const;
-
protected:
// Called from unit tests as well
void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0bdede8..63b7f75 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -292,6 +292,13 @@
displayHdrCapabilities.getDesiredMinLuminance()};
}
+uint32_t getLayerIdFromSurfaceControl(sp<SurfaceControl> surfaceControl) {
+ if (!surfaceControl) {
+ return UNASSIGNED_LAYER_ID;
+ }
+ return LayerHandle::getLayerId(surfaceControl->getHandle());
+}
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -497,14 +504,13 @@
// the window manager died on us. prepare its eulogy.
mBootFinished = false;
- // Sever the link to inputflinger since it's gone as well.
- static_cast<void>(mScheduler->schedule(
- [this] { mInputFlinger.clear(); }));
+ static_cast<void>(mScheduler->schedule([this]() FTL_FAKE_GUARD(kMainThreadContext) {
+ // Sever the link to inputflinger since it's gone as well.
+ mInputFlinger.clear();
- // restore initial conditions (default device unblank, etc)
- initializeDisplays();
+ initializeDisplays();
+ }));
- // restart the boot-animation
startBootAnim();
}
@@ -873,7 +879,9 @@
mDrawingState = mCurrentState;
onActiveDisplayChangedLocked(nullptr, *display);
- initializeDisplays();
+
+ static_cast<void>(mScheduler->schedule(
+ [this]() FTL_FAKE_GUARD(kMainThreadContext) { initializeDisplays(); }));
mPowerAdvisor->init();
@@ -2882,7 +2890,12 @@
const auto* outputLayer =
compositionDisplay->getOutputLayerForLayer(layerFe);
if (outputLayer) {
- info.mergeDesiredRatio(snapshot.desiredSdrHdrRatio);
+ // TODO(b/267350616): Rename SdrHdrRatio -> HdrSdrRatio
+ // everywhere
+ const float desiredHdrSdrRatio = snapshot.desiredSdrHdrRatio <= 1.f
+ ? std::numeric_limits<float>::infinity()
+ : snapshot.desiredSdrHdrRatio;
+ info.mergeDesiredRatio(desiredHdrSdrRatio);
info.numberOfHdrLayers++;
const auto displayFrame = outputLayer->getState().displayFrame;
const int32_t area = displayFrame.width() * displayFrame.height();
@@ -3485,7 +3498,7 @@
// TODO(b/175678251) Call a listener instead.
if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) {
- updateActiveDisplayVsyncLocked(*display);
+ resetPhaseConfiguration(display->getActiveMode().fps);
}
}
return;
@@ -3519,9 +3532,11 @@
}
}
-void SurfaceFlinger::updateActiveDisplayVsyncLocked(const DisplayDevice& activeDisplay) {
+void SurfaceFlinger::resetPhaseConfiguration(Fps refreshRate) {
+ // Cancel the pending refresh rate change, if any, before updating the phase configuration.
+ mScheduler->vsyncModulator().cancelRefreshRateChange();
+
mVsyncConfiguration->reset();
- const Fps refreshRate = activeDisplay.getActiveMode().fps;
updatePhaseConfiguration(refreshRate);
mRefreshRateStats->setRefreshRate(refreshRate);
}
@@ -4061,7 +4076,7 @@
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
-status_t SurfaceFlinger::addClientLayer(const LayerCreationArgs& args, const sp<IBinder>& handle,
+status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
const sp<Layer>& layer, const wp<Layer>& parent,
uint32_t* outTransformHint) {
if (mNumLayers >= MAX_LAYERS) {
@@ -4091,7 +4106,8 @@
if (outTransformHint) {
*outTransformHint = mActiveDisplayTransformHint;
}
-
+ args.parentId = LayerHandle::getLayerId(args.parentHandle.promote());
+ args.layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
{
std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
mCreatedLayers.emplace_back(layer, parent, args.addToRoot);
@@ -4119,6 +4135,7 @@
ATRACE_INT("mTransactionFlags", transactionFlags);
if (const bool scheduled = transactionFlags & mask; !scheduled) {
+ mScheduler->resync();
scheduleCommit(frameHint);
} else if (frameHint == FrameHint::kActive) {
// Even if the next frame is already scheduled, we should reset the idle timer
@@ -4261,7 +4278,7 @@
bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
VsyncId vsyncId) {
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
return applyTransactionsLocked(transactions, vsyncId);
}
@@ -4342,9 +4359,8 @@
// We don't want to latch unsignaled if are in early / client composition
// as it leads to jank due to RenderEngine waiting for unsignaled buffer
// or window animations being slow.
- const auto isDefaultVsyncConfig = mScheduler->vsyncModulator().isVsyncConfigDefault();
- if (!isDefaultVsyncConfig) {
- ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)",
+ if (mScheduler->vsyncModulator().isVsyncConfigEarly()) {
+ ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; isVsyncConfigEarly)",
__func__);
return false;
}
@@ -4423,6 +4439,21 @@
layerName.c_str(), transactionId);
mBufferCountTracker.increment(resolvedState.state.surface->localBinder());
}
+ resolvedState.layerId = LayerHandle::getLayerId(resolvedState.state.surface);
+ if (resolvedState.state.what & layer_state_t::eReparent) {
+ resolvedState.parentId =
+ getLayerIdFromSurfaceControl(resolvedState.state.parentSurfaceControlForChild);
+ }
+ if (resolvedState.state.what & layer_state_t::eRelativeLayerChanged) {
+ resolvedState.relativeParentId =
+ getLayerIdFromSurfaceControl(resolvedState.state.relativeLayerSurfaceControl);
+ }
+ if (resolvedState.state.what & layer_state_t::eInputInfoChanged) {
+ wp<IBinder>& touchableRegionCropHandle =
+ resolvedState.state.windowInfoHandle->editInfo()->touchableRegionCropHandle;
+ resolvedState.touchCropId =
+ LayerHandle::getLayerId(touchableRegionCropHandle.promote());
+ }
}
TransactionState state{frameTimelineInfo,
@@ -4547,7 +4578,7 @@
bool SurfaceFlinger::applyAndCommitDisplayTransactionStates(
std::vector<TransactionState>& transactions) {
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
bool needsTraversal = false;
uint32_t transactionFlags = 0;
for (auto& transaction : transactions) {
@@ -5285,8 +5316,8 @@
setTransactionFlags(eTransactionFlushNeeded);
}
-void SurfaceFlinger::onInitializeDisplays() {
- const auto display = getDefaultDisplayDeviceLocked();
+void SurfaceFlinger::initializeDisplays() {
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (!display) return;
const sp<IBinder> token = display->getDisplayToken().promote();
@@ -5294,13 +5325,13 @@
TransactionState state;
state.inputWindowCommands = mInputWindowCommands;
- nsecs_t now = systemTime();
+ const nsecs_t now = systemTime();
state.desiredPresentTime = now;
state.postTime = now;
state.permissions = layer_state_t::ACCESS_SURFACE_FLINGER;
state.originPid = mPid;
state.originUid = static_cast<int>(getuid());
- uint64_t transactionId = (((uint64_t)mPid) << 32) | mUniqueTransactionId++;
+ const uint64_t transactionId = (static_cast<uint64_t>(mPid) << 32) | mUniqueTransactionId++;
state.id = transactionId;
// reset screen orientation and use primary layer stack
@@ -5320,21 +5351,16 @@
std::vector<TransactionState> transactions;
transactions.emplace_back(state);
- // It should be on the main thread, apply it directly.
if (mLegacyFrontEndEnabled) {
- applyTransactionsLocked(transactions, /*vsyncId=*/{0});
+ applyTransactions(transactions, VsyncId{0});
} else {
applyAndCommitDisplayTransactionStates(transactions);
}
- setPowerModeInternal(display, hal::PowerMode::ON);
-}
-
-void SurfaceFlinger::initializeDisplays() {
- // Async since we may be called from the main thread.
- static_cast<void>(mScheduler->schedule(
- [this]() FTL_FAKE_GUARD(mStateLock)
- FTL_FAKE_GUARD(kMainThreadContext) { onInitializeDisplays(); }));
+ {
+ ftl::FakeGuard guard(mStateLock);
+ setPowerModeInternal(display, hal::PowerMode::ON);
+ }
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -7721,14 +7747,20 @@
const DisplayDevice& activeDisplay) {
ATRACE_CALL();
+ // For the first display activated during boot, there is no need to force setDesiredActiveMode,
+ // because DM is about to send its policy via setDesiredDisplayModeSpecs.
+ bool forceApplyPolicy = false;
+
if (inactiveDisplayPtr) {
inactiveDisplayPtr->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
+ forceApplyPolicy = true;
}
mActiveDisplayId = activeDisplay.getPhysicalId();
activeDisplay.getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
- updateActiveDisplayVsyncLocked(activeDisplay);
+ resetPhaseConfiguration(activeDisplay.getActiveMode().fps);
+
mScheduler->setModeChangePending(false);
mScheduler->setPacesetterDisplay(mActiveDisplayId);
@@ -7739,8 +7771,8 @@
// that case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In
// either case, the Scheduler's cachedModeChangedParams must be initialized to the newly active
// mode, and the kernel idle timer of the newly active display must be toggled.
- constexpr bool kForce = true;
- applyRefreshRateSelectorPolicy(mActiveDisplayId, activeDisplay.refreshRateSelector(), kForce);
+ applyRefreshRateSelectorPolicy(mActiveDisplayId, activeDisplay.refreshRateSelector(),
+ forceApplyPolicy);
}
status_t SurfaceFlinger::addWindowInfosListener(
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 338531f..63d54bc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -737,6 +737,8 @@
void updateCursorAsync();
void initScheduler(const sp<const DisplayDevice>&) REQUIRES(kMainThreadContext, mStateLock);
+
+ void resetPhaseConfiguration(Fps) REQUIRES(mStateLock, kMainThreadContext);
void updatePhaseConfiguration(Fps) REQUIRES(mStateLock);
/*
@@ -818,7 +820,7 @@
void markLayerPendingRemovalLocked(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
- status_t addClientLayer(const LayerCreationArgs& args, const sp<IBinder>& handle,
+ status_t addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
const sp<Layer>& layer, const wp<Layer>& parentLayer,
uint32_t* outTransformHint);
@@ -855,8 +857,7 @@
*/
// Called during boot, and restart after system_server death.
- void initializeDisplays();
- void onInitializeDisplays() REQUIRES(mStateLock, kMainThreadContext);
+ void initializeDisplays() REQUIRES(kMainThreadContext);
sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const
REQUIRES(mStateLock) {
@@ -1121,9 +1122,6 @@
std::chrono::nanoseconds presentLatency);
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
- void updateActiveDisplayVsyncLocked(const DisplayDevice& activeDisplay)
- REQUIRES(mStateLock, kMainThreadContext);
-
bool isHdrLayer(const frontend::LayerSnapshot& snapshot) const;
ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 40d06a8..2daea25 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -20,6 +20,7 @@
#include <memory>
#include <mutex>
#include <vector>
+#include "FrontEnd/LayerCreationArgs.h"
#include "renderengine/ExternalTexture.h"
#include <gui/LayerState.h>
@@ -39,6 +40,10 @@
ResolvedComposerState() = default;
ResolvedComposerState(ComposerState&& source) { state = std::move(source.state); }
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ uint32_t layerId = UNASSIGNED_LAYER_ID;
+ uint32_t parentId = UNASSIGNED_LAYER_ID;
+ uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
+ uint32_t touchCropId = UNASSIGNED_LAYER_ID;
};
struct TransactionState {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index f27f53b..72cecc9 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -402,9 +402,8 @@
SurfaceFlinger *flinger() { return mFlinger.get(); }
scheduler::TestableScheduler *scheduler() { return mScheduler; }
- // Allow reading display state without locking, as if called on the SF main thread.
- auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
- return mFlinger->onInitializeDisplays();
+ void initializeDisplays() {
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->initializeDisplays());
}
void setGlobalShadowSettings(FuzzedDataProvider *fdp) {
@@ -542,7 +541,7 @@
mFlinger->createDisplay(String8(fdp->ConsumeRandomLengthString().c_str()),
fdp->ConsumeBool());
- onInitializeDisplays();
+ initializeDisplays();
mFlinger->getPhysicalDisplayToken(physicalDisplayId);
mFlinger->mStartPropertySetThread =
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 012a4ad..df3ffd2 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -107,9 +107,9 @@
"SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
"SurfaceFlinger_HdrOutputControlTest.cpp",
"SurfaceFlinger_HotplugTest.cpp",
+ "SurfaceFlinger_InitializeDisplaysTest.cpp",
"SurfaceFlinger_MultiDisplayPacesetterTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
- "SurfaceFlinger_OnInitializeDisplaysTest.cpp",
"SurfaceFlinger_PowerHintTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 77dc868..ddf3363 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -17,12 +17,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
-#include "Layer.h"
#include "LayerHierarchyTest.h"
-#include "gui/SurfaceComposerClient.h"
#define UPDATE_AND_VERIFY(HIERARCHY) \
({ \
@@ -207,7 +204,8 @@
reparentRelativeLayer(11, 2);
UPDATE_AND_VERIFY(hierarchyBuilder);
- reparentRelativeLayer(11, UNASSIGNED_LAYER_ID);
+ // This calls setLayer
+ removeRelativeZ(11);
UPDATE_AND_VERIFY(hierarchyBuilder);
std::vector<uint32_t> expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2};
@@ -418,7 +416,7 @@
EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
// remove relative parent so layer becomes onscreen again
- reparentRelativeLayer(11, UNASSIGNED_LAYER_ID);
+ removeRelativeZ(11);
UPDATE_AND_VERIFY(hierarchyBuilder);
expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13};
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index b9a6159..5b3c7ef 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -17,11 +17,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
+#include "Client.h" // temporarily needed for LayerCreationArgs
+#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
-#include "Layer.h"
-#include "gui/SurfaceComposerClient.h"
namespace android::surfaceflinger::frontend {
@@ -51,20 +50,21 @@
createLayer(1221, 122);
}
- LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent,
- wp<IBinder> mirror) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
+ LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, uint32_t parentId,
+ uint32_t layerIdToMirror) {
+ LayerCreationArgs args(std::make_optional(id));
+ args.name = "testlayer";
args.addToRoot = canBeRoot;
- args.parentHandle = parent;
- args.mirrorLayerHandle = mirror;
+ args.parentId = parentId;
+ args.layerIdToMirror = layerIdToMirror;
return args;
}
- LayerCreationArgs createDisplayMirrorArgs(uint32_t id, ui::LayerStack layerStack) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
+ LayerCreationArgs createDisplayMirrorArgs(uint32_t id, ui::LayerStack layerStackToMirror) {
+ LayerCreationArgs args(std::make_optional(id));
+ args.name = "testlayer";
args.addToRoot = true;
- args.parentHandle.clear();
- args.layerStackToMirror = layerStack;
+ args.layerStackToMirror = layerStackToMirror;
return args;
}
@@ -90,17 +90,14 @@
}
virtual void createRootLayer(uint32_t id) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr)));
+ createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID)));
mLifecycleManager.addLayers(std::move(layers));
}
void createDisplayMirrorLayer(uint32_t id, ui::LayerStack layerStack) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
createDisplayMirrorArgs(/*id=*/id, layerStack)));
@@ -108,62 +105,56 @@
}
virtual void createLayer(uint32_t id, uint32_t parentId) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/mHandles[parentId],
- /*mirror=*/nullptr)));
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
+ /*mirror=*/UNASSIGNED_LAYER_ID)));
mLifecycleManager.addLayers(std::move(layers));
}
- void reparentLayer(uint32_t id, uint32_t newParentId) {
+ std::vector<TransactionState> reparentLayerTransaction(uint32_t id, uint32_t newParentId) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
-
- if (newParentId == UNASSIGNED_LAYER_ID) {
- transactions.back().states.front().state.parentSurfaceControlForChild = nullptr;
- } else {
- auto parentHandle = mHandles[newParentId];
- transactions.back().states.front().state.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
- static_cast<int32_t>(newParentId), "Test");
- }
+ transactions.back().states.front().parentId = newParentId;
transactions.back().states.front().state.what = layer_state_t::eReparent;
- transactions.back().states.front().state.surface = mHandles[id];
- mLifecycleManager.applyTransactions(transactions);
+ transactions.back().states.front().relativeParentId = UNASSIGNED_LAYER_ID;
+ transactions.back().states.front().layerId = id;
+ return transactions;
+ }
+
+ void reparentLayer(uint32_t id, uint32_t newParentId) {
+ mLifecycleManager.applyTransactions(reparentLayerTransaction(id, newParentId));
+ }
+
+ std::vector<TransactionState> relativeLayerTransaction(uint32_t id, uint32_t relativeParentId) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().relativeParentId = relativeParentId;
+ transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
+ transactions.back().states.front().layerId = id;
+ return transactions;
}
void reparentRelativeLayer(uint32_t id, uint32_t relativeParentId) {
+ mLifecycleManager.applyTransactions(relativeLayerTransaction(id, relativeParentId));
+ }
+
+ void removeRelativeZ(uint32_t id) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
-
- if (relativeParentId == UNASSIGNED_LAYER_ID) {
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- } else {
- auto parentHandle = mHandles[relativeParentId];
- transactions.back().states.front().state.relativeLayerSurfaceControl =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
- static_cast<int32_t>(relativeParentId), "test");
- transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
- }
- transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
- virtual void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) {
- auto parentHandle = (parent == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[parent];
- auto mirrorHandle =
- (layerToMirror == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[layerToMirror];
-
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
+ virtual void mirrorLayer(uint32_t id, uint32_t parentId, uint32_t layerIdToMirror) {
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentHandle,
- /*mirror=*/mHandles[layerToMirror])));
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentId,
+ /*mirror=*/layerIdToMirror)));
mLifecycleManager.addLayers(std::move(layers));
}
@@ -173,7 +164,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
transactions.back().states.front().state.bgColor.a = alpha;
- transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
@@ -196,16 +187,19 @@
mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
}
- void setZ(uint32_t id, int32_t z) {
+ std::vector<TransactionState> setZTransaction(uint32_t id, int32_t z) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.z = z;
- mLifecycleManager.applyTransactions(transactions);
+ return transactions;
+ }
+
+ void setZ(uint32_t id, int32_t z) {
+ mLifecycleManager.applyTransactions(setZTransaction(id, z));
}
void setCrop(uint32_t id, const Rect& crop) {
@@ -214,8 +208,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eCropChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.crop = crop;
mLifecycleManager.applyTransactions(transactions);
}
@@ -228,8 +221,7 @@
transactions.back().states.front().state.what = layer_state_t::eFlagsChanged;
transactions.back().states.front().state.flags = flags;
transactions.back().states.front().state.mask = mask;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
@@ -239,8 +231,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eAlphaChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.color.a = static_cast<half>(alpha);
mLifecycleManager.applyTransactions(transactions);
}
@@ -257,8 +248,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eColorChanged;
transactions.back().states.front().state.color.rgb = rgb;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
mLifecycleManager.applyTransactions(transactions);
}
@@ -268,8 +258,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eLayerStackChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.layerStack = ui::LayerStack::fromValue(layerStack);
mLifecycleManager.applyTransactions(transactions);
}
@@ -280,8 +269,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
- transactions.back().states.front().state.surface = mHandles[id];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().layerId = id;
transactions.back().states.front().state.windowInfoHandle =
sp<gui::WindowInfoHandle>::make();
auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
@@ -291,7 +279,6 @@
}
LayerLifecycleManager mLifecycleManager;
- std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index 99c1d23..14b8e4b 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -17,25 +17,14 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerLifecycleManager.h"
-#include "Layer.h"
-#include "gui/SurfaceComposerClient.h"
+#include "LayerHierarchyTest.h"
+#include "TransactionState.h"
using namespace android::surfaceflinger;
namespace android::surfaceflinger::frontend {
-namespace {
-LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent, wp<IBinder> mirror) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
- args.addToRoot = canBeRoot;
- args.parentHandle = parent;
- args.mirrorLayerHandle = mirror;
- return args;
-}
-} // namespace
-
// To run test:
/**
mp :libsurfaceflinger_unittest && adb sync; adb shell \
@@ -66,69 +55,24 @@
std::unordered_set<uint32_t> mActualLayersDestroyed;
};
-class LayerLifecycleManagerTest : public testing::Test {
+class LayerLifecycleManagerTest : public LayerHierarchyTestBase {
protected:
std::unique_ptr<RequestedLayerState> rootLayer(uint32_t id) {
- return std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr));
+ return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/true,
+ /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID));
}
std::unique_ptr<RequestedLayerState> childLayer(uint32_t id, uint32_t parentId) {
- mHandles[parentId] = sp<LayerHandle>::make(parentId);
return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/false,
- /*parent=*/mHandles[parentId],
- /*mirror=*/nullptr));
- }
-
- TransactionState reparentLayer(uint32_t id, uint32_t newParentId) {
- TransactionState transaction;
- transaction.states.push_back({});
-
- if (newParentId == UNASSIGNED_LAYER_ID) {
- transaction.states.front().state.parentSurfaceControlForChild = nullptr;
- } else {
- transaction.states.front().state.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
- sp<LayerHandle>::make(newParentId),
- static_cast<int32_t>(newParentId), "Test");
- }
- transaction.states.front().state.what = layer_state_t::eReparent;
- transaction.states.front().state.surface = sp<LayerHandle>::make(id);
- return transaction;
- }
-
- TransactionState setLayer(uint32_t id, int32_t z) {
- TransactionState transaction;
- transaction.states.push_back({});
- transaction.states.front().state.z = z;
- transaction.states.front().state.what = layer_state_t::eLayerChanged;
- transaction.states.front().state.surface = sp<LayerHandle>::make(id);
- return transaction;
- }
-
- TransactionState makeRelative(uint32_t id, uint32_t relativeParentId) {
- TransactionState transaction;
- transaction.states.push_back({});
-
- if (relativeParentId == UNASSIGNED_LAYER_ID) {
- transaction.states.front().state.relativeLayerSurfaceControl = nullptr;
- } else {
- transaction.states.front().state.relativeLayerSurfaceControl =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
- sp<LayerHandle>::make(relativeParentId),
- static_cast<int32_t>(relativeParentId), "Test");
- }
- transaction.states.front().state.what = layer_state_t::eRelativeLayerChanged;
- transaction.states.front().state.surface = sp<LayerHandle>::make(id);
- return transaction;
+ parentId,
+ /*mirror=*/UNASSIGNED_LAYER_ID));
}
RequestedLayerState* getRequestedLayerState(LayerLifecycleManager& lifecycleManager,
uint32_t layerId) {
return lifecycleManager.getLayerFromId(layerId);
}
-
- std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
};
TEST_F(LayerLifecycleManagerTest, addLayers) {
@@ -153,16 +97,7 @@
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(rootLayer(1));
lifecycleManager.addLayers(std::move(layers));
-
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.z = 2;
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
- lifecycleManager.applyTransactions(transactions);
- transactions.clear();
+ lifecycleManager.applyTransactions(setZTransaction(1, 2));
auto& managedLayers = lifecycleManager.getLayers();
ASSERT_EQ(managedLayers.size(), 1u);
@@ -177,11 +112,12 @@
EXPECT_FALSE(managedLayers.front()->changes.test(RequestedLayerState::Changes::Z));
// apply transactions that do not affect the hierarchy
+ std::vector<TransactionState> transactions;
transactions.emplace_back();
transactions.back().states.push_back({});
transactions.back().states.front().state.backgroundBlurRadius = 22;
transactions.back().states.front().state.what = layer_state_t::eBackgroundBlurRadiusChanged;
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
lifecycleManager.applyTransactions(transactions);
EXPECT_FALSE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
lifecycleManager.commitChanges();
@@ -232,7 +168,7 @@
listener->expectLayersAdded({1, 2, 3});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(3, UNASSIGNED_LAYER_ID));
lifecycleManager.commitChanges();
listener->expectLayersAdded({});
listener->expectLayersDestroyed({});
@@ -257,7 +193,7 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(3, UNASSIGNED_LAYER_ID));
lifecycleManager.onHandlesDestroyed({3});
lifecycleManager.commitChanges();
listener->expectLayersAdded({});
@@ -278,7 +214,7 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(3, UNASSIGNED_LAYER_ID));
lifecycleManager.onHandlesDestroyed({3, 4});
lifecycleManager.commitChanges();
listener->expectLayersAdded({});
@@ -300,9 +236,9 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({makeRelative(4, 1)});
+ lifecycleManager.applyTransactions(relativeLayerTransaction(4, 1));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
- lifecycleManager.applyTransactions({reparentLayer(4, 2)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(4, 2));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
lifecycleManager.commitChanges();
@@ -325,9 +261,9 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({makeRelative(4, 1)});
+ lifecycleManager.applyTransactions(relativeLayerTransaction(4, 1));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
- lifecycleManager.applyTransactions({reparentLayer(4, UNASSIGNED_LAYER_ID)});
+ lifecycleManager.applyTransactions(reparentLayerTransaction(4, UNASSIGNED_LAYER_ID));
EXPECT_FALSE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
lifecycleManager.commitChanges();
@@ -350,9 +286,9 @@
listener->expectLayersAdded({1, 2, 3, 4});
listener->expectLayersDestroyed({});
- lifecycleManager.applyTransactions({makeRelative(4, 1)});
+ lifecycleManager.applyTransactions(relativeLayerTransaction(4, 1));
EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
- lifecycleManager.applyTransactions({setLayer(4, 1)});
+ lifecycleManager.applyTransactions(setZTransaction(4, 1));
EXPECT_FALSE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf);
lifecycleManager.commitChanges();
@@ -374,8 +310,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0.5;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
lifecycleManager.applyTransactions(transactions);
auto& managedLayers = lifecycleManager.getLayers();
@@ -403,13 +338,12 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0.5;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
transactions.emplace_back();
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
lifecycleManager.applyTransactions(transactions);
@@ -437,8 +371,7 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.bgColor.a = 0.5;
transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- sp<LayerHandle> handle = sp<LayerHandle>::make(1u);
- transactions.back().states.front().state.surface = handle;
+ transactions.back().states.front().layerId = 1;
transactions.emplace_back();
lifecycleManager.applyTransactions(transactions);
lifecycleManager.onHandlesDestroyed({1});
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index db0b907..b8c4781 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -17,11 +17,9 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "FrontEnd/LayerHandle.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
#include "FrontEnd/LayerSnapshotBuilder.h"
-#include "Layer.h"
#include "LayerHierarchyTest.h"
#define UPDATE_AND_VERIFY(BUILDER, ...) \
@@ -268,7 +266,7 @@
transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
transactions.back().states.front().state.metadata = LayerMetadata();
transactions.back().states.front().state.metadata.setInt32(METADATA_GAME_MODE, 42);
- transactions.back().states.front().state.surface = mHandles[1];
+ transactions.back().states.front().layerId = 1;
transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
mLifecycleManager.applyTransactions(transactions);
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
@@ -297,8 +295,7 @@
ANATIVEWINDOW_FRAME_RATE_EXACT;
transactions.back().states.front().state.changeFrameRateStrategy =
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS;
- transactions.back().states.front().state.surface = mHandles[11];
- transactions.back().states.front().state.layerId = static_cast<int32_t>(11);
+ transactions.back().states.front().layerId = 11;
mLifecycleManager.applyTransactions(transactions);
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index f4d052d..63ed87b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1455,6 +1455,24 @@
lr.name = "ExplicitExactOrMultiple 29.97 Hz";
EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers)->getId());
}
+
+ // Test that 29.97 will choose 30 if 59.94 is not supported
+ {
+ auto selector = createSelector(makeModes(kMode30, kMode60), kModeId60);
+
+ lr.desiredRefreshRate = 29.97_Hz;
+ lr.name = "ExplicitExactOrMultiple 29.97 Hz";
+ EXPECT_EQ(kModeId30, selector.getBestFrameRateMode(layers)->getId());
+ }
+
+ // Test that 59.94 will choose 60 if 59.94 is not supported
+ {
+ auto selector = createSelector(makeModes(kMode60, kMode30Frac, kMode30), kModeId60);
+
+ lr.desiredRefreshRate = 59.94_Hz;
+ lr.name = "ExplicitExactOrMultiple 59.94 Hz";
+ EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId());
+ }
}
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitExact_WithFractionalRefreshRates) {
@@ -2981,6 +2999,12 @@
layers[0].name = "Test layer";
layers[0].vote = LayerVoteType::Min;
EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
+
+ constexpr FpsRanges kCappedAt60 = {{30_Hz, 90_Hz}, {30_Hz, 60_Hz}};
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {DisplayModeId(kModeId60), kCappedAt60, kCappedAt60}));
+ EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
}
TEST_P(RefreshRateSelectorTest, frameRateIsCappedByPolicy) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index fd1fd47..e176546 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -119,7 +119,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90.value(), false, 0,
@@ -159,7 +159,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90.value(), true, 0,
@@ -195,7 +195,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90.value(), false, 0,
@@ -238,7 +238,7 @@
ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
- mFlinger.onActiveDisplayChanged(*mDisplay);
+ mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
mock::createDisplayModeSpecs(kModeId90_4K.value(), false, 0,
@@ -284,9 +284,43 @@
ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90_4K);
}
-TEST_F(DisplayModeSwitchingTest, multiDisplay) {
+MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") {
+ if (!arg->getDesiredActiveMode()) {
+ *result_listener << "No desired active mode";
+ return false;
+ }
+
+ if (arg->getDesiredActiveMode()->modeOpt->modePtr->getId() != modeId) {
+ *result_listener << "Unexpected desired active mode " << modeId;
+ return false;
+ }
+
+ if (!flinger->scheduler()->vsyncModulator().isVsyncConfigEarly()) {
+ *result_listener << "VsyncModulator did not shift to early phase";
+ return false;
+ }
+
+ return true;
+}
+
+MATCHER_P(ModeSettledTo, modeId, "") {
+ if (const auto desiredOpt = arg->getDesiredActiveMode()) {
+ *result_listener << "Unsettled desired active mode "
+ << desiredOpt->modeOpt->modePtr->getId();
+ return false;
+ }
+
ftl::FakeGuard guard(kMainThreadContext);
+ if (arg->getActiveMode().modePtr->getId() != modeId) {
+ *result_listener << "Settled to unexpected active mode " << modeId;
+ return false;
+ }
+
+ return true;
+}
+
+TEST_F(DisplayModeSwitchingTest, multiDisplay) {
constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
@@ -309,13 +343,13 @@
const auto& innerDisplay = mDisplay;
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
- EXPECT_EQ(innerDisplay->getActiveMode().modePtr->getId(), kModeId60);
- EXPECT_EQ(outerDisplay->getActiveMode().modePtr->getId(), kModeId120);
+ mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
- mFlinger.onActiveDisplayChanged(*innerDisplay);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
EXPECT_EQ(NO_ERROR,
mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
@@ -327,12 +361,8 @@
mock::createDisplayModeSpecs(kModeId60.value(),
false, 0.f, 120.f)));
- // Transition on the inner display.
- ASSERT_TRUE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
-
- // No transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_CALL(*mComposer,
@@ -342,31 +372,18 @@
mFlinger.commit();
- // Transition on the inner display.
- ASSERT_TRUE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
-
- // No transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
mFlinger.commit();
- // Transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getActiveMode().modePtr->getId(), kModeId90);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
- // No transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getActiveMode().modePtr->getId(), kModeId120);
+ mFlinger.onActiveDisplayChanged(innerDisplay.get(), *outerDisplay);
- mFlinger.onActiveDisplayChanged(*outerDisplay);
-
- // No transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
-
- // Transition on the outer display.
- ASSERT_TRUE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId60);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
EXPECT_CALL(*mComposer,
setActiveConfigWithConstraints(kOuterDisplayHwcId,
@@ -375,22 +392,13 @@
mFlinger.commit();
- // No transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
-
- // Transition on the outer display.
- ASSERT_TRUE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId60);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
mFlinger.commit();
- // No transition on the inner display.
- EXPECT_FALSE(innerDisplay->getDesiredActiveMode());
- EXPECT_EQ(innerDisplay->getActiveMode().modePtr->getId(), kModeId90);
-
- // Transition on the outer display.
- EXPECT_FALSE(outerDisplay->getDesiredActiveMode());
- EXPECT_EQ(outerDisplay->getActiveMode().modePtr->getId(), kModeId60);
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp
similarity index 93%
rename from services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
rename to services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp
index 98644aa..fc5f2b0 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp
@@ -22,9 +22,9 @@
namespace android {
namespace {
-class OnInitializeDisplaysTest : public DisplayTransactionTest {};
+class InitializeDisplaysTest : public DisplayTransactionTest {};
-TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
+TEST_F(InitializeDisplaysTest, commitsPrimaryDisplay) {
using Case = SimplePrimaryDisplayCase;
// --------------------------------------------------------------------
@@ -52,7 +52,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.onInitializeDisplays();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger.initializeDisplays());
// --------------------------------------------------------------------
// Postconditions
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d4b4434..f1a5fc4 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -102,7 +102,6 @@
}
auto& mutableAppConnectionHandle() { return mAppConnectionHandle; }
- auto& mutableVsyncModulator() { return *mVsyncModulator; }
auto& mutableLayerHistory() { return mLayerHistory; }
size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6334ec8..fc9e653 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -419,10 +419,7 @@
return mFlinger->setDisplayStateLocked(s);
}
- // Allow reading display state without locking, as if called on the SF main thread.
- auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
- return mFlinger->onInitializeDisplays();
- }
+ void initializeDisplays() FTL_FAKE_GUARD(kMainThreadContext) { mFlinger->initializeDisplays(); }
auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
@@ -505,10 +502,11 @@
return mFlinger->setDesiredDisplayModeSpecs(displayToken, specs);
}
- void onActiveDisplayChanged(const DisplayDevice& activeDisplay) {
+ void onActiveDisplayChanged(const DisplayDevice* inactiveDisplayPtr,
+ const DisplayDevice& activeDisplay) {
Mutex::Autolock lock(mFlinger->mStateLock);
ftl::FakeGuard guard(kMainThreadContext);
- mFlinger->onActiveDisplayChangedLocked(nullptr, activeDisplay);
+ mFlinger->onActiveDisplayChangedLocked(inactiveDisplayPtr, activeDisplay);
}
auto createLayer(LayerCreationArgs& args, const sp<IBinder>& parentHandle,
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index c78148f..d4e2357 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -199,7 +199,7 @@
void modulateVsync() {
static_cast<void>(
- mFlinger.mutableScheduler().mutableVsyncModulator().onRefreshRateChangeInitiated());
+ mFlinger.mutableScheduler().vsyncModulator().onRefreshRateChangeInitiated());
}
bool mHasListenerCallbacks = false;