diff options
Diffstat (limited to 'include')
45 files changed, 1423 insertions, 224 deletions
diff --git a/include/android/font.h b/include/android/font.h index 8a3a474f25..022572535b 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -31,6 +31,7 @@ #include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include <sys/cdefs.h> /****************************************************************** @@ -86,10 +87,11 @@ enum { AFONT_WEIGHT_MAX = 1000 }; +struct AFont; /** * AFont provides information of the single font configuration. */ -struct AFont; +typedef struct AFont AFont; /** * Close an AFont. diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index 4417422687..60ff95e123 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -75,6 +75,7 @@ #include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include <sys/cdefs.h> #include <android/font.h> @@ -116,11 +117,12 @@ enum { AFAMILY_VARIANT_ELEGANT = 2, }; +struct AFontMatcher; /** * AFontMatcher performs match operation on given parameters and available font files. * This matcher is not a thread-safe object. Do not pass this matcher to other threads. */ -struct AFontMatcher; +typedef struct AFontMatcher AFontMatcher; /** * Select the best font from given parameters. diff --git a/include/android/input.h b/include/android/input.h index 38b27bc587..5d19c5cb13 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -54,7 +54,14 @@ #include <stdint.h> #include <sys/types.h> #include <android/keycodes.h> + +// This file is included by modules that have host support but android/looper.h is not supported +// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. +#ifndef __BIONIC__ +#define __REMOVED_IN(x) __attribute__((deprecated)) +#endif #include <android/looper.h> + #include <jni.h> #if !defined(__INTRODUCED_IN) @@ -764,9 +771,33 @@ enum { * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_16 = 47, + /** + * Axis constant: X gesture offset axis of a motion event. + * + * - For a touch pad, reports the distance that a swipe gesture has moved in the X axis, as a + * proportion of the touch pad's size. For example, if a touch pad is 1000 units wide, and a + * swipe gesture starts at X = 500 then moves to X = 400, this axis would have a value of + * -0.1. + */ + AMOTION_EVENT_AXIS_GESTURE_X_OFFSET = 48, + /** + * Axis constant: Y gesture offset axis of a motion event. + * + * The same as {@link AMOTION_EVENT_AXIS_GESTURE_X_OFFSET}, but for the Y axis. + */ + AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET = 49, + + /** + * Note: This is not an "Axis constant". It does not represent any axis, nor should it be used + * to represent any axis. It is a constant holding the value of the largest defined axis value, + * to make some computations (like iterating through all possible axes) cleaner. + * Please update the value accordingly if you add a new axis. + */ + AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. + // Update AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE accordingly as well. }; /** @@ -833,6 +864,12 @@ enum AMotionClassification : uint32_t { * This classification type should be used to accelerate the long press behaviour. */ AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2, + /** + * Classification constant: touchpad two-finger swipe. + * + * The current event stream represents the user swiping with two fingers on a touchpad. + */ + AMOTION_EVENT_CLASSIFICATION_TWO_FINGER_SWIPE = 3, }; /** diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 214559d683..e5b5db2964 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -776,7 +776,59 @@ enum { AKEYCODE_THUMBS_DOWN = 287, /** Used to switch current account that is consuming content. * May be consumed by system to switch current viewer profile. */ - AKEYCODE_PROFILE_SWITCH = 288 + AKEYCODE_PROFILE_SWITCH = 288, + /** Video Application key #1. */ + AKEYCODE_VIDEO_APP_1 = 289, + /** Video Application key #2. */ + AKEYCODE_VIDEO_APP_2 = 290, + /** Video Application key #3. */ + AKEYCODE_VIDEO_APP_3 = 291, + /** Video Application key #4. */ + AKEYCODE_VIDEO_APP_4 = 292, + /** Video Application key #5. */ + AKEYCODE_VIDEO_APP_5 = 293, + /** Video Application key #6. */ + AKEYCODE_VIDEO_APP_6 = 294, + /** Video Application key #7. */ + AKEYCODE_VIDEO_APP_7 = 295, + /** Video Application key #8. */ + AKEYCODE_VIDEO_APP_8 = 296, + /** Featured Application key #1. */ + AKEYCODE_FEATURED_APP_1 = 297, + /** Featured Application key #2. */ + AKEYCODE_FEATURED_APP_2 = 298, + /** Featured Application key #3. */ + AKEYCODE_FEATURED_APP_3 = 299, + /** Featured Application key #4. */ + AKEYCODE_FEATURED_APP_4 = 300, + /** Demo Application key #1. */ + AKEYCODE_DEMO_APP_1 = 301, + /** Demo Application key #2. */ + AKEYCODE_DEMO_APP_2 = 302, + /** Demo Application key #3. */ + AKEYCODE_DEMO_APP_3 = 303, + /** Demo Application key #4. */ + AKEYCODE_DEMO_APP_4 = 304, + /** Keyboard backlight Down key. + * Adjusts the keyboard backlight brightness down. */ + AKEYCODE_KEYBOARD_BACKLIGHT_DOWN = 305, + /** Keyboard backlight Up key. + * Adjusts the keyboard backlight brightness up. */ + AKEYCODE_KEYBOARD_BACKLIGHT_UP = 306, + /** Keyboard backlight Toggle key. + * Toggles the keyboard backlight on/off. */ + AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307, + /** The primary button on the barrel of a stylus. + * This is usually the button closest to the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_PRIMARY = 308, + /** The secondary button on the barrel of a stylus. + * This is usually the second button from the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_SECONDARY = 309, + /** The tertiary button on the barrel of a stylus. + * This is usually the third button from the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_TERTIARY = 310, + /** A button on the tail end of a stylus. */ + AKEYCODE_STYLUS_BUTTON_TAIL = 311, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/include/android/looper.h b/include/android/looper.h index 718f703048..4fe142a8e2 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -201,8 +201,11 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa * Like ALooper_pollOnce(), but performs all pending callbacks until all * data has been consumed or a file descriptor is available with no callback. * This function will never return ALOOPER_POLL_CALLBACK. + * + * Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls. + * Use ALooper_pollOnce instead. */ -int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData); +int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) __REMOVED_IN(1); /** * Wakes the poll asynchronously. diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index 5fa47f64be..eed6b3339f 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -88,6 +88,36 @@ typedef struct APerformanceHintManager APerformanceHintManager; typedef struct APerformanceHintSession APerformanceHintSession; /** + * Hints for the session used by {@link APerformanceHint_sendHint} to signal upcoming changes + * in the mode or workload. + */ +enum SessionHint { + /** + * This hint indicates a sudden increase in CPU workload intensity. It means + * that this hint session needs extra CPU resources immediately to meet the + * target duration for the current work cycle. + */ + CPU_LOAD_UP = 0, + /** + * This hint indicates a decrease in CPU workload intensity. It means that + * this hint session can reduce CPU resources and still meet the target duration. + */ + CPU_LOAD_DOWN = 1, + /* + * This hint indicates an upcoming CPU workload that is completely changed and + * unknown. It means that the hint session should reset CPU resources to a known + * baseline to prepare for an arbitrary load, and must wake up if inactive. + */ + CPU_LOAD_RESET = 2, + /* + * This hint indicates that the most recent CPU workload is resuming after a + * period of inactivity. It means that the hint session should allocate similar + * CPU resources to what was used previously, and must wake up if inactive. + */ + CPU_LOAD_RESUME = 3, +}; + +/** * Acquire an instance of the performance hint manager. * * @return manager instance on success, nullptr on failure. @@ -159,6 +189,17 @@ int APerformanceHint_reportActualWorkDuration( void APerformanceHint_closeSession( APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__); +/** + * Sends performance hints to inform the hint session of changes in the workload. + * + * @param session The performance hint session instance to update. + * @param hint The hint to send to the session. + * @return 0 on success + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_sendHint( + APerformanceHintSession* session, int hint) __INTRODUCED_IN(__ANDROID_API_U__); + __END_DECLS #endif // ANDROID_NATIVE_PERFORMANCE_HINT_H diff --git a/include/android/sensor.h b/include/android/sensor.h index eef69f4b32..105f9524c7 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -45,6 +45,11 @@ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ +// This file is included by modules that have host support but android/looper.h is not supported +// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. +#ifndef __BIONIC__ +#define __REMOVED_IN(x) __attribute__((deprecated)) +#endif #include <android/looper.h> #include <stdbool.h> diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 6223ef7f82..f76e73d3cf 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -545,6 +545,8 @@ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, * You can register for changes in the refresh rate using * \a AChoreographer_registerRefreshRateCallback. * + * See ASurfaceTransaction_clearFrameRate(). + * * \param frameRate is the intended frame rate of this surface, in frames per second. 0 is a special * value that indicates the app will accept the system's choice for the display frame rate, which is * the default behavior if this function isn't called. The frameRate param does <em>not</em> need to @@ -568,6 +570,31 @@ void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* tra __INTRODUCED_IN(31); /** + * Clears the frame rate which is set for \a surface_control. + * + * This is equivalent to calling + * ASurfaceTransaction_setFrameRateWithChangeStrategy( + * transaction, 0, compatibility, changeFrameRateStrategy). + * + * Usage of this API won't directly affect the application's frame production pipeline. However, + * because the system may change the display refresh rate, calls to this function may result in + * changes to Choreographer callback timings, and changes to the time interval at which the system + * releases buffers back to the application. + * + * See ASurfaceTransaction_setFrameRateWithChangeStrategy() + * + * You can register for changes in the refresh rate using + * \a AChoreographer_registerRefreshRateCallback. + * + * See ASurfaceTransaction_setFrameRateWithChangeStrategy(). + * + * Available since API level 34. + */ +void ASurfaceTransaction_clearFrameRate(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control) + __INTRODUCED_IN(__ANDROID_API_U__); + +/** * Indicate whether to enable backpressure for buffer submission to a given SurfaceControl. * * By default backpressure is disabled, which means submitting a buffer prior to receiving diff --git a/include/android/surface_control_jni.h b/include/android/surface_control_jni.h new file mode 100644 index 0000000000..840f6e724b --- /dev/null +++ b/include/android/surface_control_jni.h @@ -0,0 +1,68 @@ +/* + * Copyright 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. + */ + +/** + * @addtogroup NativeActivity Native Activity + * @{ + */ + +/** + * @file surface_control_jni.h + */ + +#ifndef ANDROID_SURFACE_CONTROL_JNI_H +#define ANDROID_SURFACE_CONTROL_JNI_H + +#include <jni.h> +#include <sys/cdefs.h> + +#include <android/surface_control.h> + +__BEGIN_DECLS + +/** + * Return the ASurfaceControl wrapped by a Java SurfaceControl object. + * + * The caller takes ownership of the returned ASurfaceControl returned and must + * release it * using ASurfaceControl_release. + * + * surfaceControlObj must be a non-null instance of android.view.SurfaceControl + * and isValid() must be true. + * + * Available since API level 34. + */ +ASurfaceControl* _Nonnull ASurfaceControl_fromJava(JNIEnv* _Nonnull env, + jobject _Nonnull surfaceControlObj) __INTRODUCED_IN(__ANDROID_API_U__); + +/** + * Return the ASurfaceTransaction wrapped by a Java Transaction object. + * + * The returned ASurfaceTransaction is still owned by the Java Transaction object is only + * valid while the Java Transaction object is alive. In particular, the returned transaction + * must NOT be deleted with ASurfaceTransaction_delete. + * + * transactionObj must be a non-null instance of + * android.view.SurfaceControl.Transaction and close() must not already be called. + * + * Available since API level 34. + */ +ASurfaceTransaction* _Nonnull ASurfaceTransaction_fromJava(JNIEnv* _Nonnull env, + jobject _Nonnull transactionObj) __INTRODUCED_IN(__ANDROID_API_U__); + +__END_DECLS + +#endif // ANDROID_SURFACE_CONTROL_JNI_H +/** @} */ diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index b0bbb954a9..94484eaf54 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -87,13 +87,14 @@ __BEGIN_DECLS +struct ASystemFontIterator; /** * ASystemFontIterator provides access to the system font configuration. * * ASystemFontIterator is an iterator for all available system font settings. * This iterator is not a thread-safe object. Do not pass this iterator to other threads. */ -struct ASystemFontIterator; +typedef struct ASystemFontIterator ASystemFontIterator; /** * Create a system font iterator. diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h index 4aa2f60d45..6794fbfc34 100644 --- a/include/audiomanager/AudioManager.h +++ b/include/audiomanager/AudioManager.h @@ -38,8 +38,52 @@ typedef enum { PLAYER_STATE_PAUSED = 3, PLAYER_STATE_STOPPED = 4, PLAYER_UPDATE_DEVICE_ID = 5, + PLAYER_UPDATE_PORT_ID = 6, + PLAYER_UPDATE_MUTED = 7, } player_state_t; +static constexpr char + kExtraPlayerEventMuteKey[] = "android.media.extra.PLAYER_EVENT_MUTE"; +enum { + PLAYER_MUTE_MASTER = (1 << 0), + PLAYER_MUTE_STREAM_VOLUME = (1 << 1), + PLAYER_MUTE_STREAM_MUTED = (1 << 2), + PLAYER_MUTE_PLAYBACK_RESTRICTED = (1 << 3), + PLAYER_MUTE_CLIENT_VOLUME = (1 << 4), + PLAYER_MUTE_VOLUME_SHAPER = (1 << 5), +}; + +struct mute_state_t { + /** Flag used when the master volume is causing the mute state. */ + bool muteFromMasterMute = false; + /** Flag used when the stream volume is causing the mute state. */ + bool muteFromStreamVolume = false; + /** Flag used when the stream muted is causing the mute state. */ + bool muteFromStreamMuted = false; + /** Flag used when playback is restricted by AppOps manager with OP_PLAY_AUDIO. */ + bool muteFromPlaybackRestricted = false; + /** Flag used when audio track was muted by client volume. */ + bool muteFromClientVolume = false; + /** Flag used when volume is muted by volume shaper. */ + bool muteFromVolumeShaper = false; + + explicit operator int() const + { + int result = muteFromMasterMute * PLAYER_MUTE_MASTER; + result |= muteFromStreamVolume * PLAYER_MUTE_STREAM_VOLUME; + result |= muteFromStreamMuted * PLAYER_MUTE_STREAM_MUTED; + result |= muteFromPlaybackRestricted * PLAYER_MUTE_PLAYBACK_RESTRICTED; + result |= muteFromClientVolume * PLAYER_MUTE_CLIENT_VOLUME; + result |= muteFromVolumeShaper * PLAYER_MUTE_VOLUME_SHAPER; + return result; + } + + bool operator==(const mute_state_t& other) const + { + return static_cast<int>(*this) == static_cast<int>(other); + } +}; + // must be kept in sync with definitions in AudioManager.java #define RECORD_RIID_INVALID -1 diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index 426e10c9bc..769670ea99 100644 --- a/include/audiomanager/IAudioManager.h +++ b/include/audiomanager/IAudioManager.h @@ -17,8 +17,10 @@ #ifndef ANDROID_IAUDIOMANAGER_H #define ANDROID_IAUDIOMANAGER_H +#include <audiomanager/AudioManager.h> #include <utils/Errors.h> #include <binder/IInterface.h> +#include <binder/PersistableBundle.h> #include <hardware/power.h> #include <system/audio.h> @@ -40,6 +42,7 @@ public: RECORDER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 5, RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6, PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7, + PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8, }; DECLARE_META_INTERFACE(AudioManager) @@ -52,12 +55,14 @@ public: /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage, audio_content_type_t content)= 0; /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event, - audio_port_handle_t deviceId) = 0; + audio_port_handle_t eventId) = 0; /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0; virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0; /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0; /*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0; /*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0; + /*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event, + const std::unique_ptr<os::PersistableBundle>& extras) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/ftl/algorithm.h b/include/ftl/algorithm.h new file mode 100644 index 0000000000..c5ff03b80d --- /dev/null +++ b/include/ftl/algorithm.h @@ -0,0 +1,71 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <algorithm> +#include <functional> +#include <utility> + +#include <ftl/optional.h> + +namespace android::ftl { + +// Adapter for std::find_if that converts the return value from iterator to optional. +// +// const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv}; +// assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv); +// +template <typename Container, typename Predicate, typename V = typename Container::value_type> +constexpr auto find_if(const Container& container, Predicate&& predicate) + -> Optional<std::reference_wrapper<const V>> { + const auto it = std::find_if(std::cbegin(container), std::cend(container), + std::forward<Predicate>(predicate)); + if (it == std::cend(container)) return {}; + return std::cref(*it); +} + +// Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs. +// +// const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>( +// 12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv); +// +// using Map = decltype(map); +// +// assert(14 == ftl::find_if(map, [](const auto& pair) { +// return pair.second.size() == 3; +// }).transform(ftl::to_key<Map>)); +// +// const auto opt = ftl::find_if(map, [](const auto& pair) { +// return pair.second.size() == 1; +// }).transform(ftl::to_mapped_ref<Map>); +// +// assert(opt); +// assert(opt->get() == ftl::StaticVector("tiramisu"sv)); +// +template <typename Map, typename Pair = typename Map::value_type, + typename Key = typename Map::key_type> +constexpr auto to_key(const Pair& pair) -> Key { + return pair.first; +} + +template <typename Map, typename Pair = typename Map::value_type, + typename Mapped = typename Map::mapped_type> +constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> { + return std::cref(pair.second); +} + +} // namespace android::ftl diff --git a/include/ftl/concat.h b/include/ftl/concat.h index ded48f7c8c..e0774d39f3 100644 --- a/include/ftl/concat.h +++ b/include/ftl/concat.h @@ -20,7 +20,9 @@ namespace android::ftl { -// Lightweight (not allocating nor sprintf-based) concatenation. +// Lightweight (not allocating nor sprintf-based) concatenation. The variadic arguments can be +// values of integral type (including bool and char), string literals, or strings whose length +// is constrained: // // std::string_view name = "Volume"; // ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h index 8ce949ef05..726ba0297e 100644 --- a/include/ftl/details/concat.h +++ b/include/ftl/details/concat.h @@ -19,6 +19,7 @@ #include <functional> #include <string_view> +#include <ftl/details/type_traits.h> #include <ftl/string.h> namespace android::ftl::details { @@ -26,16 +27,42 @@ namespace android::ftl::details { template <typename T, typename = void> struct StaticString; +// Booleans. 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>; +struct StaticString<T, std::enable_if_t<is_bool_v<T>>> { + static constexpr std::size_t N = 5; // Length of "false". - explicit StaticString(T v) : view(to_chars(buffer, v)) {} + explicit constexpr StaticString(bool b) : view(b ? "true" : "false") {} - to_chars_buffer_t<T> buffer; const std::string_view view; }; +// Characters. +template <typename T> +struct StaticString<T, std::enable_if_t<is_char_v<T>>> { + static constexpr std::size_t N = 1; + + explicit constexpr StaticString(char c) : character(c) {} + + const char character; + const std::string_view view{&character, 1u}; +}; + +// Integers, including the integer value of other character types like char32_t. +template <typename T> +struct StaticString< + T, std::enable_if_t<std::is_integral_v<remove_cvref_t<T>> && !is_bool_v<T> && !is_char_v<T>>> { + using U = remove_cvref_t<T>; + static constexpr std::size_t N = to_chars_length_v<U>; + + // TODO: Mark this and to_chars as `constexpr` in C++23. + explicit StaticString(U v) : view(to_chars(buffer, v)) {} + + to_chars_buffer_t<U> buffer; + const std::string_view view; +}; + +// Character arrays. template <std::size_t M> struct StaticString<const char (&)[M], void> { static constexpr std::size_t N = M - 1; @@ -50,6 +77,7 @@ struct Truncated { std::string_view view; }; +// Strings with constrained length. template <std::size_t M> struct StaticString<Truncated<M>, void> { static constexpr std::size_t N = M; diff --git a/include/ftl/details/match.h b/include/ftl/details/match.h new file mode 100644 index 0000000000..51b99d2f13 --- /dev/null +++ b/include/ftl/details/match.h @@ -0,0 +1,59 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <type_traits> +#include <variant> + +namespace android::ftl::details { + +template <typename... Ms> +struct Matcher : Ms... { + using Ms::operator()...; +}; + +// Deduction guide. +template <typename... Ms> +Matcher(Ms...) -> Matcher<Ms...>; + +template <typename Matcher, typename... Ts> +constexpr bool is_exhaustive_match_v = (std::is_invocable_v<Matcher, Ts> && ...); + +template <typename...> +struct Match; + +template <typename T, typename U, typename... Ts> +struct Match<T, U, Ts...> { + template <typename Variant, typename Matcher> + static decltype(auto) match(Variant& variant, const Matcher& matcher) { + if (auto* const ptr = std::get_if<T>(&variant)) { + return matcher(*ptr); + } else { + return Match<U, Ts...>::match(variant, matcher); + } + } +}; + +template <typename T> +struct Match<T> { + template <typename Variant, typename Matcher> + static decltype(auto) match(Variant& variant, const Matcher& matcher) { + return matcher(std::get<T>(variant)); + } +}; + +} // namespace android::ftl::details diff --git a/include/ftl/details/mixins.h b/include/ftl/details/mixins.h new file mode 100644 index 0000000000..9ab9e083ae --- /dev/null +++ b/include/ftl/details/mixins.h @@ -0,0 +1,30 @@ +/* + * Copyright 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. + */ + +#pragma once + +namespace android::ftl::details { + +template <typename Self, template <typename> class> +class Mixin { + protected: + constexpr Self& self() { return *static_cast<Self*>(this); } + constexpr const Self& self() const { return *static_cast<const Self*>(this); } + + constexpr auto& mut() { return self().value_; } +}; + +} // namespace android::ftl::details diff --git a/include/ftl/details/optional.h b/include/ftl/details/optional.h new file mode 100644 index 0000000000..bff7c1e000 --- /dev/null +++ b/include/ftl/details/optional.h @@ -0,0 +1,58 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <functional> +#include <optional> + +#include <ftl/details/type_traits.h> + +namespace android::ftl { + +template <typename> +struct Optional; + +namespace details { + +template <typename> +struct is_optional : std::false_type {}; + +template <typename T> +struct is_optional<std::optional<T>> : std::true_type {}; + +template <typename T> +struct is_optional<Optional<T>> : std::true_type {}; + +template <typename F, typename T> +struct transform_result { + using type = Optional<std::remove_cv_t<std::invoke_result_t<F, T>>>; +}; + +template <typename F, typename T> +using transform_result_t = typename transform_result<F, T>::type; + +template <typename F, typename T> +struct and_then_result { + using type = remove_cvref_t<std::invoke_result_t<F, T>>; + static_assert(is_optional<type>{}, "and_then function must return an optional"); +}; + +template <typename F, typename T> +using and_then_result_t = typename and_then_result<F, T>::type; + +} // namespace details +} // namespace android::ftl diff --git a/include/ftl/details/type_traits.h b/include/ftl/details/type_traits.h new file mode 100644 index 0000000000..47bebc5114 --- /dev/null +++ b/include/ftl/details/type_traits.h @@ -0,0 +1,33 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <type_traits> + +namespace android::ftl::details { + +// TODO: Replace with std::remove_cvref_t in C++20. +template <typename U> +using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>; + +template <typename T> +constexpr bool is_bool_v = std::is_same_v<remove_cvref_t<T>, bool>; + +template <typename T> +constexpr bool is_char_v = std::is_same_v<remove_cvref_t<T>, char>; + +} // namespace android::ftl::details diff --git a/include/ftl/enum.h b/include/ftl/enum.h index 82af1d6cf8..075d12bd17 100644 --- a/include/ftl/enum.h +++ b/include/ftl/enum.h @@ -92,7 +92,7 @@ inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value; // enum class E { A, B, C }; // static_assert(ftl::to_underlying(E::B) == 1); // -template <typename E> +template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr auto to_underlying(E v) { return static_cast<std::underlying_type_t<E>>(v); } diff --git a/include/ftl/flags.h b/include/ftl/flags.h index 70aaa0e6dd..cdb4e840a4 100644 --- a/include/ftl/flags.h +++ b/include/ftl/flags.h @@ -125,7 +125,7 @@ public: /* Tests whether all of the given flags are set */ bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; } - Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); } + constexpr Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); } Flags<F>& operator|=(Flags<F> rhs) { mFlags = mFlags | rhs.mFlags; return *this; @@ -217,7 +217,7 @@ inline Flags<F> operator~(F f) { } template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>> -Flags<F> operator|(F lhs, F rhs) { +constexpr Flags<F> operator|(F lhs, F rhs) { return static_cast<F>(to_underlying(lhs) | to_underlying(rhs)); } diff --git a/include/ftl/match.h b/include/ftl/match.h new file mode 100644 index 0000000000..7318c45b7b --- /dev/null +++ b/include/ftl/match.h @@ -0,0 +1,62 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <utility> +#include <variant> + +#include <ftl/details/match.h> + +namespace android::ftl { + +// Concise alternative to std::visit that compiles to branches rather than a dispatch table. For +// std::variant<T0, ..., TN> where N is small, this is slightly faster since the branches can be +// inlined unlike the function pointers. +// +// using namespace std::chrono; +// std::variant<seconds, minutes, hours> duration = 119min; +// +// // Mutable match. +// ftl::match(duration, [](auto& d) { ++d; }); +// +// // Immutable match. Exhaustive due to minutes being convertible to seconds. +// assert("2 hours"s == +// ftl::match(duration, +// [](const seconds& s) { +// const auto h = duration_cast<hours>(s); +// return std::to_string(h.count()) + " hours"s; +// }, +// [](const hours& h) { return std::to_string(h.count() / 24) + " days"s; })); +// +template <typename... Ts, typename... Ms> +decltype(auto) match(std::variant<Ts...>& variant, Ms&&... matchers) { + const auto matcher = details::Matcher{std::forward<Ms>(matchers)...}; + static_assert(details::is_exhaustive_match_v<decltype(matcher), Ts&...>, "Non-exhaustive match"); + + return details::Match<Ts...>::match(variant, matcher); +} + +template <typename... Ts, typename... Ms> +decltype(auto) match(const std::variant<Ts...>& variant, Ms&&... matchers) { + const auto matcher = details::Matcher{std::forward<Ms>(matchers)...}; + static_assert(details::is_exhaustive_match_v<decltype(matcher), const Ts&...>, + "Non-exhaustive match"); + + return details::Match<Ts...>::match(variant, matcher); +} + +} // namespace android::ftl diff --git a/include/ftl/mixins.h b/include/ftl/mixins.h new file mode 100644 index 0000000000..0e1d2004a3 --- /dev/null +++ b/include/ftl/mixins.h @@ -0,0 +1,148 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <ftl/details/mixins.h> + +namespace android::ftl { + +// CRTP mixins for defining type-safe wrappers that are distinct from their underlying type. Common +// uses are IDs, opaque handles, and physical quantities. The constructor is provided by (and must +// be inherited from) the `Constructible` mixin, whereas operators (equality, ordering, arithmetic, +// etc.) are enabled through inheritance: +// +// struct Id : ftl::Constructible<Id, std::int32_t>, ftl::Equatable<Id> { +// using Constructible::Constructible; +// }; +// +// static_assert(!std::is_default_constructible_v<Id>); +// +// Unlike `Constructible`, `DefaultConstructible` allows default construction. The default value is +// zero-initialized unless specified: +// +// struct Color : ftl::DefaultConstructible<Color, std::uint8_t>, +// ftl::Equatable<Color>, +// ftl::Orderable<Color> { +// using DefaultConstructible::DefaultConstructible; +// }; +// +// static_assert(Color() == Color(0u)); +// static_assert(ftl::to_underlying(Color(-1)) == 255u); +// static_assert(Color(1u) < Color(2u)); +// +// struct Sequence : ftl::DefaultConstructible<Sequence, std::int8_t, -1>, +// ftl::Equatable<Sequence>, +// ftl::Orderable<Sequence>, +// ftl::Incrementable<Sequence> { +// using DefaultConstructible::DefaultConstructible; +// }; +// +// static_assert(Sequence() == Sequence(-1)); +// +// The underlying type need not be a fundamental type: +// +// struct Timeout : ftl::DefaultConstructible<Timeout, std::chrono::seconds, 10>, +// ftl::Equatable<Timeout>, +// ftl::Addable<Timeout> { +// using DefaultConstructible::DefaultConstructible; +// }; +// +// using namespace std::chrono_literals; +// static_assert(Timeout() + Timeout(5s) == Timeout(15s)); +// +template <typename Self, typename T> +struct Constructible { + explicit constexpr Constructible(T value) : value_(value) {} + + explicit constexpr operator const T&() const { return value_; } + + private: + template <typename, template <typename> class> + friend class details::Mixin; + + T value_; +}; + +template <typename Self, typename T, auto kDefault = T{}> +struct DefaultConstructible : Constructible<Self, T> { + using Constructible<Self, T>::Constructible; + constexpr DefaultConstructible() : DefaultConstructible(T{kDefault}) {} +}; + +// Shorthand for casting a type-safe wrapper to its underlying value. +template <typename Self, typename T> +constexpr const T& to_underlying(const Constructible<Self, T>& c) { + return static_cast<const T&>(c); +} + +// Comparison operators for equality. +template <typename Self> +struct Equatable : details::Mixin<Self, Equatable> { + constexpr bool operator==(const Self& other) const { + return to_underlying(this->self()) == to_underlying(other); + } + + constexpr bool operator!=(const Self& other) const { return !(*this == other); } +}; + +// Comparison operators for ordering. +template <typename Self> +struct Orderable : details::Mixin<Self, Orderable> { + constexpr bool operator<(const Self& other) const { + return to_underlying(this->self()) < to_underlying(other); + } + + constexpr bool operator>(const Self& other) const { return other < this->self(); } + constexpr bool operator>=(const Self& other) const { return !(*this < other); } + constexpr bool operator<=(const Self& other) const { return !(*this > other); } +}; + +// Pre-increment and post-increment operators. +template <typename Self> +struct Incrementable : details::Mixin<Self, Incrementable> { + constexpr Self& operator++() { + ++this->mut(); + return this->self(); + } + + constexpr Self operator++(int) { + const Self tmp = this->self(); + operator++(); + return tmp; + } +}; + +// Additive operators, including incrementing. +template <typename Self> +struct Addable : details::Mixin<Self, Addable>, Incrementable<Self> { + constexpr Self& operator+=(const Self& other) { + this->mut() += to_underlying(other); + return this->self(); + } + + constexpr Self operator+(const Self& other) const { + Self tmp = this->self(); + return tmp += other; + } + + private: + using Base = details::Mixin<Self, Addable>; + using Base::mut; + using Base::self; +}; + +} // namespace android::ftl diff --git a/include/ftl/non_null.h b/include/ftl/non_null.h new file mode 100644 index 0000000000..35d09d71de --- /dev/null +++ b/include/ftl/non_null.h @@ -0,0 +1,116 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <cstdlib> +#include <type_traits> +#include <utility> + +namespace android::ftl { + +// Enforces and documents non-null pre/post-condition for (raw or smart) pointers. +// +// void get_length(const ftl::NonNull<std::shared_ptr<std::string>>& string_ptr, +// ftl::NonNull<std::size_t*> length_ptr) { +// // No need for `nullptr` checks. +// *length_ptr = string_ptr->length(); +// } +// +// const auto string_ptr = ftl::as_non_null(std::make_shared<std::string>("android")); +// std::size_t size; +// get_length(string_ptr, ftl::as_non_null(&size)); +// assert(size == 7u); +// +// For compatibility with std::unique_ptr<T> and performance with std::shared_ptr<T>, move +// operations are allowed despite breaking the invariant: +// +// using Pair = std::pair<ftl::NonNull<std::shared_ptr<int>>, std::shared_ptr<int>>; +// +// Pair dupe_if(ftl::NonNull<std::unique_ptr<int>> non_null_ptr, bool condition) { +// // Move the underlying pointer out, so `non_null_ptr` must not be accessed after this point. +// auto unique_ptr = std::move(non_null_ptr).take(); +// +// auto non_null_shared_ptr = ftl::as_non_null(std::shared_ptr<int>(std::move(unique_ptr))); +// auto nullable_shared_ptr = condition ? non_null_shared_ptr.get() : nullptr; +// +// return {std::move(non_null_shared_ptr), std::move(nullable_shared_ptr)}; +// } +// +// auto ptr = ftl::as_non_null(std::make_unique<int>(42)); +// const auto [ptr1, ptr2] = dupe_if(std::move(ptr), true); +// assert(ptr1.get() == ptr2); +// +template <typename Pointer> +class NonNull final { + struct Passkey {}; + + public: + // Disallow `nullptr` explicitly for clear compilation errors. + NonNull() = delete; + NonNull(std::nullptr_t) = delete; + + // Copy operations. + + constexpr NonNull(const NonNull&) = default; + constexpr NonNull& operator=(const NonNull&) = default; + + constexpr const Pointer& get() const { return pointer_; } + constexpr explicit operator const Pointer&() const { return get(); } + + // Move operations. These break the invariant, so care must be taken to avoid subsequent access. + + constexpr NonNull(NonNull&&) = default; + constexpr NonNull& operator=(NonNull&&) = default; + + constexpr Pointer take() && { return std::move(pointer_); } + constexpr explicit operator Pointer() && { return take(); } + + // Dereferencing. + constexpr decltype(auto) operator*() const { return *get(); } + constexpr decltype(auto) operator->() const { return get(); } + + // Private constructor for ftl::as_non_null. Excluded from candidate constructors for conversions + // through the passkey idiom, for clear compilation errors. + template <typename P> + constexpr NonNull(Passkey, P&& pointer) : pointer_(std::forward<P>(pointer)) { + if (!pointer_) std::abort(); + } + + private: + template <typename P> + friend constexpr auto as_non_null(P&&) -> NonNull<std::decay_t<P>>; + + Pointer pointer_; +}; + +template <typename P> +constexpr auto as_non_null(P&& pointer) -> NonNull<std::decay_t<P>> { + using Passkey = typename NonNull<std::decay_t<P>>::Passkey; + return {Passkey{}, std::forward<P>(pointer)}; +} + +template <typename P, typename Q> +constexpr bool operator==(const NonNull<P>& lhs, const NonNull<Q>& rhs) { + return lhs.get() == rhs.get(); +} + +template <typename P, typename Q> +constexpr bool operator!=(const NonNull<P>& lhs, const NonNull<Q>& rhs) { + return !operator==(lhs, rhs); +} + +} // namespace android::ftl diff --git a/include/ftl/optional.h b/include/ftl/optional.h new file mode 100644 index 0000000000..7b02bac340 --- /dev/null +++ b/include/ftl/optional.h @@ -0,0 +1,117 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <functional> +#include <optional> +#include <utility> + +#include <ftl/details/optional.h> + +namespace android::ftl { + +// Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8. +// +// TODO: Remove in C++23. +// +template <typename T> +struct Optional final : std::optional<T> { + using std::optional<T>::optional; + + // Implicit downcast. + Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {} + + using std::optional<T>::has_value; + using std::optional<T>::value; + + // Returns Optional<U> where F is a function that maps T to U. + template <typename F> + constexpr auto transform(F&& f) const& { + using R = details::transform_result_t<F, decltype(value())>; + if (has_value()) return R(std::invoke(std::forward<F>(f), value())); + return R(); + } + + template <typename F> + constexpr auto transform(F&& f) & { + using R = details::transform_result_t<F, decltype(value())>; + if (has_value()) return R(std::invoke(std::forward<F>(f), value())); + return R(); + } + + template <typename F> + constexpr auto transform(F&& f) const&& { + using R = details::transform_result_t<F, decltype(std::move(value()))>; + if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value()))); + return R(); + } + + template <typename F> + constexpr auto transform(F&& f) && { + using R = details::transform_result_t<F, decltype(std::move(value()))>; + if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value()))); + return R(); + } + + // Returns Optional<U> where F is a function that maps T to Optional<U>. + template <typename F> + constexpr auto and_then(F&& f) const& { + using R = details::and_then_result_t<F, decltype(value())>; + if (has_value()) return std::invoke(std::forward<F>(f), value()); + return R(); + } + + template <typename F> + constexpr auto and_then(F&& f) & { + using R = details::and_then_result_t<F, decltype(value())>; + if (has_value()) return std::invoke(std::forward<F>(f), value()); + return R(); + } + + template <typename F> + constexpr auto and_then(F&& f) const&& { + using R = details::and_then_result_t<F, decltype(std::move(value()))>; + if (has_value()) return std::invoke(std::forward<F>(f), std::move(value())); + return R(); + } + + template <typename F> + constexpr auto and_then(F&& f) && { + using R = details::and_then_result_t<F, decltype(std::move(value()))>; + if (has_value()) return std::invoke(std::forward<F>(f), std::move(value())); + return R(); + } +}; + +template <typename T, typename U> +constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) { + return static_cast<std::optional<T>>(lhs) == static_cast<std::optional<U>>(rhs); +} + +template <typename T, typename U> +constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) { + return !(lhs == rhs); +} + +// Deduction guides. +template <typename T> +Optional(T) -> Optional<T>; + +template <typename T> +Optional(std::optional<T>) -> Optional<T>; + +} // namespace android::ftl diff --git a/include/ftl/shared_mutex.h b/include/ftl/shared_mutex.h new file mode 100644 index 0000000000..146f5ba4a9 --- /dev/null +++ b/include/ftl/shared_mutex.h @@ -0,0 +1,47 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <shared_mutex> + +namespace android::ftl { + +// Wrapper around std::shared_mutex to provide capabilities for thread-safety +// annotations. +// TODO(b/257958323): This class is no longer needed once b/135688034 is fixed (currently blocked on +// b/175635923). +class [[clang::capability("shared_mutex")]] SharedMutex final { + public: + [[clang::acquire_capability()]] void lock() { + mutex_.lock(); + } + [[clang::release_capability()]] void unlock() { + mutex_.unlock(); + } + + [[clang::acquire_shared_capability()]] void lock_shared() { + mutex_.lock_shared(); + } + [[clang::release_shared_capability()]] void unlock_shared() { + mutex_.unlock_shared(); + } + + private: + std::shared_mutex mutex_; +}; + +} // namespace android::ftl diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h index 5217e76064..49cde7fedc 100644 --- a/include/ftl/small_map.h +++ b/include/ftl/small_map.h @@ -17,11 +17,11 @@ #pragma once #include <ftl/initializer_list.h> +#include <ftl/optional.h> #include <ftl/small_vector.h> #include <algorithm> #include <functional> -#include <optional> #include <type_traits> #include <utility> @@ -47,7 +47,7 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); -// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); +// assert(map.get(42).transform([](const std::string& s) { return s.size(); }) == 3u); // // const auto opt = map.get(-1); // assert(opt); @@ -59,7 +59,7 @@ namespace android::ftl { // map.emplace_or_replace(0, "vanilla", 2u, 3u); // assert(map.dynamic()); // -// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); +// assert(map == SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); // template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>> class SmallMap final { @@ -123,9 +123,7 @@ class SmallMap final { const_iterator cend() const { return map_.cend(); } // Returns whether a mapping exists for the given key. - bool contains(const key_type& key) const { - return get(key, [](const mapped_type&) {}); - } + bool contains(const key_type& key) const { return get(key).has_value(); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // @@ -139,46 +137,24 @@ class SmallMap final { // ref.get() = 'D'; // assert(d == 'D'); // - 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 get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { - return get(key, [](mapped_type& v) { return std::ref(v); }); + auto get(const key_type& key) const -> Optional<std::reference_wrapper<const mapped_type>> { + for (const auto& [k, v] : *this) { + if (KeyEqual{}(k, key)) { + return std::cref(v); + } + } + return {}; } - // Returns the result R of a unary operation F on (a constant or mutable reference to) the value - // for the given key, or std::nullopt if the key was not found. If F has a return type of void, - // then the Boolean result indicates whether the key was found. - // - // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); - // - // 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 get(const key_type& key, F f) const - -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> { + auto get(const key_type& key) -> Optional<std::reference_wrapper<mapped_type>> { for (auto& [k, v] : *this) { if (KeyEqual{}(k, key)) { - if constexpr (std::is_void_v<R>) { - f(v); - return true; - } else { - return f(v); - } + return std::ref(v); } } - return {}; } - template <typename F> - 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()); } @@ -286,7 +262,7 @@ bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs for (const auto& [k, v] : lhs) { const auto& lv = v; - if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { + if (!rhs.get(k).transform([&lv](const W& rv) { return lv == rv; }).value_or(false)) { return false; } } diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index 339726e4ea..11294c3ac8 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -21,11 +21,12 @@ #include <algorithm> #include <iterator> -#include <type_traits> #include <utility> #include <variant> #include <vector> +#include <ftl/details/type_traits.h> + namespace android::ftl { template <typename> @@ -80,10 +81,6 @@ class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<Sma using Static = StaticVector<T, N>; using Dynamic = SmallVector<T, 0>; - // TODO: Replace with std::remove_cvref_t in C++20. - template <typename U> - using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>; - public: FTL_ARRAY_TRAIT(T, value_type); FTL_ARRAY_TRAIT(T, size_type); @@ -104,7 +101,7 @@ class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<Sma // Constructs at most N elements. See StaticVector for underlying constructors. template <typename Arg, typename... Args, - typename = std::enable_if_t<!is_small_vector<remove_cvref_t<Arg>>{}>> + typename = std::enable_if_t<!is_small_vector<details::remove_cvref_t<Arg>>{}>> SmallVector(Arg&& arg, Args&&... args) : vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {} diff --git a/include/ftl/unit.h b/include/ftl/unit.h new file mode 100644 index 0000000000..e38230b976 --- /dev/null +++ b/include/ftl/unit.h @@ -0,0 +1,61 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <type_traits> +#include <utility> + +namespace android::ftl { + +// The unit type, and its only value. +constexpr struct Unit { +} unit; + +constexpr bool operator==(Unit, Unit) { + return true; +} + +constexpr bool operator!=(Unit, Unit) { + return false; +} + +// Adapts a function object F to return Unit. The return value of F is ignored. +// +// As a practical use, the function passed to ftl::Optional<T>::transform is not allowed to return +// void (cf. https://wg21.link/P0798R8#mapping-functions-returning-void), but may return Unit if +// only its side effects are meaningful: +// +// ftl::Optional opt = "food"s; +// opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); })); +// assert(opt == "foo"s); +// +template <typename F> +struct UnitFn { + F f; + + template <typename... Args> + Unit operator()(Args&&... args) { + return f(std::forward<Args>(args)...), unit; + } +}; + +template <typename F> +constexpr auto unit_fn(F&& f) -> UnitFn<std::decay_t<F>> { + return {std::forward<F>(f)}; +} + +} // namespace android::ftl diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index 9148fee532..98a18c9560 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H -#define _LIBINPUT_DISPLAY_VIEWPORT_H +#pragma once #include <android-base/stringprintf.h> #include <ftl/enum.h> @@ -144,5 +143,3 @@ struct DisplayViewport { }; } // namespace android - -#endif // _LIBINPUT_DISPLAY_VIEWPORT_H diff --git a/include/input/Input.h b/include/input/Input.h index 7ea297049b..d298d817f5 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_H -#define _LIBINPUT_INPUT_H +#pragma once #pragma GCC system_header @@ -210,6 +209,8 @@ std::string inputEventSourceToString(int32_t source); bool isFromSource(uint32_t source, uint32_t test); +bool isStylusToolType(uint32_t toolType); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. @@ -290,6 +291,10 @@ enum class MotionClassification : uint8_t { * The current gesture likely represents a user intentionally exerting force on the touchscreen. */ DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS, + /** + * The current gesture represents the user swiping with two fingers on a touchpad. + */ + TWO_FINGER_SWIPE = AMOTION_EVENT_CLASSIFICATION_TWO_FINGER_SWIPE, }; /** @@ -363,7 +368,7 @@ struct PointerCoords { // Values of axes that are stored in this structure packed in order by axis id // for each axis that is present in the structure according to 'bits'. - float values[MAX_AXES]; + std::array<float, MAX_AXES> values; inline void clear() { BitSet64::clear(bits); @@ -403,7 +408,8 @@ struct PointerCoords { return !(*this == other); } - void copyFrom(const PointerCoords& other); + inline void copyFrom(const PointerCoords& other) { *this = other; } + PointerCoords& operator=(const PointerCoords&) = default; private: void tooManyAxes(int axis); @@ -1061,6 +1067,46 @@ public: uint32_t seq; }; -} // namespace android +/* Pointer icon styles. + * Must match the definition in android.view.PointerIcon. + * + * Due to backwards compatibility and public api constraints, this is a duplicate (but type safe) + * definition of PointerIcon.java. + * + * TODO(b/235023317) move this definition to an aidl and statically assign to the below java public + * api values. + * + * WARNING: Keep these definitions in sync with + * frameworks/base/core/java/android/view/PointerIcon.java + */ +enum class PointerIconStyle : int32_t { + TYPE_CUSTOM = -1, + TYPE_NULL = 0, + TYPE_ARROW = 1000, + TYPE_CONTEXT_MENU = 1001, + TYPE_HAND = 1002, + TYPE_HELP = 1003, + TYPE_WAIT = 1004, + TYPE_CELL = 1006, + TYPE_CROSSHAIR = 1007, + TYPE_TEXT = 1008, + TYPE_VERTICAL_TEXT = 1009, + TYPE_ALIAS = 1010, + TYPE_COPY = 1011, + TYPE_NO_DROP = 1012, + TYPE_ALL_SCROLL = 1013, + TYPE_HORIZONTAL_DOUBLE_ARROW = 1014, + TYPE_VERTICAL_DOUBLE_ARROW = 1015, + TYPE_TOP_RIGHT_DOUBLE_ARROW = 1016, + TYPE_TOP_LEFT_DOUBLE_ARROW = 1017, + TYPE_ZOOM_IN = 1018, + TYPE_ZOOM_OUT = 1019, + TYPE_GRAB = 1020, + TYPE_GRABBING = 1021, + + TYPE_SPOT_HOVER = 2000, + TYPE_SPOT_TOUCH = 2001, + TYPE_SPOT_ANCHOR = 2002, +}; -#endif // _LIBINPUT_INPUT_H +} // namespace android diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 3585392c2b..e911734407 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -14,15 +14,18 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_DEVICE_H -#define _LIBINPUT_INPUT_DEVICE_H +#pragma once #include <android/sensor.h> +#include <ftl/flags.h> #include <input/Input.h> #include <input/KeyCharacterMap.h> #include <unordered_map> #include <vector> +#include <android/os/IInputConstants.h> +#include "android/hardware/input/InputDeviceCountryCode.h" + namespace android { /* @@ -55,6 +58,9 @@ struct InputDeviceIdentifier { // reuse values that are not associated with an input anymore. uint16_t nonce; + // The bluetooth address of the device, if known. + std::optional<std::string> bluetoothAddress; + /** * Return InputDeviceIdentifier.name that has been adjusted as follows: * - all characters besides alphanumerics, dash, @@ -104,12 +110,18 @@ enum class InputDeviceSensorReportingMode : int32_t { }; enum class InputDeviceLightType : int32_t { - MONO = 0, + INPUT = 0, PLAYER_ID = 1, - RGB = 2, - MULTI_COLOR = 3, + KEYBOARD_BACKLIGHT = 2, + + ftl_last = KEYBOARD_BACKLIGHT +}; - ftl_last = MULTI_COLOR +enum class InputDeviceLightCapability : uint32_t { + /** Capability to change brightness of the light */ + BRIGHTNESS = 0x00000001, + /** Capability to change color of the light */ + RGB = 0x00000002, }; struct InputDeviceSensorInfo { @@ -170,14 +182,17 @@ struct InputDeviceSensorInfo { struct InputDeviceLightInfo { explicit InputDeviceLightInfo(std::string name, int32_t id, InputDeviceLightType type, + ftl::Flags<InputDeviceLightCapability> capabilityFlags, int32_t ordinal) - : name(name), id(id), type(type), ordinal(ordinal) {} + : name(name), id(id), type(type), capabilityFlags(capabilityFlags), ordinal(ordinal) {} // Name string of the light. std::string name; // Light id int32_t id; // Type of the light. InputDeviceLightType type; + // Light capabilities. + ftl::Flags<InputDeviceLightCapability> capabilityFlags; // Ordinal of the light int32_t ordinal; }; @@ -210,8 +225,10 @@ public: }; void initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, - bool hasMic); + const InputDeviceIdentifier& identifier, const std::string& alias, + bool isExternal, bool hasMic, + hardware::input::InputDeviceCountryCode countryCode = + hardware::input::InputDeviceCountryCode::INVALID); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } @@ -223,6 +240,7 @@ public: } inline bool isExternal() const { return mIsExternal; } inline bool hasMic() const { return mHasMic; } + inline hardware::input::InputDeviceCountryCode getCountryCode() const { return mCountryCode; } inline uint32_t getSources() const { return mSources; } const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; @@ -266,6 +284,9 @@ public: std::vector<InputDeviceLightInfo> getLights(); + inline void setSupportsUsi(bool supportsUsi) { mSupportsUsi = supportsUsi; } + inline bool supportsUsi() const { return mSupportsUsi; } + private: int32_t mId; int32_t mGeneration; @@ -274,9 +295,13 @@ private: std::string mAlias; bool mIsExternal; bool mHasMic; + hardware::input::InputDeviceCountryCode mCountryCode; uint32_t mSources; int32_t mKeyboardType; std::shared_ptr<KeyCharacterMap> mKeyCharacterMap; + // Whether this device supports the Universal Stylus Initiative (USI) protocol for styluses. + bool mSupportsUsi; + bool mHasVibrator; bool mHasBattery; bool mHasButtonUnderPad; @@ -325,6 +350,8 @@ extern std::string getInputDeviceConfigurationFilePathByName( const std::string& name, InputDeviceConfigurationFileType type); enum ReservedInputDeviceId : int32_t { + // Device id representing an invalid device + INVALID_INPUT_DEVICE_ID = android::os::IInputConstants::INVALID_INPUT_DEVICE_ID, // Device id of a special "virtual" keyboard that is always present. VIRTUAL_KEYBOARD_ID = -1, // Device id of the "built-in" keyboard if there is one. @@ -334,5 +361,3 @@ enum ReservedInputDeviceId : int32_t { }; } // namespace android - -#endif // _LIBINPUT_INPUT_DEVICE_H diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index 2a742f9cf4..b4374acdcc 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_EVENT_LABELS_H -#define _LIBINPUT_INPUT_EVENT_LABELS_H +#pragma once #include <input/Input.h> #include <android/keycodes.h> @@ -68,4 +67,3 @@ private: }; } // namespace android -#endif // _LIBINPUT_INPUT_EVENT_LABELS_H diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 5f9a37d69c..1c52792cf6 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_INPUT_TRANSPORT_H -#define _LIBINPUT_INPUT_TRANSPORT_H +#pragma once #pragma GCC system_header @@ -452,8 +451,11 @@ private: */ class InputConsumer { public: - /* Creates a consumer associated with an input channel. */ + /* Create a consumer associated with an input channel. */ explicit InputConsumer(const std::shared_ptr<InputChannel>& channel); + /* Create a consumer associated with an input channel, override resampling system property */ + explicit InputConsumer(const std::shared_ptr<InputChannel>& channel, + bool enableTouchResampling); /* Destroys the consumer and releases its input channel. */ ~InputConsumer(); @@ -671,5 +673,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_INPUT_TRANSPORT_H diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index f6f8939b7a..dc928b806f 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef _LIBINPUT_KEY_CHARACTER_MAP_H -#define _LIBINPUT_KEY_CHARACTER_MAP_H +#pragma once #include <stdint.h> +#include <list> #ifdef __linux__ #include <binder/IBinder.h> @@ -152,29 +152,22 @@ public: private: struct Behavior { - Behavior(); - Behavior(const Behavior& other); - - /* The next behavior in the list, or NULL if none. */ - Behavior* next; - /* The meta key modifiers for this behavior. */ - int32_t metaState; + int32_t metaState = 0; /* The character to insert. */ - char16_t character; + char16_t character = 0; /* The fallback keycode if the key is not handled. */ - int32_t fallbackKeyCode; + int32_t fallbackKeyCode = 0; /* The replacement keycode if the key has to be replaced outright. */ - int32_t replacementKeyCode; + int32_t replacementKeyCode = 0; }; struct Key { Key(); Key(const Key& other); - ~Key(); /* The single character label printed on the key, or 0 if none. */ char16_t label; @@ -184,7 +177,7 @@ private: /* The list of key behaviors sorted from most specific to least specific * meta key binding. */ - Behavior* firstBehavior; + std::list<Behavior> behaviors; }; class Parser { @@ -240,8 +233,7 @@ private: KeyCharacterMap(const std::string& filename); bool getKey(int32_t keyCode, const Key** outKey) const; - bool getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const; + const Behavior* getKeyBehavior(int32_t keyCode, int32_t metaState) const; static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState); bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; @@ -277,5 +269,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_KEY_CHARACTER_MAP_H diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h index 1da78aa0c1..e203d190a6 100644 --- a/include/input/KeyLayoutMap.h +++ b/include/input/KeyLayoutMap.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_KEY_LAYOUT_MAP_H -#define _LIBINPUT_KEY_LAYOUT_MAP_H +#pragma once #include <android-base/result.h> #include <stdint.h> @@ -78,7 +77,7 @@ public: std::optional<AxisInfo> mapAxis(int32_t scanCode) const; const std::string getLoadFileName() const; // Return pair of sensor type and sensor data index, for the input device abs code - base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode); + base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode) const; virtual ~KeyLayoutMap(); @@ -131,5 +130,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_KEY_LAYOUT_MAP_H diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h index 9a3e15f1cd..f7f960f8e6 100644 --- a/include/input/Keyboard.h +++ b/include/input/Keyboard.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_KEYBOARD_H -#define _LIBINPUT_KEYBOARD_H +#pragma once #include <input/Input.h> #include <input/InputDevice.h> @@ -88,5 +87,3 @@ extern int32_t normalizeMetaState(int32_t oldMetaState); extern bool isMetaKey(int32_t keyCode); } // namespace android - -#endif // _LIBINPUT_KEYBOARD_H diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 55f730b287..e24344b3f1 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -24,16 +24,20 @@ namespace android { template <typename T> -std::string constToString(const T& v) { +inline std::string constToString(const T& v) { return std::to_string(v); } +inline std::string constToString(const std::string& s) { + return s; +} + /** * Convert an optional type to string. */ template <typename T> -std::string toString(const std::optional<T>& optional, - std::string (*toString)(const T&) = constToString) { +inline std::string toString(const std::optional<T>& optional, + std::string (*toString)(const T&) = constToString) { return optional ? toString(*optional) : "<not set>"; } diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h index 451918bb46..28e4816afe 100644 --- a/include/input/PropertyMap.h +++ b/include/input/PropertyMap.h @@ -14,14 +14,11 @@ * limitations under the License. */ -#ifndef _UTILS_PROPERTY_MAP_H -#define _UTILS_PROPERTY_MAP_H +#pragma once #include <android-base/result.h> -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include <utils/String8.h> #include <utils/Tokenizer.h> +#include <unordered_map> namespace android { @@ -58,30 +55,27 @@ public: /* Adds a property. * Replaces the property with the same key if it is already present. */ - void addProperty(const String8& key, const String8& value); - - /* Returns true if the property map contains the specified key. */ - bool hasProperty(const String8& key) const; + void addProperty(const std::string& key, const std::string& value); /* 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.) */ - bool tryGetProperty(const String8& key, String8& outValue) const; - bool tryGetProperty(const String8& key, bool& outValue) const; - bool tryGetProperty(const String8& key, int32_t& outValue) const; - bool tryGetProperty(const String8& key, float& outValue) const; + bool tryGetProperty(const std::string& key, std::string& outValue) const; + 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; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); - /* Gets the underlying property map. */ - inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; } - /* Loads a property map from a file. */ static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename); private: + /* Returns true if the property map contains the specified key. */ + bool hasProperty(const std::string& key) const; + class Parser { PropertyMap* mMap; Tokenizer* mTokenizer; @@ -95,13 +89,11 @@ private: status_t parseType(); status_t parseKey(); status_t parseKeyProperty(); - status_t parseModifier(const String8& token, int32_t* outMetaState); + status_t parseModifier(const std::string& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; - KeyedVector<String8, String8> mProperties; + std::unordered_map<std::string, std::string> mProperties; }; } // namespace android - -#endif // _UTILS_PROPERTY_MAP_H diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h index eda628e233..a616a95ab1 100644 --- a/include/input/TouchVideoFrame.h +++ b/include/input/TouchVideoFrame.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_TOUCHVIDEOFRAME_H -#define _LIBINPUT_TOUCHVIDEOFRAME_H +#pragma once #include <stdint.h> #include <sys/time.h> @@ -75,5 +74,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_TOUCHVIDEOFRAME_H diff --git a/include/input/VelocityControl.h b/include/input/VelocityControl.h index 1acc2aef70..f3c201e7c4 100644 --- a/include/input/VelocityControl.h +++ b/include/input/VelocityControl.h @@ -14,13 +14,15 @@ * limitations under the License. */ -#ifndef _LIBINPUT_VELOCITY_CONTROL_H -#define _LIBINPUT_VELOCITY_CONTROL_H +#pragma once +#include <android-base/stringprintf.h> #include <input/Input.h> #include <input/VelocityTracker.h> #include <utils/Timers.h> +using android::base::StringPrintf; + namespace android { /* @@ -70,6 +72,12 @@ struct VelocityControlParameters { scale(scale), lowThreshold(lowThreshold), highThreshold(highThreshold), acceleration(acceleration) { } + + std::string dump() const { + return StringPrintf("scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, " + "acceleration=%0.3f\n", + scale, lowThreshold, highThreshold, acceleration); + } }; /* @@ -79,6 +87,9 @@ class VelocityControl { public: VelocityControl(); + /* Gets the various parameters. */ + VelocityControlParameters& getParameters(); + /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); @@ -98,10 +109,8 @@ private: VelocityControlParameters mParameters; nsecs_t mLastMovementTime; - VelocityTracker::Position mRawPosition; + float mRawPositionX, mRawPositionY; VelocityTracker mVelocityTracker; }; } // namespace android - -#endif // _LIBINPUT_VELOCITY_CONTROL_H diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 886f1f7753..62c3ae15ce 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef _LIBINPUT_VELOCITY_TRACKER_H -#define _LIBINPUT_VELOCITY_TRACKER_H +#pragma once #include <input/Input.h> #include <utils/BitSet.h> #include <utils/Timers.h> +#include <map> +#include <set> namespace android { @@ -46,18 +47,14 @@ public: MAX = LEGACY, }; - struct Position { - float x, y; - }; - struct Estimator { static const size_t MAX_DEGREE = 4; // Estimator time base. nsecs_t time; - // Polynomial coefficients describing motion in X and Y. - float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; + // Polynomial coefficients describing motion. + float coeff[MAX_DEGREE + 1]; // Polynomial degree (number of coefficients), or zero if no information is // available. @@ -71,18 +68,47 @@ public: degree = 0; confidence = 0; for (size_t i = 0; i <= MAX_DEGREE; i++) { - xCoeff[i] = 0; - yCoeff[i] = 0; + coeff[i] = 0; + } + } + }; + + /* + * Contains all available velocity data from a VelocityTracker. + */ + struct ComputedVelocity { + inline std::optional<float> getVelocity(int32_t axis, uint32_t id) const { + const auto& axisVelocities = mVelocities.find(axis); + if (axisVelocities == mVelocities.end()) { + return {}; } + + const auto& axisIdVelocity = axisVelocities->second.find(id); + if (axisIdVelocity == axisVelocities->second.end()) { + return {}; + } + + return axisIdVelocity->second; } + + inline void addVelocity(int32_t axis, uint32_t id, float velocity) { + mVelocities[axis][id] = velocity; + } + + private: + std::map<int32_t /*axis*/, std::map<int32_t /*pointerId*/, float /*velocity*/>> mVelocities; }; - // Creates a velocity tracker using the specified strategy. + // Creates a velocity tracker using the specified strategy for each supported axis. // If strategy is not provided, uses the default strategy for the platform. + // TODO(b/32830165): support axis-specific strategies. VelocityTracker(const Strategy strategy = Strategy::DEFAULT); ~VelocityTracker(); + /** Return true if the axis is supported for velocity tracking, false otherwise. */ + static bool isAxisSupported(int32_t axis); + // Resets the velocity tracker state. void clear(); @@ -92,47 +118,57 @@ public: void clearPointers(BitSet32 idBits); // Adds movement information for a set of pointers. - // The idBits bitfield specifies the pointer ids of the pointers whose positions + // The idBits bitfield specifies the pointer ids of the pointers whose data points // are included in the movement. - // The positions array contains position information for each pointer in order by - // increasing id. Its size should be equal to the number of one bits in idBits. - void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions); + // The positions map contains a mapping of an axis to positions array. + // The positions arrays contain information for each pointer in order by increasing id. + // Each array's size should be equal to the number of one bits in idBits. + void addMovement(nsecs_t eventTime, BitSet32 idBits, + const std::map<int32_t, std::vector<float>>& positions); // Adds movement information for all pointers in a MotionEvent, including historical samples. void addMovement(const MotionEvent* event); - // Gets the velocity of the specified pointer id in position units per second. - // Returns false and sets the velocity components to zero if there is - // insufficient movement information for the pointer. - bool getVelocity(uint32_t id, float* outVx, float* outVy) const; + // Returns the velocity of the specified pointer id and axis in position units per second. + // Returns empty optional if there is insufficient movement information for the pointer, or if + // the given axis is not supported for velocity tracking. + std::optional<float> getVelocity(int32_t axis, uint32_t id) const; + + // Returns a ComputedVelocity instance with all available velocity data, using the given units + // (reference: units == 1 means "per millisecond"), and clamping each velocity between + // [-maxVelocity, maxVelocity], inclusive. + ComputedVelocity getComputedVelocity(int32_t units, float maxVelocity); - // Gets an estimator for the recent movements of the specified pointer id. + // Gets an estimator for the recent movements of the specified pointer id for the given axis. // Returns false and clears the estimator if there is no information available // about the pointer. - bool getEstimator(uint32_t id, Estimator* outEstimator) const; + bool getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const; // Gets the active pointer id, or -1 if none. inline int32_t getActivePointerId() const { return mActivePointerId; } - // Gets a bitset containing all pointer ids from the most recent movement. - inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } - private: - // The default velocity tracker strategy. - // Although other strategies are available for testing and comparison purposes, - // this is the strategy that applications will actually use. Be very careful - // when adjusting the default strategy because it can dramatically affect - // (often in a bad way) the user experience. - static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2; - nsecs_t mLastEventTime; BitSet32 mCurrentPointerIdBits; int32_t mActivePointerId; - std::unique_ptr<VelocityTrackerStrategy> mStrategy; - - bool configureStrategy(const Strategy strategy); - static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy); + // An override strategy passed in the constructor to be used for all axes. + // This strategy will apply to all axes, unless the default strategy is specified here. + // When default strategy is specified, then each axis will use a potentially different strategy + // based on a hardcoded mapping. + const Strategy mOverrideStrategy; + // Maps axes to their respective VelocityTrackerStrategy instances. + // Note that, only axes that have had MotionEvents (and not all supported axes) will be here. + std::map<int32_t /*axis*/, std::unique_ptr<VelocityTrackerStrategy>> mConfiguredStrategies; + + void configureStrategy(int32_t axis); + + // Generates a VelocityTrackerStrategy instance for the given Strategy type. + // The `deltaValues` parameter indicates whether or not the created strategy should treat motion + // values as deltas (and not as absolute values). This the parameter is applicable only for + // strategies that support differential axes. + static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy, + bool deltaValues); }; @@ -146,10 +182,9 @@ protected: public: virtual ~VelocityTrackerStrategy() { } - virtual void clear() = 0; virtual void clearPointers(BitSet32 idBits) = 0; virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) = 0; + const std::vector<float>& positions) = 0; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; }; @@ -178,10 +213,9 @@ public: LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); virtual ~LeastSquaresVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -196,11 +230,9 @@ private: struct Movement { nsecs_t eventTime; BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; + float positions[MAX_POINTERS]; - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; float chooseWeight(uint32_t index) const; @@ -221,10 +253,9 @@ public: IntegratingVelocityTrackerStrategy(uint32_t degree); ~IntegratingVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -233,16 +264,15 @@ private: nsecs_t updateTime; uint32_t degree; - float xpos, xvel, xaccel; - float ypos, yvel, yaccel; + float pos, vel, accel; }; const uint32_t mDegree; BitSet32 mPointerIdBits; State mPointerState[MAX_POINTER_ID + 1]; - void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; - void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; + void initState(State& state, nsecs_t eventTime, float pos) const; + void updateState(State& state, nsecs_t eventTime, float pos) const; void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; }; @@ -255,10 +285,9 @@ public: LegacyVelocityTrackerStrategy(); virtual ~LegacyVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -274,11 +303,9 @@ private: struct Movement { nsecs_t eventTime; BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; + float positions[MAX_POINTERS]; - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; uint32_t mIndex; @@ -287,13 +314,12 @@ private: class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { public: - ImpulseVelocityTrackerStrategy(); + ImpulseVelocityTrackerStrategy(bool deltaValues); virtual ~ImpulseVelocityTrackerStrategy(); - virtual void clear(); virtual void clearPointers(BitSet32 idBits); void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; + const std::vector<float>& positions) override; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: @@ -308,17 +334,18 @@ private: struct Movement { nsecs_t eventTime; BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; + float positions[MAX_POINTERS]; - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; } }; + // Whether or not the input movement values for the strategy come in the form of delta values. + // If the input values are not deltas, the strategy needs to calculate deltas as part of its + // velocity calculation. + const bool mDeltaValues; + size_t mIndex; Movement mMovements[HISTORY_SIZE]; }; } // namespace android - -#endif // _LIBINPUT_VELOCITY_TRACKER_H diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h index 6e8e2c9cf4..a4381eaab9 100644 --- a/include/input/VirtualKeyMap.h +++ b/include/input/VirtualKeyMap.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef _LIBINPUT_VIRTUAL_KEY_MAP_H -#define _LIBINPUT_VIRTUAL_KEY_MAP_H +#pragma once #include <stdint.h> @@ -77,5 +76,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_KEY_CHARACTER_MAP_H diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h index ed6f6f35f5..e0384f31db 100644 --- a/include/powermanager/PowerHalLoader.h +++ b/include/powermanager/PowerHalLoader.h @@ -19,6 +19,8 @@ #include <android-base/thread_annotations.h> #include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/1.2/IPower.h> +#include <android/hardware/power/1.3/IPower.h> #include <android/hardware/power/IPower.h> namespace android { @@ -32,12 +34,16 @@ public: static sp<hardware::power::IPower> loadAidl(); static sp<hardware::power::V1_0::IPower> loadHidlV1_0(); static sp<hardware::power::V1_1::IPower> loadHidlV1_1(); + static sp<hardware::power::V1_2::IPower> loadHidlV1_2(); + static sp<hardware::power::V1_3::IPower> loadHidlV1_3(); private: static std::mutex gHalMutex; static sp<hardware::power::IPower> gHalAidl GUARDED_BY(gHalMutex); static sp<hardware::power::V1_0::IPower> gHalHidlV1_0 GUARDED_BY(gHalMutex); static sp<hardware::power::V1_1::IPower> gHalHidlV1_1 GUARDED_BY(gHalMutex); + static sp<hardware::power::V1_2::IPower> gHalHidlV1_2 GUARDED_BY(gHalMutex); + static sp<hardware::power::V1_3::IPower> gHalHidlV1_3 GUARDED_BY(gHalMutex); static sp<hardware::power::V1_0::IPower> loadHidlV1_0Locked() EXCLUSIVE_LOCKS_REQUIRED(gHalMutex); diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index dfb0ff59a0..8028aa86e1 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -19,6 +19,8 @@ #include <android-base/thread_annotations.h> #include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/1.2/IPower.h> +#include <android/hardware/power/1.3/IPower.h> #include <android/hardware/power/Boost.h> #include <android/hardware/power/IPower.h> #include <android/hardware/power/IPowerHintSession.h> @@ -142,8 +144,8 @@ public: // Wrapper for the HIDL Power HAL v1.0. class HidlHalWrapperV1_0 : public HalWrapper { public: - explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> Hal) - : mHandleV1_0(std::move(Hal)) {} + explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> handleV1_0) + : mHandleV1_0(std::move(handleV1_0)) {} virtual ~HidlHalWrapperV1_0() = default; virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; @@ -154,10 +156,10 @@ public: virtual HalResult<int64_t> getHintSessionPreferredRate() override; protected: - virtual HalResult<void> sendPowerHint(hardware::power::V1_0::PowerHint hintId, uint32_t data); + const sp<hardware::power::V1_0::IPower> mHandleV1_0; + virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data); private: - sp<hardware::power::V1_0::IPower> mHandleV1_0; HalResult<void> setInteractive(bool enabled); HalResult<void> setFeature(hardware::power::V1_0::Feature feature, bool enabled); }; @@ -165,17 +167,40 @@ private: // Wrapper for the HIDL Power HAL v1.1. class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 { public: - HidlHalWrapperV1_1(sp<hardware::power::V1_0::IPower> handleV1_0, - sp<hardware::power::V1_1::IPower> handleV1_1) - : HidlHalWrapperV1_0(std::move(handleV1_0)), mHandleV1_1(std::move(handleV1_1)) {} + HidlHalWrapperV1_1(sp<hardware::power::V1_1::IPower> handleV1_1) + : HidlHalWrapperV1_0(std::move(handleV1_1)) {} virtual ~HidlHalWrapperV1_1() = default; protected: - virtual HalResult<void> sendPowerHint(hardware::power::V1_0::PowerHint hintId, + virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; +}; -private: - sp<hardware::power::V1_1::IPower> mHandleV1_1; +// Wrapper for the HIDL Power HAL v1.2. +class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 { +public: + virtual HalResult<void> setBoost(hardware::power::Boost boost, int32_t durationMs) override; + virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; + HidlHalWrapperV1_2(sp<hardware::power::V1_2::IPower> handleV1_2) + : HidlHalWrapperV1_1(std::move(handleV1_2)) {} + virtual ~HidlHalWrapperV1_2() = default; + +protected: + virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, + uint32_t data) override; +}; + +// Wrapper for the HIDL Power HAL v1.3. +class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 { +public: + virtual HalResult<void> setMode(hardware::power::Mode mode, bool enabled) override; + HidlHalWrapperV1_3(sp<hardware::power::V1_3::IPower> handleV1_3) + : HidlHalWrapperV1_2(std::move(handleV1_3)) {} + virtual ~HidlHalWrapperV1_3() = default; + +protected: + virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, + uint32_t data) override; }; // Wrapper for the AIDL Power HAL. |