summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/android/choreographer.h64
-rw-r--r--include/android/input.h14
-rw-r--r--include/android/sensor.h40
-rw-r--r--include/android/surface_control.h20
-rw-r--r--include/ftl/Flags.h99
-rw-r--r--include/ftl/NamedEnum.h129
-rw-r--r--include/ftl/cast.h84
-rw-r--r--include/ftl/concat.h84
-rw-r--r--include/ftl/details/array_traits.h (renamed from include/ftl/array_traits.h)6
-rw-r--r--include/ftl/details/cast.h57
-rw-r--r--include/ftl/details/concat.h62
-rw-r--r--include/ftl/enum.h301
-rw-r--r--include/ftl/initializer_list.h13
-rw-r--r--include/ftl/small_map.h157
-rw-r--r--include/ftl/small_vector.h33
-rw-r--r--include/ftl/static_vector.h24
-rw-r--r--include/ftl/string.h101
-rw-r--r--include/input/DisplayViewport.h10
-rw-r--r--include/input/Input.h93
-rw-r--r--include/input/InputDevice.h5
-rw-r--r--include/input/InputTransport.h58
-rw-r--r--include/powermanager/PowerHalWrapper.h4
-rw-r--r--include/private/surface_control_private.h6
23 files changed, 1134 insertions, 330 deletions
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index b743f491e4..98f0eec8cc 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -39,6 +39,18 @@ struct AChoreographer;
*/
typedef struct AChoreographer AChoreographer;
+
+/**
+ * The identifier of a frame timeline.
+ */
+typedef int64_t AVsyncId;
+
+struct AChoreographerFrameCallbackData;
+/**
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ */
+typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
+
/**
* Prototype of the function that is called when a new frame is being rendered.
* It's passed the time that the frame is being rendered as nanoseconds in the
@@ -60,6 +72,14 @@ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data);
typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
/**
+ * Prototype of the function that is called when a new frame is being rendered.
+ * It's passed the frame data that should not outlive the callback, as well as the data pointer
+ * provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_extendedFrameCallback)(
+ const AChoreographerFrameCallbackData* callbackData, void* data);
+
+/**
* Prototype of the function that is called when the display refresh rate
* changes. It's passed the new vsync period in nanoseconds, as well as the data
* pointer provided by the application that registered a callback.
@@ -111,6 +131,14 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
uint32_t delayMillis) __INTRODUCED_IN(29);
/**
+ * Posts a callback to run on the next frame. The data pointer provided will
+ * be passed to the callback function when it's called.
+ */
+void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
+ AChoreographer_extendedFrameCallback callback, void* data)
+ __INTRODUCED_IN(33);
+
+/**
* Registers a callback to be run when the display refresh rate changes. The
* data pointer provided will be passed to the callback function when it's
* called. The same callback may be registered multiple times, provided that a
@@ -160,6 +188,42 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback, void* data)
__INTRODUCED_IN(30);
+/**
+ * The time in nanoseconds when the frame started being rendered.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The number of possible frame timelines.
+ */
+size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * Get index of the platform-preferred FrameTimeline.
+ */
+size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The vsync ID token used to map Choreographer data.
+ */
+AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index is expected to be presented.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index needs to be ready by.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/include/android/input.h b/include/android/input.h
index 76422154f1..fbd61b53f4 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -169,6 +169,9 @@ enum {
/** Drag event */
AINPUT_EVENT_TYPE_DRAG = 5,
+
+ /** TouchMode event */
+ AINPUT_EVENT_TYPE_TOUCH_MODE = 6,
};
/**
@@ -1382,6 +1385,17 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event);
*/
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
+/**
+ * Returns the AInputQueue* object associated with the supplied Java InputQueue
+ * object. The returned native object holds a weak reference to the Java object,
+ * and is only valid as long as the Java object has not yet been disposed. You
+ * should ensure that there is a strong reference to the Java object and that it
+ * has not been disposed before using the returned object.
+ *
+ * Available since API level 33.
+ */
+AInputQueue* AInputQueue_fromJava(JNIEnv* env, jobject inputQueue) __INTRODUCED_IN(33);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 9dc6983e50..45e8afc7de 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -256,6 +256,13 @@ enum {
* The hinge angle sensor value is returned in degrees.
*/
ASENSOR_TYPE_HINGE_ANGLE = 36,
+ /**
+ * {@link ASENSOR_TYPE_HEAD_TRACKER}
+ * reporting-mode: continuous
+ *
+ * Measures the orientation and rotational velocity of a user's head.
+ */
+ ASENSOR_TYPE_HEAD_TRACKER = 37,
};
/**
@@ -440,6 +447,38 @@ typedef struct AAdditionalInfoEvent {
};
} AAdditionalInfoEvent;
+typedef struct AHeadTrackerEvent {
+ /**
+ * The fields rx, ry, rz are an Euler vector (rotation vector, i.e. a vector
+ * whose direction indicates the axis of rotation and magnitude indicates
+ * the angle to rotate around that axis) representing the transform from
+ * the (arbitrary, possibly slowly drifting) reference frame to the
+ * head frame. Expressed in radians. Magnitude of the vector must be
+ * in the range [0, pi], while the value of individual axes are
+ * in the range [-pi, pi].
+ */
+ float rx;
+ float ry;
+ float rz;
+
+ /**
+ * The fields vx, vy, vz are an Euler vector (rotation vector) representing
+ * the angular velocity of the head (relative to itself), in radians per
+ * second. The direction of this vector indicates the axis of rotation, and
+ * the magnitude indicates the rate of rotation.
+ */
+ float vx;
+ float vy;
+ float vz;
+
+ /**
+ * This value changes each time the reference frame is suddenly and
+ * significantly changed, for example if an orientation filter algorithm
+ * used for determining the orientation has had its state reset.
+ */
+ int32_t discontinuity_count;
+} AHeadTrackerEvent;
+
/**
* Information that describes a sensor event, refer to
* <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
@@ -476,6 +515,7 @@ typedef struct ASensorEvent {
AHeartRateEvent heart_rate;
ADynamicSensorEvent dynamic_sensor_meta;
AAdditionalInfoEvent additional_info;
+ AHeadTrackerEvent head_tracker;
};
union {
uint64_t data[8];
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 059bc41f9a..9a36ecb537 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
+#include <android/choreographer.h>
#include <android/data_space.h>
#include <android/hardware_buffer.h>
#include <android/hdr_metadata.h>
@@ -595,6 +596,25 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction,
bool enableBackPressure)
__INTRODUCED_IN(31);
+/**
+ * Sets the frame timeline to use in Surface Flinger.
+ *
+ * A frame timeline should be chosen based on what frame deadline the application
+ * can meet when rendering the frame and the application's desired present time.
+ * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding
+ * expected present time.
+ *
+ * To receive frame timelines, a callback must be posted to Choreographer using
+ * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the
+ * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId().
+ *
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
+ * the corresponding expected present time and deadline from the frame to be rendered. A stale or
+ * invalid value will be ignored.
+ */
+void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
+ AVsyncId vsyncId) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h
index 27c84769cb..932af2d9f9 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/Flags.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,79 +14,22 @@
* limitations under the License.
*/
-#include <android-base/stringprintf.h>
+#pragma once
+
+#include <ftl/enum.h>
+#include <ftl/string.h>
-#include <array>
#include <cstdint>
-#include <optional>
+#include <iterator>
#include <string>
#include <type_traits>
-#include <ftl/NamedEnum.h>
#include "utils/BitSet.h"
-#pragma once
+// TODO(b/185536303): Align with FTL style and namespace.
namespace android {
-namespace details {
-
-template <typename F>
-inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__;
-
-template <typename F, typename T, T... I>
-constexpr auto generate_flag_values(std::integer_sequence<T, I...> seq) {
- constexpr size_t count = seq.size();
-
- std::array<F, count> values{};
- for (size_t i = 0, v = 0; v < count; ++i) {
- values[v++] = static_cast<F>(T{1} << i);
- }
-
- return values;
-}
-
-template <typename F>
-inline constexpr auto flag_values = generate_flag_values<F>(
- std::make_integer_sequence<std::underlying_type_t<F>, flag_count<F>>{});
-
-template <typename F, std::size_t... I>
-constexpr auto generate_flag_names(std::index_sequence<I...>) noexcept {
- return std::array<std::optional<std::string_view>, sizeof...(I)>{
- {enum_value_name<F, flag_values<F>[I]>()...}};
-}
-
-template <typename F>
-inline constexpr auto flag_names =
- generate_flag_names<F>(std::make_index_sequence<flag_count<F>>{});
-
-// A trait for determining whether a type is specifically an enum class or not.
-template <typename T, bool = std::is_enum_v<T>>
-struct is_enum_class : std::false_type {};
-
-// By definition, an enum class is an enum that is not implicitly convertible to its underlying
-// type.
-template <typename T>
-struct is_enum_class<T, true>
- : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
-
-template <typename T>
-inline constexpr bool is_enum_class_v = is_enum_class<T>::value;
-} // namespace details
-
-template <auto V>
-constexpr auto flag_name() {
- using F = decltype(V);
- return details::enum_value_name<F, V>();
-}
-
-template <typename F>
-constexpr std::optional<std::string_view> flag_name(F flag) {
- using U = std::underlying_type_t<F>;
- auto idx = static_cast<size_t>(__builtin_ctzl(static_cast<U>(flag)));
- return details::flag_names<F>[idx];
-}
-
/* A class for handling flags defined by an enum or enum class in a type-safe way. */
template <typename F>
class Flags {
@@ -94,7 +37,7 @@ class Flags {
// further to avoid this restriction but in general we want to encourage the use of enums
// anyways.
static_assert(std::is_enum_v<F>, "Flags type must be an enum");
- using U = typename std::underlying_type_t<F>;
+ using U = std::underlying_type_t<F>;
public:
constexpr Flags(F f) : mFlags(static_cast<U>(f)) {}
@@ -106,11 +49,10 @@ public:
// should force them to be explicitly constructed from their underlying types to make full use
// of the type checker.
template <typename T = U>
- constexpr Flags(T t, typename std::enable_if_t<!details::is_enum_class_v<F>, T>* = nullptr)
- : mFlags(t) {}
+ constexpr Flags(T t, std::enable_if_t<!ftl::is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
+
template <typename T = U>
- explicit constexpr Flags(T t,
- typename std::enable_if_t<details::is_enum_class_v<F>, T>* = nullptr)
+ explicit constexpr Flags(T t, std::enable_if_t<ftl::is_scoped_enum_v<F>, T>* = nullptr)
: mFlags(t) {}
class Iterator {
@@ -229,16 +171,16 @@ public:
bool first = true;
U unstringified = 0;
for (const F f : *this) {
- std::optional<std::string_view> flagString = flag_name(f);
- if (flagString) {
- appendFlag(result, flagString.value(), first);
+ if (const auto flagName = ftl::flag_name(f)) {
+ appendFlag(result, flagName.value(), first);
} else {
unstringified |= static_cast<U>(f);
}
}
if (unstringified != 0) {
- appendFlag(result, base::StringPrintf("0x%08x", unstringified), first);
+ constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex;
+ appendFlag(result, ftl::to_string(unstringified, radix), first);
}
if (first) {
@@ -265,15 +207,14 @@ private:
// as flags. In order to use these, add them via a `using namespace` declaration.
namespace flag_operators {
-template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>>
+template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
inline Flags<F> operator~(F f) {
- using U = typename std::underlying_type_t<F>;
- return static_cast<F>(~static_cast<U>(f));
+ return static_cast<F>(~ftl::to_underlying(f));
}
-template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>>
+
+template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
Flags<F> operator|(F lhs, F rhs) {
- using U = typename std::underlying_type_t<F>;
- return static_cast<F>(static_cast<U>(lhs) | static_cast<U>(rhs));
+ return static_cast<F>(ftl::to_underlying(lhs) | ftl::to_underlying(rhs));
}
} // namespace flag_operators
diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h
deleted file mode 100644
index 6e98feeb87..0000000000
--- a/include/ftl/NamedEnum.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/stringprintf.h>
-
-#include <array>
-#include <cstdint>
-#include <optional>
-#include <string>
-
-#pragma once
-
-namespace android {
-
-namespace details {
-template <typename E, E V>
-constexpr std::optional<std::string_view> enum_value_name() {
- // Should look something like (but all on one line):
- // std::optional<std::string_view>
- // android::details::enum_value_name()
- // [E = android::test::TestEnums, V = android::test::TestEnums::ONE]
- std::string_view view = __PRETTY_FUNCTION__;
- size_t templateStart = view.rfind("[");
- size_t templateEnd = view.rfind("]");
- if (templateStart == std::string::npos || templateEnd == std::string::npos) {
- return std::nullopt;
- }
-
- // Extract the template parameters without the enclosing braces.
- // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE
- view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
- size_t valStart = view.rfind("V = ");
- if (valStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Example (cont'd): V = android::test::TestEnums::ONE
- view = view.substr(valStart);
- // Check invalid enum values with cast, like V = (android::test::TestEnums)8.
- if (view.find('(') != std::string::npos) {
- return std::nullopt;
- }
- size_t nameStart = view.rfind("::");
- if (nameStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Chop off the initial "::"
- nameStart += 2;
- return view.substr(nameStart);
-}
-
-template <typename E, typename T, T... I>
-constexpr auto generate_enum_values(std::integer_sequence<T, I...> seq) {
- constexpr size_t count = seq.size();
-
- std::array<E, count> values{};
- for (size_t i = 0, v = 0; v < count; ++i) {
- values[v++] = static_cast<E>(T{0} + i);
- }
-
- return values;
-}
-
-template <typename E, std::size_t N>
-inline constexpr auto enum_values =
- generate_enum_values<E>(std::make_integer_sequence<std::underlying_type_t<E>, N>{});
-
-template <typename E, std::size_t N, std::size_t... I>
-constexpr auto generate_enum_names(std::index_sequence<I...>) noexcept {
- return std::array<std::optional<std::string_view>, sizeof...(I)>{
- {enum_value_name<E, enum_values<E, N>[I]>()...}};
-}
-
-template <typename E, std::size_t N>
-inline constexpr auto enum_names = generate_enum_names<E, N>(std::make_index_sequence<N>{});
-
-} // namespace details
-
-class NamedEnum {
-public:
- // By default allowed enum value range is 0 ~ 7.
- template <typename E>
- static constexpr size_t max = 8;
-
- template <auto V>
- static constexpr auto enum_name() {
- using E = decltype(V);
- return details::enum_value_name<E, V>();
- }
-
- template <typename E>
- static constexpr std::optional<std::string_view> enum_name(E val) {
- auto idx = static_cast<size_t>(val);
- return idx < max<E> ? details::enum_names<E, max<E>>[idx] : std::nullopt;
- }
-
- // Helper function for parsing enum value to string.
- // Example : enum class TestEnums { ZERO = 0x0 };
- // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO".
- // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16,
- // it should be declared to specialized the maximum enum by below:
- // template <> constexpr size_t NamedEnum::max<TestEnums> = 16;
- // If the enum class definition is sparse and contains enum values starting from a large value,
- // Do not specialize it to a large number to avoid performance issues.
- // The recommended maximum enum number to specialize is 64.
- template <typename E>
- static const std::string string(E val, const char* fallbackFormat = "%02d") {
- std::string result;
- std::optional<std::string_view> enumString = enum_name(val);
- result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val);
- return result;
- }
-};
-
-} // namespace android
diff --git a/include/ftl/cast.h b/include/ftl/cast.h
new file mode 100644
index 0000000000..ff1b58ad56
--- /dev/null
+++ b/include/ftl/cast.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <type_traits>
+
+#include <ftl/details/cast.h>
+
+namespace android::ftl {
+
+enum class CastSafety { kSafe, kUnderflow, kOverflow };
+
+// Returns whether static_cast<R>(v) is safe, or would result in underflow or overflow.
+//
+// static_assert(ftl::cast_safety<uint8_t>(-1) == ftl::CastSafety::kUnderflow);
+// static_assert(ftl::cast_safety<int8_t>(128u) == ftl::CastSafety::kOverflow);
+//
+// static_assert(ftl::cast_safety<uint32_t>(-.1f) == ftl::CastSafety::kUnderflow);
+// static_assert(ftl::cast_safety<int32_t>(static_cast<float>(INT32_MAX)) ==
+// ftl::CastSafety::kOverflow);
+//
+// static_assert(ftl::cast_safety<float>(-DBL_MAX) == ftl::CastSafety::kUnderflow);
+//
+template <typename R, typename T>
+constexpr CastSafety cast_safety(T v) {
+ static_assert(std::is_arithmetic_v<T>);
+ static_assert(std::is_arithmetic_v<R>);
+
+ constexpr bool kFromSigned = std::is_signed_v<T>;
+ constexpr bool kToSigned = std::is_signed_v<R>;
+
+ using details::max_exponent;
+
+ // If the R range contains the T range, then casting is always safe.
+ if constexpr ((kFromSigned == kToSigned && max_exponent<R> >= max_exponent<T>) ||
+ (!kFromSigned && kToSigned && max_exponent<R> > max_exponent<T>)) {
+ return CastSafety::kSafe;
+ }
+
+ using C = std::common_type_t<R, T>;
+
+ if constexpr (kFromSigned) {
+ using L = details::safe_limits<R, T>;
+
+ if constexpr (kToSigned) {
+ // Signed to signed.
+ if (v < L::lowest()) return CastSafety::kUnderflow;
+ return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow;
+ } else {
+ // Signed to unsigned.
+ if (v < 0) return CastSafety::kUnderflow;
+ return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe
+ : CastSafety::kOverflow;
+ }
+ } else {
+ using L = std::numeric_limits<R>;
+
+ if constexpr (kToSigned) {
+ // Unsigned to signed.
+ return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe
+ : CastSafety::kOverflow;
+ } else {
+ // Unsigned to unsigned.
+ return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow;
+ }
+ }
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/concat.h b/include/ftl/concat.h
new file mode 100644
index 0000000000..ded48f7c8c
--- /dev/null
+++ b/include/ftl/concat.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ftl/details/concat.h>
+
+namespace android::ftl {
+
+// Lightweight (not allocating nor sprintf-based) concatenation.
+//
+// std::string_view name = "Volume";
+// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB");
+//
+// assert(string.str() == "Vol: -3 dB");
+// assert(string.c_str()[string.size()] == '\0');
+//
+template <std::size_t, typename... Ts>
+struct Concat;
+
+template <std::size_t N, typename T, typename... Ts>
+struct Concat<N, T, Ts...> : Concat<N + details::StaticString<T>::N, Ts...> {
+ explicit constexpr Concat(T v, Ts... args) { append(v, args...); }
+
+ protected:
+ constexpr Concat() = default;
+
+ constexpr void append(T v, Ts... args) {
+ using Str = details::StaticString<T>;
+ const Str str(v);
+
+ // TODO: Replace with constexpr std::copy in C++20.
+ for (auto it = str.view.begin(); it != str.view.end();) {
+ *this->end_++ = *it++;
+ }
+
+ using Base = Concat<N + Str::N, Ts...>;
+ this->Base::append(args...);
+ }
+};
+
+template <std::size_t N>
+struct Concat<N> {
+ static constexpr std::size_t max_size() { return N; }
+ constexpr std::size_t size() const { return end_ - buffer_; }
+
+ constexpr const char* c_str() const { return buffer_; }
+
+ constexpr std::string_view str() const {
+ // TODO: Replace with {buffer_, end_} in C++20.
+ return {buffer_, size()};
+ }
+
+ protected:
+ constexpr Concat() : end_(buffer_) {}
+ constexpr void append() { *end_ = '\0'; }
+
+ char buffer_[N + 1];
+ char* end_;
+};
+
+// Deduction guide.
+template <typename... Ts>
+Concat(Ts&&...) -> Concat<0, Ts...>;
+
+template <std::size_t N>
+constexpr auto truncated(std::string_view v) {
+ return details::Truncated<N>{v};
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/array_traits.h b/include/ftl/details/array_traits.h
index 1265fa15fe..16e63eca74 100644
--- a/include/ftl/array_traits.h
+++ b/include/ftl/details/array_traits.h
@@ -21,9 +21,9 @@
#include <new>
#include <type_traits>
-#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U
+#define FTL_ARRAY_TRAIT(T, U) using U = typename details::ArrayTraits<T>::U
-namespace android::ftl {
+namespace android::ftl::details {
template <typename T>
struct ArrayTraits {
@@ -132,4 +132,4 @@ struct ArrayComparators {
}
};
-} // namespace android::ftl
+} // namespace android::ftl::details
diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h
new file mode 100644
index 0000000000..87b9f1e20a
--- /dev/null
+++ b/include/ftl/details/cast.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <type_traits>
+
+namespace android::ftl::details {
+
+// Exponent whose power of 2 is the (exclusive) upper bound of T.
+template <typename T, typename L = std::numeric_limits<T>>
+constexpr int max_exponent = std::is_floating_point_v<T> ? L::max_exponent : L::digits;
+
+// Extension of std::numeric_limits<T> that reduces the maximum for integral types T such that it
+// has an exact representation for floating-point types F. For example, the maximum int32_t value
+// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot
+// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is
+// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the
+// minimum is representable.
+template <typename T, typename F>
+struct safe_limits : std::numeric_limits<T> {
+ static constexpr T max() {
+ using Base = std::numeric_limits<T>;
+
+ if constexpr (std::is_integral_v<T> && std::is_floating_point_v<F>) {
+ // Assume the mantissa is 24 bits for float, or 53 bits for double.
+ using Float = std::numeric_limits<F>;
+ static_assert(Float::is_iec559);
+
+ // If the integer is wider than the mantissa, clear the excess bits of precision.
+ constexpr int kShift = Base::digits - Float::digits;
+ if constexpr (kShift > 0) {
+ using U = std::make_unsigned_t<T>;
+ constexpr U kOne = static_cast<U>(1);
+ return static_cast<U>(Base::max()) & ~((kOne << kShift) - kOne);
+ }
+ }
+
+ return Base::max();
+ }
+};
+
+} // namespace android::ftl::details
diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h
new file mode 100644
index 0000000000..8ce949ef05
--- /dev/null
+++ b/include/ftl/details/concat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <string_view>
+
+#include <ftl/string.h>
+
+namespace android::ftl::details {
+
+template <typename T, typename = void>
+struct StaticString;
+
+template <typename T>
+struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> {
+ static constexpr std::size_t N = to_chars_length_v<T>;
+
+ explicit StaticString(T v) : view(to_chars(buffer, v)) {}
+
+ to_chars_buffer_t<T> buffer;
+ const std::string_view view;
+};
+
+template <std::size_t M>
+struct StaticString<const char (&)[M], void> {
+ static constexpr std::size_t N = M - 1;
+
+ explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {}
+
+ const std::string_view view;
+};
+
+template <std::size_t N>
+struct Truncated {
+ std::string_view view;
+};
+
+template <std::size_t M>
+struct StaticString<Truncated<M>, void> {
+ static constexpr std::size_t N = M;
+
+ explicit constexpr StaticString(Truncated<M> str) : view(str.view.substr(0, N)) {}
+
+ const std::string_view view;
+};
+
+} // namespace android::ftl::details
diff --git a/include/ftl/enum.h b/include/ftl/enum.h
new file mode 100644
index 0000000000..5234c051b1
--- /dev/null
+++ b/include/ftl/enum.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <limits>
+#include <optional>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+#include <ftl/string.h>
+
+// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> by parsing the
+// compiler-generated string literal for the signature of this function. The function is defined in
+// the global namespace with a short name and inferred return type to reduce bloat in the read-only
+// data segment.
+template <typename E, E V>
+constexpr auto ftl_enum() {
+ static_assert(std::is_enum_v<E>);
+
+ using R = std::optional<std::string_view>;
+ using namespace std::literals;
+
+ // The "pretty" signature has the following format:
+ //
+ // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue]
+ //
+ std::string_view view = __PRETTY_FUNCTION__;
+ const auto template_begin = view.rfind('[');
+ const auto template_end = view.rfind(']');
+ if (template_begin == view.npos || template_end == view.npos) return R{};
+
+ // Extract the template parameters without the enclosing brackets. Example (cont'd):
+ //
+ // E = android::test::Enum, V = android::test::Enum::kValue
+ //
+ view = view.substr(template_begin + 1, template_end - template_begin - 1);
+ const auto value_begin = view.rfind("V = "sv);
+ if (value_begin == view.npos) return R{};
+
+ // Example (cont'd):
+ //
+ // V = android::test::Enum::kValue
+ //
+ view = view.substr(value_begin);
+ const auto name_begin = view.rfind("::"sv);
+ if (name_begin == view.npos) return R{};
+
+ // Chop off the leading "::".
+ const auto name = view.substr(name_begin + 2);
+
+ // A value that is not enumerated has the format "Enum)42".
+ return name.find(')') == view.npos ? R{name} : R{};
+}
+
+namespace android::ftl {
+
+// Trait for determining whether a type is specifically a scoped enum or not. By definition, a
+// scoped enum is one that is not implicitly convertible to its underlying type.
+//
+// TODO: Replace with std::is_scoped_enum in C++23.
+//
+template <typename T, bool = std::is_enum_v<T>>
+struct is_scoped_enum : std::false_type {};
+
+template <typename T>
+struct is_scoped_enum<T, true> : std::negation<std::is_convertible<T, std::underlying_type_t<T>>> {
+};
+
+template <typename T>
+inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value;
+
+// Shorthand for casting an enumerator to its integral value.
+//
+// TODO: Replace with std::to_underlying in C++23.
+//
+// enum class E { A, B, C };
+// static_assert(ftl::to_underlying(E::B) == 1);
+//
+template <typename E>
+constexpr auto to_underlying(E v) {
+ return static_cast<std::underlying_type_t<E>>(v);
+}
+
+// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named
+// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1
+// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the
+// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of-
+// range values results in undefined behavior if the underlying type is not fixed.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// static_assert(ftl::enum_begin_v<E> == E::A);
+// static_assert(ftl::enum_last_v<E> == E::F);
+// static_assert(ftl::enum_size_v<E> == 6);
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// static_assert(ftl::enum_begin_v<F> == F{0});
+// static_assert(ftl::enum_last_v<F> == F{15});
+// static_assert(ftl::enum_size_v<F> == 16);
+//
+template <typename E, typename = void>
+struct enum_begin {
+ static_assert(is_scoped_enum_v<E>, "Missing ftl_first enumerator");
+ static constexpr E value{0};
+};
+
+template <typename E>
+struct enum_begin<E, std::void_t<decltype(E::ftl_first)>> {
+ static constexpr E value = E::ftl_first;
+};
+
+template <typename E>
+inline constexpr E enum_begin_v = enum_begin<E>::value;
+
+template <typename E, typename = void>
+struct enum_end {
+ using U = std::underlying_type_t<E>;
+ static_assert(is_scoped_enum_v<E> && std::is_unsigned_v<U>, "Missing ftl_last enumerator");
+
+ static constexpr E value{std::numeric_limits<U>::digits};
+};
+
+template <typename E>
+struct enum_end<E, std::void_t<decltype(E::ftl_last)>> {
+ static constexpr E value = E{to_underlying(E::ftl_last) + 1};
+};
+
+template <typename E>
+inline constexpr E enum_end_v = enum_end<E>::value;
+
+template <typename E>
+inline constexpr E enum_last_v = E{to_underlying(enum_end_v<E>) - 1};
+
+template <typename E>
+struct enum_size {
+ static constexpr auto kBegin = to_underlying(enum_begin_v<E>);
+ static constexpr auto kEnd = to_underlying(enum_end_v<E>);
+ static_assert(kBegin < kEnd, "Invalid range");
+
+ static constexpr std::size_t value = kEnd - kBegin;
+ static_assert(value <= 64, "Excessive range size");
+};
+
+template <typename E>
+inline constexpr std::size_t enum_size_v = enum_size<E>::value;
+
+namespace details {
+
+template <auto V>
+struct Identity {
+ static constexpr auto value = V;
+};
+
+template <typename E>
+using make_enum_sequence = std::make_integer_sequence<std::underlying_type_t<E>, enum_size_v<E>>;
+
+template <typename E, template <E> class = Identity, typename = make_enum_sequence<E>>
+struct EnumRange;
+
+template <typename E, template <E> class F, typename T, T... Vs>
+struct EnumRange<E, F, std::integer_sequence<T, Vs...>> {
+ static constexpr auto kBegin = to_underlying(enum_begin_v<E>);
+ static constexpr auto kSize = enum_size_v<E>;
+
+ using R = decltype(F<E{}>::value);
+ const R values[kSize] = {F<static_cast<E>(Vs + kBegin)>::value...};
+
+ constexpr const auto* begin() const { return values; }
+ constexpr const auto* end() const { return values + kSize; }
+};
+
+template <auto V>
+struct EnumName {
+ static constexpr auto value = ftl_enum<decltype(V), V>();
+};
+
+template <auto I>
+struct FlagName {
+ using E = decltype(I);
+ using U = std::underlying_type_t<E>;
+
+ static constexpr E V{U{1} << to_underlying(I)};
+ static constexpr auto value = ftl_enum<E, V>();
+};
+
+} // namespace details
+
+// Returns an iterable over the range of an enum.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// std::string string;
+// for (E v : ftl::enum_range<E>()) {
+// string += ftl::enum_name(v).value_or("?");
+// }
+//
+// assert(string == "ABC??F");
+//
+template <typename E>
+constexpr auto enum_range() {
+ return details::EnumRange<E>{};
+}
+
+// Returns a stringified enumerator at compile time.
+//
+// enum class E { A, B, C };
+// static_assert(ftl::enum_name<E::B>() == "B");
+//
+template <auto V>
+constexpr std::string_view enum_name() {
+ constexpr auto kName = ftl_enum<decltype(V), V>();
+ static_assert(kName, "Unknown enumerator");
+ return *kName;
+}
+
+// Returns a stringified enumerator, possibly at compile time.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// static_assert(ftl::enum_name(E::C).value_or("?") == "C");
+// static_assert(ftl::enum_name(E{3}).value_or("?") == "?");
+//
+template <typename E>
+constexpr std::optional<std::string_view> enum_name(E v) {
+ const auto value = to_underlying(v);
+
+ constexpr auto kBegin = to_underlying(enum_begin_v<E>);
+ constexpr auto kLast = to_underlying(enum_last_v<E>);
+ if (value < kBegin || value > kLast) return {};
+
+ constexpr auto kRange = details::EnumRange<E, details::EnumName>{};
+ return kRange.values[value - kBegin];
+}
+
+// Returns a stringified flag enumerator, possibly at compile time.
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z");
+// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?");
+//
+template <typename E>
+constexpr std::optional<std::string_view> flag_name(E v) {
+ const auto value = to_underlying(v);
+
+ // TODO: Replace with std::popcount and std::countr_zero in C++20.
+ if (__builtin_popcountl(value) != 1) return {};
+
+ constexpr auto kRange = details::EnumRange<E, details::FlagName>{};
+ return kRange.values[__builtin_ctzl(value)];
+}
+
+// Returns a stringified enumerator, or its integral value if not named.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// assert(ftl::enum_string(E::C) == "C");
+// assert(ftl::enum_string(E{3}) == "3");
+//
+template <typename E>
+inline std::string enum_string(E v) {
+ if (const auto name = enum_name(v)) {
+ return std::string(*name);
+ }
+ return to_string(to_underlying(v));
+}
+
+// Returns a stringified flag enumerator, or its integral value if not named.
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// assert(ftl::flag_string(F::Z) == "Z");
+// assert(ftl::flag_string(F{7}) == "0b111");
+//
+template <typename E>
+inline std::string flag_string(E v) {
+ if (const auto name = flag_name(v)) {
+ return std::string(*name);
+ }
+ constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex;
+ return to_string(to_underlying(v), radix);
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h
index 769c09ff11..2102c253f1 100644
--- a/include/ftl/initializer_list.h
+++ b/include/ftl/initializer_list.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <tuple>
#include <utility>
@@ -65,18 +66,18 @@ struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
std::tuple<Types...> tuple;
};
-template <typename K, typename V>
+template <typename K, typename V, typename KeyEqual = std::equal_to<K>>
struct KeyValue {};
// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
// with the latter.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
+template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
+struct InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...> {
// Accumulate the three arguments to std::pair's piecewise constructor.
template <typename... Args>
[[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
- KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
+ KeyValue<K, V, E>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
std::tuple<K&&>, std::tuple<Args&&...>> {
return {std::tuple_cat(
std::move(tuple),
@@ -94,9 +95,9 @@ template <typename T, typename... Args>
return InitializerList<T>{}(std::forward<Args>(args)...);
}
-template <typename K, typename V, typename... Args>
+template <typename K, typename V, typename E = std::equal_to<K>, typename... Args>
[[nodiscard]] constexpr auto map(Args&&... args) {
- return list<KeyValue<K, V>>(std::forward<Args>(args)...);
+ return list<KeyValue<K, V, E>>(std::forward<Args>(args)...);
}
template <typename K, typename V>
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 84c15ebdca..2effaa437c 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -19,6 +19,7 @@
#include <ftl/initializer_list.h>
#include <ftl/small_vector.h>
+#include <algorithm>
#include <functional>
#include <optional>
#include <type_traits>
@@ -28,7 +29,10 @@ namespace android::ftl {
// Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are
// stored in contiguous storage for cache efficiency. The map is allocated statically until its size
-// exceeds N, at which point mappings are relocated to dynamic memory.
+// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has
+// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place
+// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator,
+// but immutable getters that can optionally transform the value.
//
// SmallMap<K, V, 0> unconditionally allocates on the heap.
//
@@ -43,18 +47,21 @@ namespace android::ftl {
// assert(!map.dynamic());
//
// assert(map.contains(123));
-// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u);
+// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u);
//
-// const auto opt = map.find(-1);
+// const auto opt = map.get(-1);
// assert(opt);
//
// std::string& ref = *opt;
// assert(ref.empty());
// ref = "xyz";
//
-// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+// map.emplace_or_replace(0, "vanilla", 2u, 3u);
+// assert(map.dynamic());
//
-template <typename K, typename V, std::size_t N>
+// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc")));
+//
+template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>>
class SmallMap final {
using Map = SmallVector<std::pair<const K, V>, N>;
@@ -80,12 +87,7 @@ class SmallMap final {
// The syntax for listing pairs is as follows:
//
// ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
- //
// static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>);
- // assert(map.size() == 3u);
- // assert(map.contains(-1) && map.find(-1)->get().empty());
- // assert(map.contains(42) && map.find(42)->get() == "???");
- // assert(map.contains(123) && map.find(123)->get() == "abc");
//
// The types of the key and value are deduced if the first pair contains exactly two arguments:
//
@@ -95,7 +97,7 @@ class SmallMap final {
template <typename U, std::size_t... Sizes, typename... Types>
SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
: map_(std::move(list)) {
- // TODO: Enforce unique keys.
+ deduplicate();
}
size_type max_size() const { return map_.max_size(); }
@@ -115,27 +117,27 @@ class SmallMap final {
// Returns whether a mapping exists for the given key.
bool contains(const key_type& key) const {
- return find(key, [](const mapped_type&) {});
+ return get(key, [](const mapped_type&) {});
}
// Returns a reference to the value for the given key, or std::nullopt if the key was not found.
//
// ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
//
- // const auto opt = map.find('c');
+ // const auto opt = map.get('c');
// assert(opt == 'C');
//
// char d = 'd';
- // const auto ref = map.find('d').value_or(std::ref(d));
+ // const auto ref = map.get('d').value_or(std::ref(d));
// ref.get() = 'D';
// assert(d == 'D');
//
- auto find(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
- return find(key, [](const mapped_type& v) { return std::cref(v); });
+ auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
+ return get(key, [](const mapped_type& v) { return std::cref(v); });
}
- auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
- return find(key, [](mapped_type& v) { return std::ref(v); });
+ auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
+ return get(key, [](mapped_type& v) { return std::ref(v); });
}
// Returns the result R of a unary operation F on (a constant or mutable reference to) the value
@@ -144,14 +146,14 @@ class SmallMap final {
//
// ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
//
- // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z');
- // assert(map.find('c', [](char& c) { c = std::toupper(c); }));
+ // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z');
+ // assert(map.get('c', [](char& c) { c = std::toupper(c); }));
//
template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>>
- auto find(const key_type& key, F f) const
+ auto get(const key_type& key, F f) const
-> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
for (auto& [k, v] : *this) {
- if (k == key) {
+ if (KeyEqual{}(k, key)) {
if constexpr (std::is_void_v<R>) {
f(v);
return true;
@@ -165,28 +167,119 @@ class SmallMap final {
}
template <typename F>
- auto find(const key_type& key, F f) {
- return std::as_const(*this).find(
+ auto get(const key_type& key, F f) {
+ return std::as_const(*this).get(
key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); });
}
+ // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise.
+ const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); }
+ iterator find(const key_type& key) { return find(key, begin()); }
+
+ // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping,
+ // and whether the mapping was inserted.
+ //
+ // On emplace, if the map reaches its static or dynamic capacity, then all iterators are
+ // invalidated. Otherwise, only the end() iterator is invalidated.
+ //
+ template <typename... Args>
+ std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
+ if (const auto it = find(key); it != end()) {
+ return {it, false};
+ }
+
+ auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return {&ref, true};
+ }
+
+ // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator
+ // otherwise.
+ //
+ // The value is replaced via move constructor, so type V does not need to define copy/move
+ // assignment, e.g. its data members may be const.
+ //
+ // The arguments may directly or indirectly refer to the mapping being replaced.
+ //
+ // Iterators to the replaced mapping point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ iterator try_replace(const key_type& key, Args&&... args) {
+ const auto it = find(key);
+ if (it == end()) return it;
+ map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return it;
+ }
+
+ // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or
+ // false on replace.
+ //
+ // The value is emplaced and replaced via move constructor, so type V does not need to define
+ // copy/move assignment, e.g. its data members may be const.
+ //
+ // On emplace, if the map reaches its static or dynamic capacity, then all iterators are
+ // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators
+ // to the replaced mapping point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ std::pair<iterator, bool> emplace_or_replace(const key_type& key, Args&&... args) {
+ const auto [it, ok] = try_emplace(key, std::forward<Args>(args)...);
+ if (ok) return {it, ok};
+ map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return {it, ok};
+ }
+
+ // Removes a mapping if it exists, and returns whether it did.
+ //
+ // The last() and end() iterators, as well as those to the erased mapping, are invalidated.
+ //
+ bool erase(const key_type& key) { return erase(key, begin()); }
+
+ // Removes all mappings.
+ //
+ // All iterators are invalidated.
+ //
+ void clear() { map_.clear(); }
+
private:
+ iterator find(const key_type& key, iterator first) {
+ return std::find_if(first, end(),
+ [&key](const auto& pair) { return KeyEqual{}(pair.first, key); });
+ }
+
+ bool erase(const key_type& key, iterator first) {
+ const auto it = find(key, first);
+ if (it == end()) return false;
+ map_.unstable_erase(it);
+ return true;
+ }
+
+ void deduplicate() {
+ for (auto it = begin(); it != end();) {
+ if (const auto key = it->first; ++it != end()) {
+ while (erase(key, it));
+ }
+ }
+ }
+
Map map_;
};
// Deduction guide for in-place constructor.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
- -> SmallMap<K, V, sizeof...(Sizes)>;
+template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
+SmallMap(InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallMap<K, V, sizeof...(Sizes), E>;
// Returns whether the key-value pairs of two maps are equal.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
+bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
if (lhs.size() != rhs.size()) return false;
for (const auto& [k, v] : lhs) {
const auto& lv = v;
- if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
+ if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
return false;
}
}
@@ -195,8 +288,8 @@ bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
}
// TODO: Remove in C++20.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
+inline bool operator!=(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
return !(lhs == rhs);
}
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index cb0ae359eb..03587e35ac 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -16,7 +16,7 @@
#pragma once
-#include <ftl/array_traits.h>
+#include <ftl/details/array_traits.h>
#include <ftl/static_vector.h>
#include <algorithm>
@@ -73,7 +73,7 @@ struct is_small_vector;
// assert(strings[2] == "???");
//
template <typename T, std::size_t N>
-class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
+class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<SmallVector> {
using Static = StaticVector<T, N>;
using Dynamic = SmallVector<T, 0>;
@@ -151,8 +151,6 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
DISPATCH(reference, back, noexcept)
DISPATCH(const_reference, back, const)
-#undef DISPATCH
-
reference operator[](size_type i) {
return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i];
}
@@ -214,13 +212,15 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
//
// The last() and end() iterators are invalidated.
//
- void pop_back() {
- if (dynamic()) {
- std::get<Dynamic>(vector_).pop_back();
- } else {
- std::get<Static>(vector_).pop_back();
- }
- }
+ DISPATCH(void, pop_back, noexcept)
+
+ // Removes all elements.
+ //
+ // All iterators are invalidated.
+ //
+ DISPATCH(void, clear, noexcept)
+
+#undef DISPATCH
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
@@ -266,12 +266,12 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
// Partial specialization without static storage.
template <typename T>
-class SmallVector<T, 0> final : ArrayTraits<T>,
- ArrayIterators<SmallVector<T, 0>, T>,
+class SmallVector<T, 0> final : details::ArrayTraits<T>,
+ details::ArrayIterators<SmallVector<T, 0>, T>,
std::vector<T> {
- using ArrayTraits<T>::construct_at;
+ using details::ArrayTraits<T>::construct_at;
- using Iter = ArrayIterators<SmallVector, T>;
+ using Iter = details::ArrayIterators<SmallVector, T>;
using Impl = std::vector<T>;
friend Iter;
@@ -345,10 +345,11 @@ class SmallVector<T, 0> final : ArrayTraits<T>,
return true;
}
+ using Impl::clear;
using Impl::pop_back;
void unstable_erase(iterator it) {
- if (it != last()) std::iter_swap(it, last());
+ if (it != last()) replace(it, std::move(back()));
pop_back();
}
diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h
index 96a1ae853d..b7f8c29dec 100644
--- a/include/ftl/static_vector.h
+++ b/include/ftl/static_vector.h
@@ -16,7 +16,7 @@
#pragma once
-#include <ftl/array_traits.h>
+#include <ftl/details/array_traits.h>
#include <ftl/initializer_list.h>
#include <algorithm>
@@ -73,14 +73,14 @@ constexpr struct IteratorRangeTag {
// assert(strings[2] == "???");
//
template <typename T, std::size_t N>
-class StaticVector final : ArrayTraits<T>,
- ArrayIterators<StaticVector<T, N>, T>,
- ArrayComparators<StaticVector> {
+class StaticVector final : details::ArrayTraits<T>,
+ details::ArrayIterators<StaticVector<T, N>, T>,
+ details::ArrayComparators<StaticVector> {
static_assert(N > 0);
- using ArrayTraits<T>::construct_at;
+ using details::ArrayTraits<T>::construct_at;
- using Iter = ArrayIterators<StaticVector, T>;
+ using Iter = details::ArrayIterators<StaticVector, T>;
friend Iter;
// There is ambiguity when constructing from two iterator-like elements like pointers:
@@ -189,8 +189,7 @@ class StaticVector final : ArrayTraits<T>,
}
StaticVector& operator=(StaticVector&& other) {
- std::destroy(begin(), end());
- size_ = 0;
+ clear();
swap<true>(other);
return *this;
}
@@ -280,6 +279,15 @@ class StaticVector final : ArrayTraits<T>,
//
void pop_back() { unstable_erase(last()); }
+ // Removes all elements.
+ //
+ // All iterators are invalidated.
+ //
+ void clear() {
+ std::destroy(begin(), end());
+ size_ = 0;
+ }
+
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
//
diff --git a/include/ftl/string.h b/include/ftl/string.h
new file mode 100644
index 0000000000..2d96b06a2f
--- /dev/null
+++ b/include/ftl/string.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <charconv>
+#include <limits>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+namespace android::ftl {
+
+enum class Radix { kBin = 2, kDec = 10, kHex = 16 };
+
+template <typename T>
+struct to_chars_length {
+ static_assert(std::is_integral_v<T>);
+ // Maximum binary digits, plus minus sign and radix prefix.
+ static constexpr std::size_t value = std::numeric_limits<std::make_unsigned_t<T>>::digits + 3;
+};
+
+template <typename T>
+constexpr std::size_t to_chars_length_v = to_chars_length<T>::value;
+
+template <typename T = std::int64_t>
+using to_chars_buffer_t = char[to_chars_length_v<T>];
+
+// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with
+// optional radix. See also ftl::to_string below.
+//
+// ftl::to_chars_buffer_t<> buffer;
+//
+// assert(ftl::to_chars(buffer, 123u) == "123");
+// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010");
+// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe");
+// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a");
+//
+template <typename T, std::size_t N>
+std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) {
+ static_assert(N >= to_chars_length_v<T>);
+
+ auto begin = buffer + 2;
+ const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast<int>(radix));
+ assert(err == std::errc());
+
+ if (radix == Radix::kDec) {
+ // TODO: Replace with {begin, end} in C++20.
+ return {begin, static_cast<std::size_t>(end - begin)};
+ }
+
+ const auto prefix = radix == Radix::kBin ? 'b' : 'x';
+ if constexpr (std::is_unsigned_v<T>) {
+ buffer[0] = '0';
+ buffer[1] = prefix;
+ } else {
+ if (*begin == '-') {
+ *buffer = '-';
+ } else {
+ --begin;
+ }
+
+ *begin-- = prefix;
+ *begin = '0';
+ }
+
+ // TODO: Replace with {buffer, end} in C++20.
+ return {buffer, static_cast<std::size_t>(end - buffer)};
+}
+
+// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix.
+//
+// assert(ftl::to_string(123u) == "123");
+// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010");
+// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe");
+// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a");
+//
+template <typename T>
+inline std::string to_string(T v, Radix radix = Radix::kDec) {
+ to_chars_buffer_t<T> buffer;
+ return std::string(to_chars(buffer, v, radix));
+}
+
+std::string to_string(bool) = delete;
+std::string to_string(bool, Radix) = delete;
+
+} // namespace android::ftl
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index a6213f3ddd..9148fee532 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -18,7 +18,8 @@
#define _LIBINPUT_DISPLAY_VIEWPORT_H
#include <android-base/stringprintf.h>
-#include <ftl/NamedEnum.h>
+#include <ftl/enum.h>
+#include <ftl/string.h>
#include <gui/constants.h>
#include <input/Input.h>
@@ -44,6 +45,8 @@ enum class ViewportType : int32_t {
INTERNAL = 1,
EXTERNAL = 2,
VIRTUAL = 3,
+
+ ftl_last = VIRTUAL
};
/*
@@ -132,9 +135,8 @@ struct DisplayViewport {
"physicalFrame=[%d, %d, %d, %d], "
"deviceSize=[%d, %d], "
"isActive=[%d]",
- NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(),
- physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str()
- : "<none>",
+ ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(),
+ physicalPort ? ftl::to_string(*physicalPort).c_str() : "<none>",
orientation, logicalLeft, logicalTop, logicalRight, logicalBottom,
physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth,
deviceHeight, isActive);
diff --git a/include/input/Input.h b/include/input/Input.h
index 4adaa5b1c5..f4147a0409 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -31,10 +31,8 @@
#include <stdint.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
-#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include <utils/Vector.h>
#include <array>
#include <limits>
#include <queue>
@@ -88,7 +86,7 @@ enum {
*/
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
-#ifdef __linux__
+#if defined(__linux__)
/**
* This event was generated or modified by accessibility service.
*/
@@ -201,8 +199,17 @@ namespace android {
class Parcel;
#endif
+/*
+ * Apply the given transform to the point without applying any translation/offset.
+ */
+vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy);
+
const char* inputEventTypeToString(int32_t type);
+std::string inputEventSourceToString(int32_t source);
+
+bool isFromSource(uint32_t source, uint32_t test);
+
/*
* Flags that flow alongside events in the input dispatch system to help with certain
* policy decisions such as waking from device sleep.
@@ -369,13 +376,10 @@ struct PointerCoords {
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- void scale(float globalScale);
-
// Scale the pointer coordinates according to a global scale and a
// window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
// axes, however the window scaling will not.
void scale(float globalScale, float windowXScale, float windowYScale);
- void applyOffset(float xOffset, float yOffset);
void transform(const ui::Transform& transform);
@@ -526,13 +530,17 @@ public:
inline int32_t getAction() const { return mAction; }
- inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
+ static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; }
- inline int32_t getActionIndex() const {
- return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
- >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ inline int32_t getActionMasked() const { return getActionMasked(mAction); }
+
+ static int32_t getActionIndex(int32_t action) {
+ return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
+ AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
+ inline int32_t getActionIndex() const { return getActionIndex(mAction); }
+
inline void setAction(int32_t action) { mAction = action; }
inline int32_t getFlags() const { return mFlags; }
@@ -561,7 +569,9 @@ public:
inline float getYOffset() const { return mTransform.ty(); }
- inline ui::Transform getTransform() const { return mTransform; }
+ inline const ui::Transform& getTransform() const { return mTransform; }
+
+ int getSurfaceRotation() const;
inline float getXPrecision() const { return mXPrecision; }
@@ -577,9 +587,7 @@ public:
void setCursorPosition(float x, float y);
- uint32_t getDisplayOrientation() const { return mDisplayOrientation; }
-
- int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
+ inline const ui::Transform& getRawTransform() const { return mRawTransform; }
static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
@@ -755,8 +763,8 @@ public:
int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float rawXCursorPosition,
- float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth,
- int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+ float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime,
+ nsecs_t eventTime, size_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -789,11 +797,11 @@ public:
// Low-level accessors.
inline const PointerProperties* getPointerProperties() const {
- return mPointerProperties.array();
+ return mPointerProperties.data();
}
inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); }
inline const PointerCoords* getSamplePointerCoords() const {
- return mSamplePointerCoords.array();
+ return mSamplePointerCoords.data();
}
static const char* getLabel(int32_t axis);
@@ -801,6 +809,14 @@ public:
static std::string actionToString(int32_t action);
+ // MotionEvent will transform various axes in different ways, based on the source. For
+ // example, the x and y axes will not have any offsets/translations applied if it comes from a
+ // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods
+ // are used to apply these transformations for different axes.
+ static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
+ static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
+ const PointerCoords&);
+
protected:
int32_t mAction;
int32_t mActionButton;
@@ -814,13 +830,11 @@ protected:
float mYPrecision;
float mRawXCursorPosition;
float mRawYCursorPosition;
- uint32_t mDisplayOrientation;
- int32_t mDisplayWidth;
- int32_t mDisplayHeight;
+ ui::Transform mRawTransform;
nsecs_t mDownTime;
- Vector<PointerProperties> mPointerProperties;
+ std::vector<PointerProperties> mPointerProperties;
std::vector<nsecs_t> mSampleEventTimes;
- Vector<PointerCoords> mSamplePointerCoords;
+ std::vector<PointerCoords> mSamplePointerCoords;
};
/*
@@ -834,15 +848,12 @@ public:
inline bool getHasFocus() const { return mHasFocus; }
- inline bool getInTouchMode() const { return mInTouchMode; }
-
- void initialize(int32_t id, bool hasFocus, bool inTouchMode);
+ void initialize(int32_t id, bool hasFocus);
void initialize(const FocusEvent& from);
protected:
bool mHasFocus;
- bool mInTouchMode;
};
/*
@@ -888,6 +899,25 @@ protected:
float mX, mY;
};
+/*
+ * Touch mode events.
+ */
+class TouchModeEvent : public InputEvent {
+public:
+ virtual ~TouchModeEvent() {}
+
+ virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_TOUCH_MODE; }
+
+ inline bool isInTouchMode() const { return mIsInTouchMode; }
+
+ void initialize(int32_t id, bool isInTouchMode);
+
+ void initialize(const TouchModeEvent& from);
+
+protected:
+ bool mIsInTouchMode;
+};
+
/**
* Base class for verified events.
* Do not create a VerifiedInputEvent explicitly.
@@ -912,8 +942,8 @@ struct __attribute__((__packed__)) VerifiedInputEvent {
*/
struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent {
int32_t action;
- nsecs_t downTimeNanos;
int32_t flags;
+ nsecs_t downTimeNanos;
int32_t keyCode;
int32_t scanCode;
int32_t metaState;
@@ -928,8 +958,8 @@ struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEve
float rawX;
float rawY;
int32_t actionMasked;
- nsecs_t downTimeNanos;
int32_t flags;
+ nsecs_t downTimeNanos;
int32_t metaState;
int32_t buttonState;
};
@@ -952,6 +982,7 @@ public:
virtual FocusEvent* createFocusEvent() = 0;
virtual CaptureEvent* createCaptureEvent() = 0;
virtual DragEvent* createDragEvent() = 0;
+ virtual TouchModeEvent* createTouchModeEvent() = 0;
};
/*
@@ -968,6 +999,7 @@ public:
virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; }
virtual DragEvent* createDragEvent() override { return &mDragEvent; }
+ virtual TouchModeEvent* createTouchModeEvent() override { return &mTouchModeEvent; }
private:
KeyEvent mKeyEvent;
@@ -975,6 +1007,7 @@ private:
FocusEvent mFocusEvent;
CaptureEvent mCaptureEvent;
DragEvent mDragEvent;
+ TouchModeEvent mTouchModeEvent;
};
/*
@@ -990,6 +1023,7 @@ public:
virtual FocusEvent* createFocusEvent() override;
virtual CaptureEvent* createCaptureEvent() override;
virtual DragEvent* createDragEvent() override;
+ virtual TouchModeEvent* createTouchModeEvent() override;
void recycle(InputEvent* event);
@@ -1001,6 +1035,7 @@ private:
std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool;
std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool;
std::queue<std::unique_ptr<DragEvent>> mDragEventPool;
+ std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool;
};
/*
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 7f0324a4a8..22aae196c6 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -84,6 +84,9 @@ enum class InputDeviceSensorType : int32_t {
GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR,
GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION,
+
+ ftl_first = ACCELEROMETER,
+ ftl_last = SIGNIFICANT_MOTION
};
enum class InputDeviceSensorAccuracy : int32_t {
@@ -105,6 +108,8 @@ enum class InputDeviceLightType : int32_t {
PLAYER_ID = 1,
RGB = 2,
MULTI_COLOR = 3,
+
+ ftl_last = MULTI_COLOR
};
struct InputDeviceSensorInfo {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index a790b5637f..edcb615491 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -72,6 +72,9 @@ struct InputMessage {
CAPTURE,
DRAG,
TIMELINE,
+ TOUCH_MODE,
+
+ ftl_last = TOUCH_MODE
};
struct Header {
@@ -111,7 +114,7 @@ struct InputMessage {
struct Motion {
int32_t eventId;
- uint32_t empty1;
+ uint32_t pointerCount;
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
@@ -126,20 +129,22 @@ struct InputMessage {
uint8_t empty2[3]; // 3 bytes to fill gap created by classification
int32_t edgeFlags;
nsecs_t downTime __attribute__((aligned(8)));
- float dsdx;
- float dtdx;
- float dtdy;
- float dsdy;
- float tx;
- float ty;
+ float dsdx; // Begin window transform
+ float dtdx; //
+ float dtdy; //
+ float dsdy; //
+ float tx; //
+ float ty; // End window transform
float xPrecision;
float yPrecision;
float xCursorPosition;
float yCursorPosition;
- uint32_t displayOrientation;
- int32_t displayWidth;
- int32_t displayHeight;
- uint32_t pointerCount;
+ float dsdxRaw; // Begin raw transform
+ float dtdxRaw; //
+ float dtdyRaw; //
+ float dsdyRaw; //
+ float txRaw; //
+ float tyRaw; // End raw transform
/**
* The "pointers" field must be the last field of the struct InputMessage.
* When we send the struct InputMessage across the socket, we are not
@@ -173,10 +178,9 @@ struct InputMessage {
struct Focus {
int32_t eventId;
- // The following 3 fields take up 4 bytes total
+ // The following 2 fields take up 4 bytes total
bool hasFocus;
- bool inTouchMode;
- uint8_t empty[2];
+ uint8_t empty[3];
inline size_t size() const { return sizeof(Focus); }
} focus;
@@ -206,6 +210,15 @@ struct InputMessage {
inline size_t size() const { return sizeof(Timeline); }
} timeline;
+
+ struct TouchMode {
+ int32_t eventId;
+ // The following 2 fields take up 4 bytes total
+ bool isInTouchMode;
+ uint8_t empty[3];
+
+ inline size_t size() const { return sizeof(TouchMode); }
+ } touchMode;
} __attribute__((aligned(8))) body;
bool isValid(size_t actualSize) const;
@@ -355,9 +368,8 @@ public:
int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, uint32_t displayOrientation,
- int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
- nsecs_t eventTime, uint32_t pointerCount,
+ float yCursorPosition, const ui::Transform& rawTransform,
+ nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
@@ -368,7 +380,7 @@ public:
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
+ status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus);
/* Publishes a capture event to the input channel.
*
@@ -388,6 +400,15 @@ public:
*/
status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting);
+ /* Publishes a touch mode event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode);
+
struct Finished {
uint32_t seq;
bool handled;
@@ -658,6 +679,7 @@ private:
static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
static void initializeDragEvent(DragEvent* event, const InputMessage* msg);
+ static void initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 2c6eacbfaa..dfb0ff59a0 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -201,10 +201,8 @@ private:
std::array<std::atomic<HalSupport>,
static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1>
mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN};
- // Android framework only sends mode upto DISPLAY_INACTIVE.
- // Need to increase the array if more mode supported.
std::array<std::atomic<HalSupport>,
- static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1>
+ static_cast<int32_t>(*(android::enum_range<hardware::power::Mode>().end() - 1)) + 1>
mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN};
};
diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h
index 37a476e679..7e6c51587d 100644
--- a/include/private/surface_control_private.h
+++ b/include/private/surface_control_private.h
@@ -29,8 +29,8 @@ typedef struct ASurfaceControlStats ASurfaceControlStats;
/**
* Callback to be notified when surface stats for a specific surface control are available.
*/
-typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
- ASurfaceControl* control, ASurfaceControlStats* stats);
+typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, int32_t id,
+ ASurfaceControlStats* stats);
/**
* Registers a callback to be invoked when surface stats from a specific surface are available.
@@ -42,7 +42,7 @@ typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
*
* \param func The callback to be invoked when surface stats are available.
*/
-void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context,
+void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, int32_t id, void* context,
ASurfaceControl_SurfaceStatsListener func);
/**