diff options
Diffstat (limited to 'include')
54 files changed, 2416 insertions, 305 deletions
diff --git a/include/android/choreographer.h b/include/android/choreographer.h index cd8e63dec2..f999708f04 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -219,12 +219,16 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, * * Note that this time should \b not be used to advance animation clocks. * Instead, see AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(). + * + * Available since API level 33. */ int64_t AChoreographerFrameCallbackData_getFrameTimeNanos( const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); /** * The number of possible frame timelines. + * + * Available since API level 33. */ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); @@ -233,15 +237,20 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( * Gets the index of the platform-preferred frame timeline. * The preferred frame timeline is the default * by which the platform scheduled the app, based on the device configuration. + * + * Available since API level 33. */ size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33); /** * Gets the token used by the platform to identify the frame timeline at the given \c index. + * q + * Available since API level 33. * * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See * AChoreographerFrameCallbackData_getFrameTimelinesLength() + * */ AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33); @@ -250,6 +259,8 @@ AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( * Gets the time in nanoseconds at which the frame described at the given \c index is expected to * be presented. This time should be used to advance any animation clocks. * + * Available since API level 33. + * * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See * AChoreographerFrameCallbackData_getFrameTimelinesLength() */ @@ -260,6 +271,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTime * Gets the time in nanoseconds at which the frame described at the given \c index needs to be * ready by in order to be presented on time. * + * Available since API level 33. + * * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See * AChoreographerFrameCallbackData_getFrameTimelinesLength() */ diff --git a/include/android/configuration.h b/include/android/configuration.h index 88019ae054..46c7dfeceb 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -471,10 +471,36 @@ enum { */ ACONFIGURATION_COLOR_MODE = 0x10000, /** + * Bit mask for + * <a href="/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier">grammatical gender</a> + * configuration. + */ + ACONFIGURATION_GRAMMATICAL_GENDER = 0x20000, + /** * Constant used to to represent MNC (Mobile Network Code) zero. * 0 cannot be used, since it is used to represent an undefined MNC. */ ACONFIGURATION_MNC_ZERO = 0xffff, + + /** + * <a href="/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier">Grammatical gender</a>: not specified. + */ + ACONFIGURATION_GRAMMATICAL_GENDER_ANY = 0, + + /** + * <a href="/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier">Grammatical gender</a>: neuter. + */ + ACONFIGURATION_GRAMMATICAL_GENDER_NEUTER = 1, + + /** + * <a href="/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier">Grammatical gender</a>: feminine. + */ + ACONFIGURATION_GRAMMATICAL_GENDER_FEMININE = 2, + + /** + * <a href="/guide/topics/resources/providing-resources.html#GrammaticalInflectionQualifier">Grammatical gender</a>: masculine. + */ + ACONFIGURATION_GRAMMATICAL_GENDER_MASCULINE = 3, }; /** @@ -726,6 +752,24 @@ int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_I void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17); /** + * Return the configuration's grammatical gender, or ACONFIGURATION_GRAMMATICAL_GENDER_ANY if + * not set. + * + * Available since API level 34. + */ +int32_t AConfiguration_getGrammaticalGender(AConfiguration* config) + __INTRODUCED_IN(__ANDROID_API_U__); + +/** + * Set the configuration's grammatical gender to one of the + * ACONFIGURATION_GRAMMATICAL_GENDER_* constants. + * + * Available since API level 34. + */ +void AConfiguration_setGrammaticalGender(AConfiguration* config, int32_t value) + __INTRODUCED_IN(__ANDROID_API_U__); + +/** * Perform a diff between two configurations. Returns a bit mask of * ACONFIGURATION_* constants, each bit set meaning that configuration element * is different between them. 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..d6f9d633b6 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,64 @@ 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. + * + * These values are relative to the state from the last event, not accumulated, so developers + * should make sure to process this axis value for all batched historical events. + */ + 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, + /** + * Axis constant: X scroll distance axis of a motion event. + * + * - For a touch pad, reports the distance that should be scrolled in the X axis as a result of + * the user's two-finger scroll gesture, in display pixels. + * + * These values are relative to the state from the last event, not accumulated, so developers + * should make sure to process this axis value for all batched historical events. + */ + AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE = 50, + /** + * Axis constant: Y scroll distance axis of a motion event. + * + * The same as {@link AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE}, but for the Y axis. + */ + AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE = 51, + /** + * Axis constant: pinch scale factor of a motion event. + * + * - For a touch pad, reports the change in distance between the fingers when the user is making + * a pinch gesture, as a proportion of that distance when the gesture was last reported. For + * example, if the fingers were 50 units apart and are now 52 units apart, the scale factor + * would be 1.04. + * + * These values are relative to the state from the last event, not accumulated, so developers + * should make sure to process this axis value for all batched historical events. + */ + AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR = 52, + + /** + * 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_PINCH_SCALE_FACTOR, // 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 +895,27 @@ 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, + /** + * Classification constant: multi-finger swipe. + * + * The current event stream represents the user swiping with three or more fingers on a + * touchpad. Unlike two-finger swipes, these are only to be handled by the system UI, which is + * why they have a separate constant from two-finger swipes. + */ + AMOTION_EVENT_CLASSIFICATION_MULTI_FINGER_SWIPE = 4, + /** + * Classification constant: pinch. + * + * The current event stream represents the user pinching with two fingers on a touchpad. The + * gesture is centered around the current cursor position. + */ + AMOTION_EVENT_CLASSIFICATION_PINCH = 5, }; /** diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 3357660f5c..d4ba321057 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -809,6 +809,28 @@ enum { 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, + /** Key to open recent apps (a.k.a. Overview) */ + AKEYCODE_RECENT_APPS = 312, // 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..b494f897d5 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -37,6 +37,7 @@ #include <android/api-level.h> #include <stdint.h> +#include <unistd.h> __BEGIN_DECLS @@ -159,6 +160,23 @@ int APerformanceHint_reportActualWorkDuration( void APerformanceHint_closeSession( APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__); +/** + * Set a list of threads to the performance hint session. This operation will replace + * the current list of threads with the given list of threads. + * + * @param session The performance hint session instance for the threads. + * @param threadIds The list of threads to be associated with this session. They must be part of + * this app's thread group. + * @param size the size of the list of threadIds. + * @return 0 on success. + * EINVAL if the list of thread ids is empty or if any of the thread ids is not part of the thread group. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_setThreads( + APerformanceHintSession* session, + const pid_t* threadIds, + size_t size) __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 ba81bc8d8e..085fc270c1 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..e4926a6a8d 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -521,6 +521,47 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio __INTRODUCED_IN(29); /** + * Sets the desired extended range brightness for the layer. This only applies for layers whose + * dataspace has RANGE_EXTENDED set on it. + * + * Available since API level 34. + * + * @param surface_control The layer whose extended range brightness is being specified + * @param currentBufferRatio The current hdr/sdr ratio of the current buffer as represented as + * peakHdrBrightnessInNits / targetSdrWhitePointInNits. For example if the + * buffer was rendered with a target SDR whitepoint of 100nits and a max + * display brightness of 200nits, this should be set to 2.0f. + * + * Default value is 1.0f. + * + * Transfer functions that encode their own brightness ranges, such as + * HLG or PQ, should also set this to 1.0f and instead communicate + * extended content brightness information via metadata such as CTA861_3 + * or SMPTE2086. + * + * Must be finite && >= 1.0f + * + * @param desiredRatio The desired hdr/sdr ratio as represented as peakHdrBrightnessInNits / + * targetSdrWhitePointInNits. This can be used to communicate the max desired + * brightness range. This is similar to the "max luminance" value in other + * HDR metadata formats, but represented as a ratio of the target SDR whitepoint + * to the max display brightness. The system may not be able to, or may choose + * not to, deliver the requested range. + * + * If unspecified, the system will attempt to provide the best range it can + * for the given ambient conditions & device state. However, voluntarily + * reducing the requested range can help improve battery life as well as can + * improve quality by ensuring greater bit depth is allocated to the luminance + * range in use. + * + * Must be finite && >= 1.0f + */ +void ASurfaceTransaction_setExtendedRangeBrightness(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, + float currentBufferRatio, + float desiredRatio) __INTRODUCED_IN(__ANDROID_API_U__); + +/** * Same as ASurfaceTransaction_setFrameRateWithChangeStrategy(transaction, surface_control, * frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS). * @@ -545,6 +586,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 +611,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 @@ -587,6 +655,8 @@ void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* tra * and pushing buffers earlier for server side queuing will be advantageous * in such cases. * + * Available since API level 31. + * * \param transaction The transaction in which to make the change. * \param surface_control The ASurfaceControl on which to control buffer backpressure behavior. * \param enableBackPressure Whether to enable back pressure. @@ -608,6 +678,8 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, * AChoreographer_postVsyncCallback(). The \c vsyncId can then be extracted from the * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId(). * + * Available since API level 33. + * * \param vsyncId The vsync ID received from AChoreographer, setting the frame's presentation target * to the corresponding expected presentation time and deadline from the frame to be rendered. A * stale or invalid value will be ignored. 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..43048dbff0 100644 --- a/include/audiomanager/AudioManager.h +++ b/include/audiomanager/AudioManager.h @@ -38,8 +38,60 @@ 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_UPDATE_FORMAT = 8, } player_state_t; +static constexpr char + kExtraPlayerEventSpatializedKey[] = "android.media.extra.PLAYER_EVENT_SPATIALIZED"; +static constexpr char + kExtraPlayerEventSampleRateKey[] = "android.media.extra.PLAYER_EVENT_SAMPLE_RATE"; +static constexpr char + kExtraPlayerEventChannelMaskKey[] = "android.media.extra.PLAYER_EVENT_CHANNEL_MASK"; + +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..a818128c92 --- /dev/null +++ b/include/ftl/optional.h @@ -0,0 +1,125 @@ +/* + * 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(); + } + + // Delete new for this class. Its base doesn't have a virtual destructor, and + // if it got deleted via base class pointer, it would cause undefined + // behavior. There's not a good reason to allocate this object on the heap + // anyway. + static void* operator new(size_t) = delete; + static void* operator new[](size_t) = delete; + +}; + +template <typename T, typename U> +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..7457496784 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -14,14 +14,14 @@ * 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> #include <ftl/string.h> #include <gui/constants.h> #include <input/Input.h> +#include <ui/Rotation.h> #include <cinttypes> #include <optional> @@ -30,13 +30,6 @@ using android::base::StringPrintf; namespace android { -enum { - DISPLAY_ORIENTATION_0 = 0, - DISPLAY_ORIENTATION_90 = 1, - DISPLAY_ORIENTATION_180 = 2, - DISPLAY_ORIENTATION_270 = 3 -}; - /** * Describes the different type of viewports supported by input flinger. * Keep in sync with values in InputManagerService.java. @@ -55,7 +48,7 @@ enum class ViewportType : int32_t { */ struct DisplayViewport { int32_t displayId; // -1 if invalid - int32_t orientation; + ui::Rotation orientation; int32_t logicalLeft; int32_t logicalTop; int32_t logicalRight; @@ -75,7 +68,7 @@ struct DisplayViewport { DisplayViewport() : displayId(ADISPLAY_ID_NONE), - orientation(DISPLAY_ORIENTATION_0), + orientation(ui::ROTATION_0), logicalLeft(0), logicalTop(0), logicalRight(0), @@ -112,7 +105,7 @@ struct DisplayViewport { void setNonDisplayViewport(int32_t width, int32_t height) { displayId = ADISPLAY_ID_NONE; - orientation = DISPLAY_ORIENTATION_0; + orientation = ui::ROTATION_0; logicalLeft = 0; logicalTop = 0; logicalRight = width; @@ -144,5 +137,3 @@ struct DisplayViewport { }; } // namespace android - -#endif // _LIBINPUT_DISPLAY_VIEWPORT_H diff --git a/include/input/Input.h b/include/input/Input.h index 7ea297049b..608519b70e 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 @@ -204,12 +203,21 @@ class Parcel; */ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy); +/* + * Transform an angle on the x-y plane. An angle of 0 radians corresponds to "north" or + * pointing upwards in the negative Y direction, a positive angle points towards the right, and a + * negative angle points towards the left. + */ +float transformAngle(const ui::Transform& transform, float angleRadians); + const char* inputEventTypeToString(int32_t type); 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 +298,21 @@ 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, + /** + * The current gesture represents the user swiping with three or more fingers on a touchpad. + * Unlike two-finger swipes, these are only to be handled by the system UI, which is why they + * have a separate constant from two-finger swipes. + */ + MULTI_FINGER_SWIPE = AMOTION_EVENT_CLASSIFICATION_MULTI_FINGER_SWIPE, + /** + * The current gesture represents the user pinching with two fingers on a touchpad. The gesture + * is centered around the current cursor position. + */ + PINCH = AMOTION_EVENT_CLASSIFICATION_PINCH, }; /** @@ -356,17 +379,24 @@ constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<floa * Pointer coordinate data. */ struct PointerCoords { - enum { MAX_AXES = 30 }; // 30 so that sizeof(PointerCoords) == 128 + enum { MAX_AXES = 30 }; // 30 so that sizeof(PointerCoords) == 136 // Bitfield of axes that are present in this structure. uint64_t bits __attribute__((aligned(8))); // 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; + + // Whether these coordinate data were generated by resampling. + bool isResampled; + + static_assert(sizeof(bool) == 1); // Ensure padding is correctly sized. + uint8_t empty[7]; inline void clear() { BitSet64::clear(bits); + isResampled = false; } bool isEmpty() const { @@ -403,7 +433,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); @@ -498,7 +529,7 @@ public: inline nsecs_t getEventTime() const { return mEventTime; } static const char* getLabel(int32_t keyCode); - static int32_t getKeyCodeFromLabel(const char* label); + static std::optional<int> getKeyCodeFromLabel(const char* label); void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode, @@ -519,6 +550,8 @@ protected: nsecs_t mEventTime; }; +std::ostream& operator<<(std::ostream& out, const KeyEvent& event); + /* * Motion events. */ @@ -571,7 +604,7 @@ public: inline const ui::Transform& getTransform() const { return mTransform; } - int getSurfaceRotation() const; + std::optional<ui::Rotation> getSurfaceRotation() const; inline float getXPrecision() const { return mXPrecision; } @@ -756,6 +789,10 @@ public: AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex); } + inline bool isResampled(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->isResampled; + } + ssize_t findPointerIndex(int32_t pointerId) const; void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, @@ -805,7 +842,7 @@ public: } static const char* getLabel(int32_t axis); - static int32_t getAxisFromLabel(const char* label); + static std::optional<int> getAxisFromLabel(const char* label); static std::string actionToString(int32_t action); @@ -1061,6 +1098,48 @@ 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_NOT_SPECIFIED = 1, + 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_HANDWRITING = 1022, + + 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..66d3435907 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -14,15 +14,17 @@ * 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> + namespace android { /* @@ -55,6 +57,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 +109,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 +181,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; }; @@ -190,6 +204,22 @@ struct InputDeviceBatteryInfo { int32_t id; }; +struct KeyboardLayoutInfo { + explicit KeyboardLayoutInfo(std::string languageTag, std::string layoutType) + : languageTag(languageTag), layoutType(layoutType) {} + + // A BCP 47 conformant language tag such as "en-US". + std::string languageTag; + // The layout type such as QWERTY or AZERTY. + std::string layoutType; +}; + +// The version of the Universal Stylus Initiative (USI) protocol supported by the input device. +struct InputDeviceUsiVersion { + int32_t majorVersion = -1; + int32_t minorVersion = -1; +}; + /* * Describes the characteristics and capabilities of an input device. */ @@ -210,8 +240,8 @@ 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, int32_t associatedDisplayId); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } @@ -238,6 +268,11 @@ public: void setKeyboardType(int32_t keyboardType); inline int32_t getKeyboardType() const { return mKeyboardType; } + void setKeyboardLayoutInfo(KeyboardLayoutInfo keyboardLayoutInfo); + inline const std::optional<KeyboardLayoutInfo>& getKeyboardLayoutInfo() const { + return mKeyboardLayoutInfo; + } + inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) { mKeyCharacterMap = value; } @@ -266,6 +301,13 @@ public: std::vector<InputDeviceLightInfo> getLights(); + inline void setUsiVersion(std::optional<InputDeviceUsiVersion> usiVersion) { + mUsiVersion = std::move(usiVersion); + } + inline std::optional<InputDeviceUsiVersion> getUsiVersion() const { return mUsiVersion; } + + inline int32_t getAssociatedDisplayId() const { return mAssociatedDisplayId; } + private: int32_t mId; int32_t mGeneration; @@ -274,9 +316,13 @@ private: std::string mAlias; bool mIsExternal; bool mHasMic; + std::optional<KeyboardLayoutInfo> mKeyboardLayoutInfo; uint32_t mSources; int32_t mKeyboardType; std::shared_ptr<KeyCharacterMap> mKeyCharacterMap; + std::optional<InputDeviceUsiVersion> mUsiVersion; + int32_t mAssociatedDisplayId; + bool mHasVibrator; bool mHasBattery; bool mHasButtonUnderPad; @@ -325,6 +371,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 +382,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..9dedd2b2da 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> @@ -31,27 +30,35 @@ struct InputEventLabel { int value; }; +struct EvdevEventLabel { + std::string type; + std::string code; + std::string value; +}; + // NOTE: If you want a new key code, axis code, led code or flag code in keylayout file, // then you must add it to InputEventLabels.cpp. class InputEventLookup { public: - static int lookupValueByLabel(const std::unordered_map<std::string, int>& map, - const char* literal); + static std::optional<int> lookupValueByLabel(const std::unordered_map<std::string, int>& map, + const char* literal); static const char* lookupLabelByValue(const std::vector<InputEventLabel>& vec, int value); - static int32_t getKeyCodeByLabel(const char* label); + static std::optional<int> getKeyCodeByLabel(const char* label); static const char* getLabelByKeyCode(int32_t keyCode); - static uint32_t getKeyFlagByLabel(const char* label); + static std::optional<int> getKeyFlagByLabel(const char* label); - static int32_t getAxisByLabel(const char* label); + static std::optional<int> getAxisByLabel(const char* label); static const char* getAxisLabel(int32_t axisId); - static int32_t getLedByLabel(const char* label); + static std::optional<int> getLedByLabel(const char* label); + + static EvdevEventLabel getLinuxEvdevLabel(int32_t type, int32_t code, int32_t value); private: static const std::unordered_map<std::string, int> KEYCODES; @@ -68,4 +75,3 @@ private: }; } // namespace android -#endif // _LIBINPUT_INPUT_EVENT_LABELS_H diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 5f9a37d69c..a1be542d7b 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 @@ -39,6 +38,7 @@ #include <binder/IBinder.h> #include <binder/Parcelable.h> #include <input/Input.h> +#include <input/InputVerifier.h> #include <sys/stat.h> #include <ui/Transform.h> #include <utils/BitSet.h> @@ -445,6 +445,7 @@ public: private: std::shared_ptr<InputChannel> mChannel; + InputVerifier mInputVerifier; }; /* @@ -452,8 +453,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 +675,3 @@ private: }; } // namespace android - -#endif // _LIBINPUT_INPUT_TRANSPORT_H diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h new file mode 100644 index 0000000000..d4589f53b5 --- /dev/null +++ b/include/input/InputVerifier.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 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 <input/Input.h> +#include <map> + +namespace android { + +/* + * Crash if the provided touch stream is inconsistent. + * + * TODO(b/211379801): Add support for hover events: + * - No hover move without enter + * - No touching pointers when hover enter + * - No hovering pointers when touching + * - Only 1 hovering pointer max + */ +class InputVerifier { +public: + InputVerifier(const std::string& name); + + void processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, int32_t flags); + +private: + const std::string mName; + std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> mTouchingPointerIdsByDevice; + void ensureTouchingPointersMatch(int32_t deviceId, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const char* action) const; +}; + +} // namespace android diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index f6f8939b7a..b5e6f65e48 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> @@ -87,6 +87,9 @@ public: /* Combines this key character map with the provided overlay. */ void combine(const KeyCharacterMap& overlay); + /* Clears already applied layout overlay */ + void clearLayoutOverlay(); + /* Gets the keyboard type. */ KeyboardType getKeyboardType() const; @@ -125,14 +128,21 @@ public: bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector<KeyEvent>& outEvents) const; + /* Maps an Android key code to another Android key code. This mapping is applied after scanCode + * and usageCodes are mapped to corresponding Android Keycode */ + void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode); + /* Maps a scan code and usage code to a key code, in case this key map overrides * the mapping in some way. */ status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const; - /* Tries to find a replacement key code for a given key code and meta state - * in character map. */ - void tryRemapKey(int32_t scanCode, int32_t metaState, - int32_t* outKeyCode, int32_t* outMetaState) const; + /* Returns keycode after applying Android key code remapping defined in mKeyRemapping */ + int32_t applyKeyRemapping(int32_t fromKeyCode) const; + + /* Returns the <keyCode, metaState> pair after applying key behavior defined in the kcm file, + * that tries to find a replacement key code based on current meta state */ + std::pair<int32_t /*keyCode*/, int32_t /*metaState*/> applyKeyBehavior(int32_t keyCode, + int32_t metaState) const; #ifdef __linux__ /* Reads a key map from a parcel. */ @@ -152,29 +162,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 +187,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 { @@ -234,14 +237,14 @@ private: std::string mLoadFileName; bool mLayoutOverlayApplied; - KeyedVector<int32_t, int32_t> mKeysByScanCode; - KeyedVector<int32_t, int32_t> mKeysByUsageCode; + std::map<int32_t /* fromAndroidKeyCode */, int32_t /* toAndroidKeyCode */> mKeyRemapping; + std::map<int32_t /* fromScanCode */, int32_t /* toAndroidKeyCode */> mKeysByScanCode; + std::map<int32_t /* fromHidUsageCode */, int32_t /* toAndroidKeyCode */> mKeysByUsageCode; 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 +280,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/MotionPredictor.h b/include/input/MotionPredictor.h new file mode 100644 index 0000000000..68ebf75fc6 --- /dev/null +++ b/include/input/MotionPredictor.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> + +#include <android-base/thread_annotations.h> +#include <android/sysprop/InputProperties.sysprop.h> +#include <input/Input.h> +#include <input/TfLiteMotionPredictor.h> + +namespace android { + +static inline bool isMotionPredictionEnabled() { + return sysprop::InputProperties::enable_motion_prediction().value_or(true); +} + +/** + * Given a set of MotionEvents for the current gesture, predict the motion. The returned MotionEvent + * contains a set of samples in the future. + * + * The typical usage is like this: + * + * MotionPredictor predictor(offset = MY_OFFSET); + * predictor.record(DOWN_MOTION_EVENT); + * predictor.record(MOVE_MOTION_EVENT); + * prediction = predictor.predict(futureTime); + * + * The resulting motion event will have eventTime <= (futureTime + MY_OFFSET). It might contain + * historical data, which are additional samples from the latest recorded MotionEvent's eventTime + * to the futureTime + MY_OFFSET. + * + * The offset is used to provide additional flexibility to the caller, in case the default present + * time (typically provided by the choreographer) does not account for some delays, or to simply + * reduce the aggressiveness of the prediction. Offset can be positive or negative. + */ +class MotionPredictor { +public: + /** + * Parameters: + * predictionTimestampOffsetNanos: additional, constant shift to apply to the target + * prediction time. The prediction will target the time t=(prediction time + + * predictionTimestampOffsetNanos). + * + * modelPath: filesystem path to a TfLiteMotionPredictorModel flatbuffer, or nullptr to use the + * default model path. + * + * checkEnableMotionPredition: the function to check whether the prediction should run. Used to + * provide an additional way of turning prediction on and off. Can be toggled at runtime. + */ + MotionPredictor(nsecs_t predictionTimestampOffsetNanos, const char* modelPath = nullptr, + std::function<bool()> checkEnableMotionPrediction = isMotionPredictionEnabled); + void record(const MotionEvent& event); + std::vector<std::unique_ptr<MotionEvent>> predict(nsecs_t timestamp); + bool isPredictionAvailable(int32_t deviceId, int32_t source); + +private: + const nsecs_t mPredictionTimestampOffsetNanos; + const std::string mModelPath; + const std::function<bool()> mCheckMotionPredictionEnabled; + + std::unique_ptr<TfLiteMotionPredictorModel> mModel; + // Buffers/events for each device seen by record(). + std::unordered_map</*deviceId*/ int32_t, TfLiteMotionPredictorBuffers> mDeviceBuffers; + std::unordered_map</*deviceId*/ int32_t, MotionEvent> mLastEvents; +}; + +} // namespace android diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 55f730b287..02bc2010db 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -16,24 +16,45 @@ #pragma once +#include <bitset> #include <map> #include <optional> #include <set> #include <string> +#include <vector> namespace android { +template <size_t N> +std::string bitsetToString(const std::bitset<N>& bitset) { + return bitset.to_string(); +} + template <typename T> -std::string constToString(const T& v) { +inline std::string constToString(const T& v) { return std::to_string(v); } +template <> +inline std::string constToString(const bool& value) { + return value ? "true" : "false"; +} + +template <> +inline std::string constToString(const std::vector<bool>::reference& value) { + return value ? "true" : "false"; +} + +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>"; } @@ -66,6 +87,19 @@ std::string dumpMap(const std::map<K, V>& map, std::string (*keyToString)(const return out; } +/** + * Convert a vector to a string. The values of the vector should be of a type supported by + * constToString. + */ +template <typename T> +std::string dumpVector(std::vector<T> values) { + std::string dump = constToString(values[0]); + for (size_t i = 1; i < values.size(); i++) { + dump += ", " + constToString(values[i]); + } + return dump; +} + const char* toString(bool value); /** @@ -77,4 +111,4 @@ const char* toString(bool value); */ std::string addLinePrefix(std::string str, const std::string& prefix); -} // namespace android
\ No newline at end of file +} // namespace android 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/RingBuffer.h b/include/input/RingBuffer.h new file mode 100644 index 0000000000..67984b7c80 --- /dev/null +++ b/include/input/RingBuffer.h @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2023 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 <compare> +#include <cstddef> +#include <iterator> +#include <memory> +#include <type_traits> +#include <utility> + +#include <android-base/logging.h> +#include <android-base/stringprintf.h> + +namespace android { + +// A fixed-size ring buffer of elements. +// +// Elements can only be removed from the front/back or added to the front/back, but with O(1) +// performance. Elements from the opposing side are evicted when new elements are pushed onto a full +// buffer. +template <typename T> +class RingBuffer { +public: + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + + template <typename U> + class Iterator; + using iterator = Iterator<T>; + using const_iterator = Iterator<const T>; + + // Creates an empty ring buffer that can hold some capacity. + explicit RingBuffer(size_type capacity) + : mBuffer(std::allocator<value_type>().allocate(capacity)), mCapacity(capacity) {} + + // Creates a full ring buffer holding a fixed number of elements initialised to some value. + explicit RingBuffer(size_type count, const_reference value) : RingBuffer(count) { + while (count) { + pushBack(value); + --count; + } + } + + RingBuffer(const RingBuffer& other) : RingBuffer(other.capacity()) { + for (const auto& element : other) { + pushBack(element); + } + } + + RingBuffer(RingBuffer&& other) noexcept { *this = std::move(other); } + + ~RingBuffer() { + if (mBuffer) { + clear(); + std::allocator<value_type>().deallocate(mBuffer, mCapacity); + } + } + + RingBuffer& operator=(const RingBuffer& other) { return *this = RingBuffer(other); } + + RingBuffer& operator=(RingBuffer&& other) noexcept { + if (this == &other) { + return *this; + } + if (mBuffer) { + clear(); + std::allocator<value_type>().deallocate(mBuffer, mCapacity); + } + mBuffer = std::move(other.mBuffer); + mCapacity = other.mCapacity; + mBegin = other.mBegin; + mSize = other.mSize; + other.mBuffer = nullptr; + other.mCapacity = 0; + other.mBegin = 0; + other.mSize = 0; + return *this; + } + + iterator begin() { return {*this, 0}; } + const_iterator begin() const { return {*this, 0}; } + iterator end() { return {*this, mSize}; } + const_iterator end() const { return {*this, mSize}; } + + reference operator[](size_type i) { return mBuffer[bufferIndex(i)]; } + const_reference operator[](size_type i) const { return mBuffer[bufferIndex(i)]; } + + // Removes all elements from the buffer. + void clear() { + std::destroy(begin(), end()); + mSize = 0; + } + + // Removes and returns the first element from the buffer. + value_type popFront() { + value_type element = mBuffer[mBegin]; + std::destroy_at(std::addressof(mBuffer[mBegin])); + mBegin = next(mBegin); + --mSize; + return element; + } + + // Removes and returns the last element from the buffer. + value_type popBack() { + size_type backIndex = bufferIndex(mSize - 1); + value_type element = mBuffer[backIndex]; + std::destroy_at(std::addressof(mBuffer[backIndex])); + --mSize; + return element; + } + + // Adds an element to the front of the buffer. + void pushFront(const value_type& element) { pushFront(value_type(element)); } + void pushFront(value_type&& element) { + mBegin = previous(mBegin); + if (size() == capacity()) { + mBuffer[mBegin] = std::forward<value_type>(element); + } else { + // The space at mBuffer[mBegin] is uninitialised. + // TODO: Use std::construct_at when it becomes available. + new (std::addressof(mBuffer[mBegin])) value_type(std::forward<value_type>(element)); + ++mSize; + } + } + + // Adds an element to the back of the buffer. + void pushBack(const value_type& element) { pushBack(value_type(element)); } + void pushBack(value_type&& element) { + if (size() == capacity()) { + mBuffer[mBegin] = std::forward<value_type>(element); + mBegin = next(mBegin); + } else { + // The space at mBuffer[...] is uninitialised. + // TODO: Use std::construct_at when it becomes available. + new (std::addressof(mBuffer[bufferIndex(mSize)])) + value_type(std::forward<value_type>(element)); + ++mSize; + } + } + + bool empty() const { return mSize == 0; } + size_type capacity() const { return mCapacity; } + size_type size() const { return mSize; } + + void swap(RingBuffer& other) noexcept { + using std::swap; + swap(mBuffer, other.mBuffer); + swap(mCapacity, other.mCapacity); + swap(mBegin, other.mBegin); + swap(mSize, other.mSize); + } + + friend void swap(RingBuffer& lhs, RingBuffer& rhs) noexcept { lhs.swap(rhs); } + + template <typename U> + class Iterator { + private: + using ContainerType = std::conditional_t<std::is_const_v<U>, const RingBuffer, RingBuffer>; + + public: + using iterator_category = std::random_access_iterator_tag; + using size_type = ContainerType::size_type; + using difference_type = ContainerType::difference_type; + using value_type = std::remove_cv_t<U>; + using pointer = U*; + using reference = U&; + + Iterator(ContainerType& container, size_type index) + : mContainer(container), mIndex(index) {} + + Iterator(const Iterator&) = default; + Iterator& operator=(const Iterator&) = default; + + Iterator& operator++() { + ++mIndex; + return *this; + } + + Iterator operator++(int) { + Iterator iterator(*this); + ++(*this); + return iterator; + } + + Iterator& operator--() { + --mIndex; + return *this; + } + + Iterator operator--(int) { + Iterator iterator(*this); + --(*this); + return iterator; + } + + Iterator& operator+=(difference_type n) { + mIndex += n; + return *this; + } + + Iterator operator+(difference_type n) { + Iterator iterator(*this); + return iterator += n; + } + + Iterator& operator-=(difference_type n) { return *this += -n; } + + Iterator operator-(difference_type n) { + Iterator iterator(*this); + return iterator -= n; + } + + difference_type operator-(const Iterator& other) { return mIndex - other.mIndex; } + + bool operator==(const Iterator& rhs) const { return mIndex == rhs.mIndex; } + + bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } + + friend auto operator<=>(const Iterator& lhs, const Iterator& rhs) { + return lhs.mIndex <=> rhs.mIndex; + } + + reference operator[](difference_type n) { return *(*this + n); } + + reference operator*() const { return mContainer[mIndex]; } + pointer operator->() const { return std::addressof(mContainer[mIndex]); } + + private: + ContainerType& mContainer; + size_type mIndex = 0; + }; + +private: + // Returns the index of the next element in mBuffer. + size_type next(size_type index) const { + if (index == capacity() - 1) { + return 0; + } else { + return index + 1; + } + } + + // Returns the index of the previous element in mBuffer. + size_type previous(size_type index) const { + if (index == 0) { + return capacity() - 1; + } else { + return index - 1; + } + } + + // Converts the index of an element in [0, size()] to its corresponding index in mBuffer. + size_type bufferIndex(size_type elementIndex) const { + CHECK_LE(elementIndex, size()); + size_type index = mBegin + elementIndex; + if (index >= capacity()) { + index -= capacity(); + } + CHECK_LT(index, capacity()) + << android::base::StringPrintf("Invalid index calculated for element (%zu) " + "in buffer of size %zu", + elementIndex, size()); + return index; + } + + pointer mBuffer = nullptr; + size_type mCapacity = 0; // Total capacity of mBuffer. + size_type mBegin = 0; // Index of the first initialised element in mBuffer. + size_type mSize = 0; // Total number of initialised elements. +}; + +} // namespace android diff --git a/include/input/TfLiteMotionPredictor.h b/include/input/TfLiteMotionPredictor.h new file mode 100644 index 0000000000..54e2851a7a --- /dev/null +++ b/include/input/TfLiteMotionPredictor.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 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 <array> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <optional> +#include <span> + +#include <android-base/mapped_file.h> +#include <input/RingBuffer.h> + +#include <tensorflow/lite/core/api/error_reporter.h> +#include <tensorflow/lite/interpreter.h> +#include <tensorflow/lite/model.h> +#include <tensorflow/lite/signature_runner.h> + +namespace android { + +struct TfLiteMotionPredictorSample { + // The untransformed AMOTION_EVENT_AXIS_X and AMOTION_EVENT_AXIS_Y of the sample. + struct Point { + float x; + float y; + } position; + // The AMOTION_EVENT_AXIS_PRESSURE, _TILT, and _ORIENTATION. + float pressure; + float tilt; + float orientation; +}; + +inline TfLiteMotionPredictorSample::Point operator-(const TfLiteMotionPredictorSample::Point& lhs, + const TfLiteMotionPredictorSample::Point& rhs) { + return {.x = lhs.x - rhs.x, .y = lhs.y - rhs.y}; +} + +class TfLiteMotionPredictorModel; + +// Buffer storage for a TfLiteMotionPredictorModel. +class TfLiteMotionPredictorBuffers { +public: + // Creates buffer storage for a model with the given input length. + TfLiteMotionPredictorBuffers(size_t inputLength); + + // Adds a motion sample to the buffers. + void pushSample(int64_t timestamp, TfLiteMotionPredictorSample sample); + + // Returns true if the buffers are complete enough to generate a prediction. + bool isReady() const { + // Predictions can't be applied unless there are at least two points to determine + // the direction to apply them in. + return mAxisFrom && mAxisTo; + } + + // Resets all buffers to their initial state. + void reset(); + + // Copies the buffers to those of a model for prediction. + void copyTo(TfLiteMotionPredictorModel& model) const; + + // Returns the current axis of the buffer's samples. Only valid if isReady(). + TfLiteMotionPredictorSample axisFrom() const { return *mAxisFrom; } + TfLiteMotionPredictorSample axisTo() const { return *mAxisTo; } + + // Returns the timestamp of the last sample. + int64_t lastTimestamp() const { return mTimestamp; } + +private: + int64_t mTimestamp = 0; + + RingBuffer<float> mInputR; + RingBuffer<float> mInputPhi; + RingBuffer<float> mInputPressure; + RingBuffer<float> mInputTilt; + RingBuffer<float> mInputOrientation; + + // The samples defining the current polar axis. + std::optional<TfLiteMotionPredictorSample> mAxisFrom; + std::optional<TfLiteMotionPredictorSample> mAxisTo; +}; + +// A TFLite model for generating motion predictions. +class TfLiteMotionPredictorModel { +public: + // Creates a model from an encoded Flatbuffer model. + static std::unique_ptr<TfLiteMotionPredictorModel> create(const char* modelPath); + + ~TfLiteMotionPredictorModel(); + + // Returns the length of the model's input buffers. + size_t inputLength() const; + + // Executes the model. + // Returns true if the model successfully executed and the output tensors can be read. + bool invoke(); + + // Returns mutable buffers to the input tensors of inputLength() elements. + std::span<float> inputR(); + std::span<float> inputPhi(); + std::span<float> inputPressure(); + std::span<float> inputOrientation(); + std::span<float> inputTilt(); + + // Returns immutable buffers to the output tensors of identical length. Only valid after a + // successful call to invoke(). + std::span<const float> outputR() const; + std::span<const float> outputPhi() const; + std::span<const float> outputPressure() const; + +private: + explicit TfLiteMotionPredictorModel(std::unique_ptr<android::base::MappedFile> model); + + void allocateTensors(); + void attachInputTensors(); + void attachOutputTensors(); + + TfLiteTensor* mInputR = nullptr; + TfLiteTensor* mInputPhi = nullptr; + TfLiteTensor* mInputPressure = nullptr; + TfLiteTensor* mInputTilt = nullptr; + TfLiteTensor* mInputOrientation = nullptr; + + const TfLiteTensor* mOutputR = nullptr; + const TfLiteTensor* mOutputPhi = nullptr; + const TfLiteTensor* mOutputPressure = nullptr; + + std::unique_ptr<android::base::MappedFile> mFlatBuffer; + std::unique_ptr<tflite::ErrorReporter> mErrorReporter; + std::unique_ptr<tflite::FlatBufferModel> mModel; + std::unique_ptr<tflite::Interpreter> mInterpreter; + tflite::SignatureRunner* mRunner = nullptr; +}; + +} // namespace android diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h index eda628e233..1e4f6e7a4c 100644 --- a/include/input/TouchVideoFrame.h +++ b/include/input/TouchVideoFrame.h @@ -14,8 +14,9 @@ * limitations under the License. */ -#ifndef _LIBINPUT_TOUCHVIDEOFRAME_H -#define _LIBINPUT_TOUCHVIDEOFRAME_H +#pragma once + +#include <ui/Rotation.h> #include <stdint.h> #include <sys/time.h> @@ -59,7 +60,7 @@ public: * Rotate the video frame. * The rotation value is an enum from ui/Rotation.h */ - void rotate(int32_t orientation); + void rotate(ui::Rotation orientation); private: uint32_t mHeight; @@ -75,5 +76,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..da97c3e855 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,93 +47,113 @@ public: MAX = LEGACY, }; - struct Position { - float x, y; - }; - struct Estimator { static const size_t MAX_DEGREE = 4; // Estimator time base. - nsecs_t time; + nsecs_t time = 0; - // Polynomial coefficients describing motion in X and Y. - float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; + // Polynomial coefficients describing motion. + std::array<float, MAX_DEGREE + 1> coeff{}; // Polynomial degree (number of coefficients), or zero if no information is // available. - uint32_t degree; + uint32_t degree = 0; // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). - float confidence; - - inline void clear() { - time = 0; - degree = 0; - confidence = 0; - for (size_t i = 0; i <= MAX_DEGREE; i++) { - xCoeff[i] = 0; - yCoeff[i] = 0; + float confidence = 0; + }; + + /* + * Contains all available velocity data from a VelocityTracker. + */ + struct ComputedVelocity { + inline std::optional<float> getVelocity(int32_t axis, int32_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, int32_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(); - // Resets the velocity tracker state for specific pointers. + // Resets the velocity tracker state for a specific pointer. // Call this method when some pointers have changed and may be reusing // an id that was assigned to a different pointer earlier. - void clearPointers(BitSet32 idBits); + void clearPointer(int32_t pointerId); - // Adds movement information for a set of pointers. - // The idBits bitfield specifies the pointer ids of the pointers whose positions - // 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); + // Adds movement information for a pointer for a specific axis + void addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis, float position); // 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, int32_t pointerId) 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; + std::optional<Estimator> getEstimator(int32_t axis, int32_t pointerId) 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; } + inline int32_t getActivePointerId() const { return mActivePointerId.value_or(-1); } 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); + std::optional<int32_t> mActivePointerId; + + // 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,11 +167,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; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; + virtual void clearPointer(int32_t pointerId) = 0; + virtual void addMovement(nsecs_t eventTime, int32_t pointerId, float position) = 0; + virtual std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const = 0; }; @@ -159,30 +178,28 @@ public: */ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { public: - enum Weighting { + enum class Weighting { // No weights applied. All data points are equally reliable. - WEIGHTING_NONE, + NONE, // Weight by time delta. Data points clustered together are weighted less. - WEIGHTING_DELTA, + DELTA, // Weight such that points within a certain horizon are weighed more than those // outside of that horizon. - WEIGHTING_CENTRAL, + CENTRAL, // Weight such that points older than a certain amount are weighed less. - WEIGHTING_RECENT, + RECENT, }; // Degree must be no greater than Estimator::MAX_DEGREE. - LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); - virtual ~LeastSquaresVelocityTrackerStrategy(); + LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = Weighting::NONE); + ~LeastSquaresVelocityTrackerStrategy() override; - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + void clearPointer(int32_t pointerId) override; + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; + std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; private: // Sample horizon. @@ -195,20 +212,15 @@ private: struct Movement { nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + float position; }; - float chooseWeight(uint32_t index) const; + float chooseWeight(int32_t pointerId, uint32_t index) const; const uint32_t mDegree; const Weighting mWeighting; - uint32_t mIndex; - Movement mMovements[HISTORY_SIZE]; + std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; + std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; @@ -219,13 +231,11 @@ class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { public: // Degree must be 1 or 2. IntegratingVelocityTrackerStrategy(uint32_t degree); - ~IntegratingVelocityTrackerStrategy(); + ~IntegratingVelocityTrackerStrategy() override; - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + void clearPointer(int32_t pointerId) override; + void addMovement(nsecs_t eventTime, int32_t pointerId, float positions) override; + std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; private: // Current state estimate for a particular pointer. @@ -233,16 +243,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; }; @@ -253,13 +262,11 @@ private: class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { public: LegacyVelocityTrackerStrategy(); - virtual ~LegacyVelocityTrackerStrategy(); + ~LegacyVelocityTrackerStrategy() override; - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + void clearPointer(int32_t pointerId) override; + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; + std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; private: // Oldest sample to consider when calculating the velocity. @@ -273,28 +280,21 @@ private: struct Movement { nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + float position; }; - uint32_t mIndex; - Movement mMovements[HISTORY_SIZE]; + std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; + std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { public: - ImpulseVelocityTrackerStrategy(); - virtual ~ImpulseVelocityTrackerStrategy(); + ImpulseVelocityTrackerStrategy(bool deltaValues); + ~ImpulseVelocityTrackerStrategy() override; - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - void addMovement(nsecs_t eventTime, BitSet32 idBits, - const std::vector<VelocityTracker::Position>& positions) override; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; + void clearPointer(int32_t pointerId) override; + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; + std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override; private: // Sample horizon. @@ -307,18 +307,16 @@ private: struct Movement { nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } + float position; }; - size_t mIndex; - Movement mMovements[HISTORY_SIZE]; + // 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; + + std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex; + std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements; }; } // namespace android - -#endif // _LIBINPUT_VELOCITY_TRACKER_H diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h new file mode 100644 index 0000000000..13ffb581b4 --- /dev/null +++ b/include/input/VirtualInputDevice.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 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 <android-base/unique_fd.h> + +namespace android { + +enum class UinputAction { + RELEASE = 0, + PRESS = 1, + MOVE = 2, + CANCEL = 3, +}; + +class VirtualInputDevice { +public: + VirtualInputDevice(android::base::unique_fd fd); + virtual ~VirtualInputDevice(); + +protected: + const android::base::unique_fd mFd; + bool writeInputEvent(uint16_t type, uint16_t code, int32_t value); + bool writeEvKeyEvent(int32_t androidCode, int32_t androidAction, + const std::map<int, int>& evKeyCodeMapping, + const std::map<int, UinputAction>& actionMapping); +}; + +class VirtualKeyboard : public VirtualInputDevice { +public: + static const std::map<int, int> KEY_CODE_MAPPING; + // Expose to share with VirtualDpad. + static const std::map<int, UinputAction> KEY_ACTION_MAPPING; + VirtualKeyboard(android::base::unique_fd fd); + virtual ~VirtualKeyboard() override; + bool writeKeyEvent(int32_t androidKeyCode, int32_t androidAction); +}; + +class VirtualDpad : public VirtualInputDevice { +public: + static const std::map<int, int> DPAD_KEY_CODE_MAPPING; + VirtualDpad(android::base::unique_fd fd); + virtual ~VirtualDpad() override; + bool writeDpadKeyEvent(int32_t androidKeyCode, int32_t androidAction); +}; + +class VirtualMouse : public VirtualInputDevice { +public: + VirtualMouse(android::base::unique_fd fd); + virtual ~VirtualMouse() override; + bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction); + // TODO(b/259554911): changing float parameters to int32_t. + bool writeRelativeEvent(float relativeX, float relativeY); + bool writeScrollEvent(float xAxisMovement, float yAxisMovement); + +private: + static const std::map<int, UinputAction> BUTTON_ACTION_MAPPING; + static const std::map<int, int> BUTTON_CODE_MAPPING; +}; + +class VirtualTouchscreen : public VirtualInputDevice { +public: + VirtualTouchscreen(android::base::unique_fd fd); + virtual ~VirtualTouchscreen() override; + // TODO(b/259554911): changing float parameters to int32_t. + bool writeTouchEvent(int32_t pointerId, int32_t toolType, int32_t action, float locationX, + float locationY, float pressure, float majorAxisSize); + +private: + static const std::map<int, UinputAction> TOUCH_ACTION_MAPPING; + static const std::map<int, int> TOOL_TYPE_MAPPING; + + /* The set of active touch pointers on this device. + * We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual + * touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id + * to go up to MAX_POINTERS_ID. + */ + std::bitset<MAX_POINTERS> mActivePointers{}; + bool isValidPointerId(int32_t pointerId, UinputAction uinputAction); + bool handleTouchDown(int32_t pointerId); + bool handleTouchUp(int32_t pointerId); +}; +} // namespace android 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. diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index f27f5f150f..eaf3b5e791 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -24,6 +24,51 @@ __BEGIN_DECLS */ void APerformanceHint_setIHintManagerForTesting(void* iManager); +/** + * Hints for the session used 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, +}; + +/** + * 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(void* session, int hint); + +/** + * Return the list of thread ids, this API should only be used for testing only. + */ +int APerformanceHint_getThreadIds(void* aPerformanceHintSession, + int32_t* const threadIds, size_t* const size); + __END_DECLS #endif // ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h index 7e6c51587d..138926e55b 100644 --- a/include/private/surface_control_private.h +++ b/include/private/surface_control_private.h @@ -19,6 +19,8 @@ #include <stdint.h> +#include <android/choreographer.h> + __BEGIN_DECLS struct ASurfaceControl; @@ -56,6 +58,13 @@ void ASurfaceControl_unregisterSurfaceStatsListener(void* context, ASurfaceControl_SurfaceStatsListener func); /** + * Gets the attached AChoreographer instance from the given \c surfaceControl. If there is no + * choreographer associated with the surface control, then a new instance of choreographer is + * created. The new choreographer is associated with the current thread's Looper. + */ +AChoreographer* ASurfaceControl_getChoreographer(ASurfaceControl* surfaceControl); + +/** * Returns the timestamp of when the buffer was acquired for a specific frame with frame number * obtained from ASurfaceControlStats_getFrameNumber. */ |