summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/android/bitmap.h2
-rw-r--r--include/android/choreographer.h64
-rw-r--r--include/android/input.h83
-rw-r--r--include/android/multinetwork.h73
-rw-r--r--include/android/performance_hint.h164
-rw-r--r--include/android/sensor.h191
-rw-r--r--include/android/storage_manager.h6
-rw-r--r--include/android/surface_control.h20
-rw-r--r--include/binder/Enum.h22
-rw-r--r--include/ftl/cast.h84
-rw-r--r--include/ftl/concat.h84
-rw-r--r--include/ftl/details/array_traits.h (renamed from include/ftl/array_traits.h)68
-rw-r--r--include/ftl/details/cast.h57
-rw-r--r--include/ftl/details/concat.h62
-rw-r--r--include/ftl/details/future.h98
-rw-r--r--include/ftl/enum.h301
-rw-r--r--include/ftl/fake_guard.h90
-rw-r--r--include/ftl/flags.h (renamed from include/input/Flags.h)140
-rw-r--r--include/ftl/future.h146
-rw-r--r--include/ftl/initializer_list.h13
-rw-r--r--include/ftl/small_map.h164
-rw-r--r--include/ftl/small_vector.h115
-rw-r--r--include/ftl/static_vector.h70
-rw-r--r--include/ftl/string.h101
-rw-r--r--include/input/DisplayViewport.h11
-rw-r--r--include/input/Input.h138
-rw-r--r--include/input/InputApplication.h85
-rw-r--r--include/input/InputDevice.h7
-rw-r--r--include/input/InputTransport.h73
-rw-r--r--include/input/InputWindow.h280
-rw-r--r--include/input/KeyCharacterMap.h18
-rw-r--r--include/input/NamedEnum.h128
-rw-r--r--include/input/PrintTools.h70
-rw-r--r--include/powermanager/PowerHalWrapper.h4
-rw-r--r--include/private/performance_hint_private.h116
-rw-r--r--include/private/surface_control_private.h6
36 files changed, 2164 insertions, 990 deletions
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 6704a1ddf2..35f87f96ae 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -68,6 +68,8 @@ enum AndroidBitmapFormat {
ANDROID_BITMAP_FORMAT_A_8 = 8,
/** Each component is stored as a half float. **/
ANDROID_BITMAP_FORMAT_RGBA_F16 = 9,
+ /** Red: 10 bits, Green: 10 bits, Blue: 10 bits, Alpha: 2 bits. **/
+ ANDROID_BITMAP_FORMAT_RGBA_1010102 = 10,
};
/** Bitmap alpha format */
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index b743f491e4..63aa7ff6c0 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -39,6 +39,18 @@ struct AChoreographer;
*/
typedef struct AChoreographer AChoreographer;
+
+/**
+ * The identifier of a frame timeline.
+ */
+typedef int64_t AVsyncId;
+
+struct AChoreographerFrameCallbackData;
+/**
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ */
+typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
+
/**
* Prototype of the function that is called when a new frame is being rendered.
* It's passed the time that the frame is being rendered as nanoseconds in the
@@ -60,6 +72,14 @@ typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data);
typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
/**
+ * Prototype of the function that is called when a new frame is being rendered.
+ * It's passed the frame data that should not outlive the callback, as well as the data pointer
+ * provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_vsyncCallback)(
+ const AChoreographerFrameCallbackData* callbackData, void* data);
+
+/**
* Prototype of the function that is called when the display refresh rate
* changes. It's passed the new vsync period in nanoseconds, as well as the data
* pointer provided by the application that registered a callback.
@@ -111,6 +131,14 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
uint32_t delayMillis) __INTRODUCED_IN(29);
/**
+ * Posts a callback to run on the next frame. The data pointer provided will
+ * be passed to the callback function when it's called.
+ */
+void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
+ AChoreographer_vsyncCallback callback, void* data)
+ __INTRODUCED_IN(33);
+
+/**
* Registers a callback to be run when the display refresh rate changes. The
* data pointer provided will be passed to the callback function when it's
* called. The same callback may be registered multiple times, provided that a
@@ -160,6 +188,42 @@ void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback, void* data)
__INTRODUCED_IN(30);
+/**
+ * The time in nanoseconds when the frame started being rendered.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The number of possible frame timelines.
+ */
+size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * Get index of the platform-preferred FrameTimeline.
+ */
+size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The vsync ID token used to map Choreographer data.
+ */
+AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index is expected to be presented.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index needs to be ready by.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/include/android/input.h b/include/android/input.h
index bb98beb41a..38b27bc587 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -169,6 +169,9 @@ enum {
/** Drag event */
AINPUT_EVENT_TYPE_DRAG = 5,
+
+ /** TouchMode event */
+ AINPUT_EVENT_TYPE_TOUCH_MODE = 6,
};
/**
@@ -805,6 +808,34 @@ enum {
};
/**
+ * Constants that identify different gesture classification types.
+ */
+enum AMotionClassification : uint32_t {
+ /**
+ * Classification constant: None.
+ *
+ * No additional information is available about the current motion event stream.
+ */
+ AMOTION_EVENT_CLASSIFICATION_NONE = 0,
+ /**
+ * Classification constant: Ambiguous gesture.
+ *
+ * The user's intent with respect to the current event stream is not yet determined. Events
+ * starting in AMBIGUOUS_GESTURE will eventually resolve into either DEEP_PRESS or NONE.
+ * Gestural actions, such as scrolling, should be inhibited until the classification resolves
+ * to another value or the event stream ends.
+ */
+ AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE = 1,
+ /**
+ * Classification constant: Deep press.
+ *
+ * The current event stream represents the user intentionally pressing harder on the screen.
+ * This classification type should be used to accelerate the long press behaviour.
+ */
+ AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2,
+};
+
+/**
* Input source masks.
*
* Refer to the documentation on android.view.InputDevice for more details about input sources
@@ -874,6 +905,7 @@ enum {
* Keyboard types.
*
* Refer to the documentation on android.view.InputDevice for more details.
+ * Note: When adding a new keyboard type here InputDeviceInfo::setKeyboardType needs to be updated.
*/
enum {
/** none */
@@ -947,9 +979,10 @@ int32_t AInputEvent_getSource(const AInputEvent* event);
* and {@link AMotionEvent_fromJava()}.
* After returning, the specified AInputEvent* object becomes invalid and should no longer be used.
* The underlying Java object remains valid and does not change its state.
+ *
+ * Available since API level 31.
*/
-
-void AInputEvent_release(const AInputEvent* event);
+void AInputEvent_release(const AInputEvent* event) __INTRODUCED_IN(31);
/*** Accessors for key events only. ***/
@@ -1001,8 +1034,10 @@ int64_t AKeyEvent_getEventTime(const AInputEvent* key_event);
* Creates a native AInputEvent* object that is a copy of the specified Java android.view.KeyEvent.
* The result may be used with generic and KeyEvent-specific AInputEvent_* functions. The object
* returned by this function must be disposed using {@link AInputEvent_release()}.
+ *
+ * Available since API level 31.
*/
-const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent);
+const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent) __INTRODUCED_IN(31);
/*** Accessors for motion events only. ***/
@@ -1320,12 +1355,41 @@ float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index, size_t history_index);
/**
+ * Get the action button for the motion event. Returns a valid action button when the
+ * event is associated with a button press or button release action. For other actions
+ * the return value is undefined.
+ *
+ * @see #AMOTION_EVENT_BUTTON_PRIMARY
+ * @see #AMOTION_EVENT_BUTTON_SECONDARY
+ * @see #AMOTION_EVENT_BUTTON_TERTIARY
+ * @see #AMOTION_EVENT_BUTTON_BACK
+ * @see #AMOTION_EVENT_BUTTON_FORWARD
+ * @see #AMOTION_EVENT_BUTTON_STYLUS_PRIMARY
+ * @see #AMOTION_EVENT_BUTTON_STYLUS_SECONDARY
+ */
+int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event)
+ __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
+ * Returns the classification for the current gesture.
+ * The classification may change as more events become available for the same gesture.
+ *
+ * @see #AMOTION_EVENT_CLASSIFICATION_NONE
+ * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE
+ * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS
+*/
+int32_t AMotionEvent_getClassification(const AInputEvent* motion_event)
+ __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
* Creates a native AInputEvent* object that is a copy of the specified Java
* android.view.MotionEvent. The result may be used with generic and MotionEvent-specific
* AInputEvent_* functions. The object returned by this function must be disposed using
* {@link AInputEvent_release()}.
+ *
+ * Available since API level 31.
*/
-const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent);
+const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent) __INTRODUCED_IN(31);
struct AInputQueue;
/**
@@ -1377,6 +1441,17 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event);
*/
void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled);
+/**
+ * Returns the AInputQueue* object associated with the supplied Java InputQueue
+ * object. The returned native object holds a weak reference to the Java object,
+ * and is only valid as long as the Java object has not yet been disposed. You
+ * should ensure that there is a strong reference to the Java object and that it
+ * has not been disposed before using the returned object.
+ *
+ * Available since API level 33.
+ */
+AInputQueue* AInputQueue_fromJava(JNIEnv* env, jobject inputQueue) __INTRODUCED_IN(33);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 509ee0e49b..ee392fc401 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -216,6 +216,79 @@ int android_res_nresult(int fd,
*/
void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
+/*
+ * Set the socket tag and owning UID for traffic statistics on the specified
+ * socket.
+ *
+ * Subsequent calls always replace any existing parameters. The socket tag and
+ * uid (if set) are kept when the socket is sent to another process using binder
+ * IPCs or other mechanisms such as UNIX socket fd passing. Any app can accept
+ * blame for future traffic performed on a socket originally created by another
+ * app by calling this method with its own UID (or calling
+ * android_tag_socket(int sockfd, int tag)). However, only apps holding the
+ * android.Manifest.permission#UPDATE_DEVICE_STATS permission may assign blame
+ * to another UIDs. If unset (default) the socket tag is 0, and the uid is the
+ * socket creator's uid.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Available since API level 33.
+ */
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33);
+
+/*
+ * Set the socket tag for traffic statistics on the specified socket.
+ *
+ * This function tags the socket with the caller's UID (accepting blame for
+ * future traffic performed on this socket) even if the socket was originally
+ * opened by another UID or was previously tagged by another UID. Subsequent
+ * calls always replace any existing parameters. The socket tag is kept when the
+ * socket is sent to another process using binder IPCs or other mechanisms such
+ * as UNIX socket fd passing. The tag is a value defined by the caller and used
+ * together with uid for data traffic accounting, so that the function callers
+ * can account different types of data usage for a uid.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Some possible error codes:
+ * -EBADF Bad socketfd.
+ * -EPERM No permission.
+ * -EAFNOSUPPORT Socket family is neither AF_INET nor AF_INET6.
+ * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP.
+ * -EMFILE Too many stats entries.
+ * There are still other error codes that may provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF maps read/write sys calls, which are set appropriately.
+ *
+ * Available since API level 33.
+ */
+int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33);
+
+/*
+ * Untag a network socket.
+ *
+ * Future traffic on this socket will no longer be associated with any
+ * previously configured tag and uid. If the socket was created by another UID
+ * or was previously tagged by another UID, calling this function will clear the
+ * statistics parameters, and thus the UID blamed for traffic on the socket will
+ * be the UID that originally created the socket, even if the socket was
+ * subsequently tagged by a different UID.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * One of possible error code:
+ * -EBADF Bad socketfd.
+ * Other error codes are either provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF map element deletion sys call, which are set appropriately.
+ *
+ * Available since API level 33.
+ */
+int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_MULTINETWORK_H
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
new file mode 100644
index 0000000000..5fa47f64be
--- /dev/null
+++ b/include/android/performance_hint.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_NATIVE_PERFORMANCE_HINT_H
+#define ANDROID_NATIVE_PERFORMANCE_HINT_H
+
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+#include <android/api-level.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+struct APerformanceHintManager;
+struct APerformanceHintSession;
+
+/**
+ * An opaque type representing a handle to a performance hint manager.
+ * It must be released after use.
+ *
+ * <p>To use:<ul>
+ * <li>Obtain the performance hint manager instance by calling
+ * {@link APerformanceHint_getManager} function.</li>
+ * <li>Create an {@link APerformanceHintSession} with
+ * {@link APerformanceHint_createSession}.</li>
+ * <li>Get the preferred update rate in nanoseconds with
+ * {@link APerformanceHint_getPreferredUpdateRateNanos}.</li>
+ */
+typedef struct APerformanceHintManager APerformanceHintManager;
+
+/**
+ * An opaque type representing a handle to a performance hint session.
+ * A session can only be acquired from a {@link APerformanceHintManager}
+ * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be
+ * freed with {@link APerformanceHint_closeSession} after use.
+ *
+ * A Session represents a group of threads with an inter-related workload such that hints for
+ * their performance should be considered as a unit. The threads in a given session should be
+ * long-life and not created or destroyed dynamically.
+ *
+ * <p>Each session is expected to have a periodic workload with a target duration for each
+ * cycle. The cycle duration is likely greater than the target work duration to allow other
+ * parts of the pipeline to run within the available budget. For example, a renderer thread may
+ * work at 60hz in order to produce frames at the display's frame but have a target work
+ * duration of only 6ms.</p>
+ *
+ * <p>After each cycle of work, the client is expected to use
+ * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to
+ * complete.</p>
+ *
+ * <p>To use:<ul>
+ * <li>Update a sessions target duration for each cycle of work
+ * with {@link APerformanceHint_updateTargetWorkDuration}.</li>
+ * <li>Report the actual duration for the last cycle of work with
+ * {@link APerformanceHint_reportActualWorkDuration}.</li>
+ * <li>Release the session instance with
+ * {@link APerformanceHint_closeSession}.</li></ul></p>
+ */
+typedef struct APerformanceHintSession APerformanceHintSession;
+
+/**
+ * Acquire an instance of the performance hint manager.
+ *
+ * @return manager instance on success, nullptr on failure.
+ */
+APerformanceHintManager* APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
+ * Creates a session for the given set of threads and sets their initial target work
+ * duration.
+ * @param manager The performance hint manager instance.
+ * @param threadIds The list of threads to be associated with this session. They must be part of
+ * this app's thread group.
+ * @param size the size of threadIds.
+ * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session.
+ * This must be positive.
+ * @return manager instance on success, nullptr on failure.
+ */
+APerformanceHintSession* APerformanceHint_createSession(
+ APerformanceHintManager* manager,
+ const int32_t* threadIds, size_t size,
+ int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
+ * Get preferred update rate information for this device.
+ *
+ * @param manager The performance hint manager instance.
+ * @return the preferred update rate supported by device software.
+ */
+int64_t APerformanceHint_getPreferredUpdateRateNanos(
+ APerformanceHintManager* manager) __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
+ * Updates this session's target duration for each cycle of work.
+ *
+ * @param session The performance hint session instance to update.
+ * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive.
+ * @return 0 on success
+ * EINVAL if targetDurationNanos is not positive.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_updateTargetWorkDuration(
+ APerformanceHintSession* session,
+ int64_t targetDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
+ * Reports the actual duration for the last cycle of work.
+ *
+ * <p>The system will attempt to adjust the core placement of the threads within the thread
+ * group and/or the frequency of the core on which they are run to bring the actual duration
+ * close to the target duration.</p>
+ *
+ * @param session The performance hint session instance to update.
+ * @param actualDurationNanos how long the thread group took to complete its last task in
+ * nanoseconds. This must be positive.
+ * @return 0 on success
+ * EINVAL if actualDurationNanos is not positive.
+ * EPIPE if communication with the system service has failed.
+ */
+int APerformanceHint_reportActualWorkDuration(
+ APerformanceHintSession* session,
+ int64_t actualDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
+ * Release the performance hint manager pointer acquired via
+ * {@link APerformanceHint_createSession}.
+ *
+ * @param session The performance hint session instance to release.
+ */
+void APerformanceHint_closeSession(
+ APerformanceHintSession* session) __INTRODUCED_IN(__ANDROID_API_T__);
+
+__END_DECLS
+
+#endif // ANDROID_NATIVE_PERFORMANCE_HINT_H
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 9dc6983e50..eef69f4b32 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -213,6 +213,13 @@ enum {
*/
ASENSOR_TYPE_HEART_BEAT = 31,
/**
+ * A constant describing a dynamic sensor meta event sensor.
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to or removed from
+ * the system. This sensor type should always use special trigger report mode.
+ */
+ ASENSOR_TYPE_DYNAMIC_SENSOR_META = 32,
+ /**
* This sensor type is for delivering additional sensor information aside
* from sensor event data.
*
@@ -256,6 +263,60 @@ enum {
* The hinge angle sensor value is returned in degrees.
*/
ASENSOR_TYPE_HINGE_ANGLE = 36,
+ /**
+ * {@link ASENSOR_TYPE_HEAD_TRACKER}
+ * reporting-mode: continuous
+ *
+ * Measures the orientation and rotational velocity of a user's head. Only for internal use
+ * within the Android system.
+ */
+ ASENSOR_TYPE_HEAD_TRACKER = 37,
+ /**
+ * {@link ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES}
+ * reporting-mode: continuous
+ *
+ * The first three values are in SI units (m/s^2) and measure the acceleration of the device
+ * minus the force of gravity. The last three values indicate which acceleration axes are
+ * supported. A value of 1.0 means supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES = 38,
+ /**
+ * {@link ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES}
+ * reporting-mode: continuous
+ *
+ * The first three values are in radians/second and measure the rate of rotation around the X,
+ * Y and Z axis. The last three values indicate which rotation axes are supported. A value of
+ * 1.0 means supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES = 39,
+ /**
+ * {@link ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED}
+ * reporting-mode: continuous
+ *
+ * The first three values are in SI units (m/s^2) and measure the acceleration of the device
+ * minus the force of gravity. The middle three values represent the estimated bias for each
+ * axis. The last three values indicate which acceleration axes are supported. A value of 1.0
+ * means supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40,
+ /**
+ * {@link ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED}
+ * reporting-mode: continuous
+ *
+ * The first three values are in radians/second and measure the rate of rotation around the X,
+ * Y and Z axis. The middle three values represent the estimated drift around each axis in
+ * rad/s. The last three values indicate which rotation axes are supported. A value of 1.0 means
+ * supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41,
+ /**
+ * {@link ASENSOR_TYPE_HEADING}
+ * reporting-mode: continuous
+ *
+ * A heading sensor measures the direction in which the device is pointing
+ * relative to true north in degrees.
+ */
+ ASENSOR_TYPE_HEADING = 42,
};
/**
@@ -440,6 +501,101 @@ typedef struct AAdditionalInfoEvent {
};
} AAdditionalInfoEvent;
+typedef struct AHeadTrackerEvent {
+ /**
+ * The fields rx, ry, rz are an Euler vector (rotation vector, i.e. a vector
+ * whose direction indicates the axis of rotation and magnitude indicates
+ * the angle to rotate around that axis) representing the transform from
+ * the (arbitrary, possibly slowly drifting) reference frame to the
+ * head frame. Expressed in radians. Magnitude of the vector must be
+ * in the range [0, pi], while the value of individual axes are
+ * in the range [-pi, pi].
+ */
+ float rx;
+ float ry;
+ float rz;
+
+ /**
+ * The fields vx, vy, vz are an Euler vector (rotation vector) representing
+ * the angular velocity of the head (relative to itself), in radians per
+ * second. The direction of this vector indicates the axis of rotation, and
+ * the magnitude indicates the rate of rotation.
+ */
+ float vx;
+ float vy;
+ float vz;
+
+ /**
+ * This value changes each time the reference frame is suddenly and
+ * significantly changed, for example if an orientation filter algorithm
+ * used for determining the orientation has had its state reset.
+ */
+ int32_t discontinuity_count;
+} AHeadTrackerEvent;
+
+typedef struct ALimitedAxesImuEvent {
+ union {
+ float calib[3];
+ struct {
+ float x;
+ float y;
+ float z;
+ };
+ };
+ union {
+ float supported[3];
+ struct {
+ float x_supported;
+ float y_supported;
+ float z_supported;
+ };
+ };
+} ALimitedAxesImuEvent;
+
+typedef struct ALimitedAxesImuUncalibratedEvent {
+ union {
+ float uncalib[3];
+ struct {
+ float x_uncalib;
+ float y_uncalib;
+ float z_uncalib;
+ };
+ };
+ union {
+ float bias[3];
+ struct {
+ float x_bias;
+ float y_bias;
+ float z_bias;
+ };
+ };
+ union {
+ float supported[3];
+ struct {
+ float x_supported;
+ float y_supported;
+ float z_supported;
+ };
+ };
+} ALimitedAxesImuUncalibratedEvent;
+
+typedef struct AHeadingEvent {
+ /**
+ * The direction in which the device is pointing relative to true north in
+ * degrees. The value must be between 0.0 (inclusive) and 360.0 (exclusive),
+ * with 0 indicating north, 90 east, 180 south, and 270 west.
+ */
+ float heading;
+ /**
+ * Accuracy is defined at 68% confidence. In the case where the underlying
+ * distribution is assumed Gaussian normal, this would be considered one
+ * standard deviation. For example, if the heading returns 60 degrees, and
+ * accuracy returns 10 degrees, then there is a 68 percent probability of
+ * the true heading being between 50 degrees and 70 degrees.
+ */
+ float accuracy;
+} AHeadingEvent;
+
/**
* Information that describes a sensor event, refer to
* <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
@@ -476,6 +632,10 @@ typedef struct ASensorEvent {
AHeartRateEvent heart_rate;
ADynamicSensorEvent dynamic_sensor_meta;
AAdditionalInfoEvent additional_info;
+ AHeadTrackerEvent head_tracker;
+ ALimitedAxesImuEvent limited_axes_imu;
+ ALimitedAxesImuUncalibratedEvent limited_axes_imu_uncalibrated;
+ AHeadingEvent heading;
};
union {
uint64_t data[8];
@@ -591,11 +751,40 @@ ASensorManager* ASensorManager_getInstance() __DEPRECATED_IN(26);
ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
/**
- * Returns the list of available sensors.
+ * Returns the list of available sensors. The returned list is owned by the
+ * sensor manager and will not change between calls to this function.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ * {@link ASensorManager_getInstanceForPackage}.
+ * \param list the returned list of sensors.
+ * \return positive number of returned sensors or negative error code.
+ * BAD_VALUE: manager is NULL.
*/
int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
/**
+ * Returns the list of available dynamic sensors. If there are no dynamic
+ * sensors available, returns nullptr in list.
+ *
+ * Each time this is called, the previously returned list is deallocated and
+ * must no longer be used.
+ *
+ * Clients should call this if they receive a sensor update from
+ * {@link ASENSOR_TYPE_DYNAMIC_SENSOR_META} indicating the sensors have changed.
+ * If this happens, previously received lists from this method will be stale.
+ *
+ * Available since API level 33.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ * {@link ASensorManager_getInstanceForPackage}.
+ * \param list the returned list of dynamic sensors.
+ * \return positive number of returned sensors or negative error code.
+ * BAD_VALUE: manager is NULL.
+ */
+ssize_t ASensorManager_getDynamicSensorList(
+ ASensorManager* manager, ASensorList* list) __INTRODUCED_IN(33);
+
+/**
* Returns the default sensor for the given type, or NULL if no sensor
* of that type exists.
*/
diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h
index 7f2ee08d62..270570e0df 100644
--- a/include/android/storage_manager.h
+++ b/include/android/storage_manager.h
@@ -124,6 +124,12 @@ typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const int3
/**
* Attempts to mount an OBB file. This is an asynchronous operation.
+ *
+ * Since API level 33, this function can only be used to mount unencrypted OBBs,
+ * i.e. the {@code key} parameter must be {@code null} or an empty string. Note
+ * that even before API level 33, mounting encrypted OBBs didn't work on many
+ * Android device implementations. Applications should not assume any particular
+ * behavior when {@code key} is nonempty.
*/
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key,
AStorageManager_obbCallbackFunc cb, void* data);
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 059bc41f9a..9a36ecb537 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
+#include <android/choreographer.h>
#include <android/data_space.h>
#include <android/hardware_buffer.h>
#include <android/hdr_metadata.h>
@@ -595,6 +596,25 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction,
bool enableBackPressure)
__INTRODUCED_IN(31);
+/**
+ * Sets the frame timeline to use in Surface Flinger.
+ *
+ * A frame timeline should be chosen based on what frame deadline the application
+ * can meet when rendering the frame and the application's desired present time.
+ * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding
+ * expected present time.
+ *
+ * To receive frame timelines, a callback must be posted to Choreographer using
+ * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the
+ * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId().
+ *
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
+ * the corresponding expected present time and deadline from the frame to be rendered. A stale or
+ * invalid value will be ignored.
+ */
+void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
+ AVsyncId vsyncId) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/binder/Enum.h b/include/binder/Enum.h
deleted file mode 100644
index 4c256546f6..0000000000
--- a/include/binder/Enum.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#error Do not rely on global include files. All Android cc_* programs are given access to \
- include_dirs for frameworks/native/include via global configuration, but this is legacy \
- configuration. Instead, you should have a direct dependency on libbinder OR one of your \
- dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/include/ftl/cast.h b/include/ftl/cast.h
new file mode 100644
index 0000000000..ff1b58ad56
--- /dev/null
+++ b/include/ftl/cast.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <type_traits>
+
+#include <ftl/details/cast.h>
+
+namespace android::ftl {
+
+enum class CastSafety { kSafe, kUnderflow, kOverflow };
+
+// Returns whether static_cast<R>(v) is safe, or would result in underflow or overflow.
+//
+// static_assert(ftl::cast_safety<uint8_t>(-1) == ftl::CastSafety::kUnderflow);
+// static_assert(ftl::cast_safety<int8_t>(128u) == ftl::CastSafety::kOverflow);
+//
+// static_assert(ftl::cast_safety<uint32_t>(-.1f) == ftl::CastSafety::kUnderflow);
+// static_assert(ftl::cast_safety<int32_t>(static_cast<float>(INT32_MAX)) ==
+// ftl::CastSafety::kOverflow);
+//
+// static_assert(ftl::cast_safety<float>(-DBL_MAX) == ftl::CastSafety::kUnderflow);
+//
+template <typename R, typename T>
+constexpr CastSafety cast_safety(T v) {
+ static_assert(std::is_arithmetic_v<T>);
+ static_assert(std::is_arithmetic_v<R>);
+
+ constexpr bool kFromSigned = std::is_signed_v<T>;
+ constexpr bool kToSigned = std::is_signed_v<R>;
+
+ using details::max_exponent;
+
+ // If the R range contains the T range, then casting is always safe.
+ if constexpr ((kFromSigned == kToSigned && max_exponent<R> >= max_exponent<T>) ||
+ (!kFromSigned && kToSigned && max_exponent<R> > max_exponent<T>)) {
+ return CastSafety::kSafe;
+ }
+
+ using C = std::common_type_t<R, T>;
+
+ if constexpr (kFromSigned) {
+ using L = details::safe_limits<R, T>;
+
+ if constexpr (kToSigned) {
+ // Signed to signed.
+ if (v < L::lowest()) return CastSafety::kUnderflow;
+ return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow;
+ } else {
+ // Signed to unsigned.
+ if (v < 0) return CastSafety::kUnderflow;
+ return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe
+ : CastSafety::kOverflow;
+ }
+ } else {
+ using L = std::numeric_limits<R>;
+
+ if constexpr (kToSigned) {
+ // Unsigned to signed.
+ return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe
+ : CastSafety::kOverflow;
+ } else {
+ // Unsigned to unsigned.
+ return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow;
+ }
+ }
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/concat.h b/include/ftl/concat.h
new file mode 100644
index 0000000000..ded48f7c8c
--- /dev/null
+++ b/include/ftl/concat.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ftl/details/concat.h>
+
+namespace android::ftl {
+
+// Lightweight (not allocating nor sprintf-based) concatenation.
+//
+// std::string_view name = "Volume";
+// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB");
+//
+// assert(string.str() == "Vol: -3 dB");
+// assert(string.c_str()[string.size()] == '\0');
+//
+template <std::size_t, typename... Ts>
+struct Concat;
+
+template <std::size_t N, typename T, typename... Ts>
+struct Concat<N, T, Ts...> : Concat<N + details::StaticString<T>::N, Ts...> {
+ explicit constexpr Concat(T v, Ts... args) { append(v, args...); }
+
+ protected:
+ constexpr Concat() = default;
+
+ constexpr void append(T v, Ts... args) {
+ using Str = details::StaticString<T>;
+ const Str str(v);
+
+ // TODO: Replace with constexpr std::copy in C++20.
+ for (auto it = str.view.begin(); it != str.view.end();) {
+ *this->end_++ = *it++;
+ }
+
+ using Base = Concat<N + Str::N, Ts...>;
+ this->Base::append(args...);
+ }
+};
+
+template <std::size_t N>
+struct Concat<N> {
+ static constexpr std::size_t max_size() { return N; }
+ constexpr std::size_t size() const { return end_ - buffer_; }
+
+ constexpr const char* c_str() const { return buffer_; }
+
+ constexpr std::string_view str() const {
+ // TODO: Replace with {buffer_, end_} in C++20.
+ return {buffer_, size()};
+ }
+
+ protected:
+ constexpr Concat() : end_(buffer_) {}
+ constexpr void append() { *end_ = '\0'; }
+
+ char buffer_[N + 1];
+ char* end_;
+};
+
+// Deduction guide.
+template <typename... Ts>
+Concat(Ts&&...) -> Concat<0, Ts...>;
+
+template <std::size_t N>
+constexpr auto truncated(std::string_view v) {
+ return details::Truncated<N>{v};
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/array_traits.h b/include/ftl/details/array_traits.h
index 1265fa15fe..5234c383a7 100644
--- a/include/ftl/array_traits.h
+++ b/include/ftl/details/array_traits.h
@@ -21,9 +21,9 @@
#include <new>
#include <type_traits>
-#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U
+#define FTL_ARRAY_TRAIT(T, U) using U = typename details::ArrayTraits<T>::U
-namespace android::ftl {
+namespace android::ftl::details {
template <typename T>
struct ArrayTraits {
@@ -42,7 +42,7 @@ struct ArrayTraits {
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
template <typename... Args>
- static pointer construct_at(const_iterator it, Args&&... args) {
+ static constexpr pointer construct_at(const_iterator it, Args&&... args) {
void* const ptr = const_cast<void*>(static_cast<const void*>(it));
if constexpr (std::is_constructible_v<value_type, Args...>) {
// TODO: Replace with std::construct_at in C++20.
@@ -52,6 +52,42 @@ struct ArrayTraits {
return new (ptr) value_type{std::forward<Args>(args)...};
}
}
+
+ // TODO: Make constexpr in C++20.
+ template <typename... Args>
+ static reference replace_at(const_iterator it, Args&&... args) {
+ value_type element{std::forward<Args>(args)...};
+ return replace_at(it, std::move(element));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static reference replace_at(const_iterator it, value_type&& value) {
+ std::destroy_at(it);
+ // This is only safe because exceptions are disabled.
+ return *construct_at(it, std::move(value));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static void in_place_swap(reference a, reference b) {
+ value_type c{std::move(a)};
+ replace_at(&a, std::move(b));
+ replace_at(&b, std::move(c));
+ }
+
+ // TODO: Make constexpr in C++20.
+ static void in_place_swap_ranges(iterator first1, iterator last1, iterator first2) {
+ while (first1 != last1) {
+ in_place_swap(*first1++, *first2++);
+ }
+ }
+
+ // TODO: Replace with std::uninitialized_copy in C++20.
+ template <typename Iterator>
+ static void uninitialized_copy(Iterator first, Iterator last, const_iterator out) {
+ while (first != last) {
+ construct_at(out++, *first++);
+ }
+ }
};
// CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end.
@@ -101,35 +137,35 @@ class ArrayIterators {
// TODO: Replace with operator<=> in C++20.
template <template <typename, std::size_t> class Array>
struct ArrayComparators {
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator==(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator<(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator>(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return rhs < lhs;
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator!=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs == rhs);
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator>=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs < rhs);
}
- template <typename T, std::size_t N, std::size_t M>
- friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ template <typename T, typename U, std::size_t N, std::size_t M>
+ friend bool operator<=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
return !(lhs > rhs);
}
};
-} // namespace android::ftl
+} // namespace android::ftl::details
diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h
new file mode 100644
index 0000000000..87b9f1e20a
--- /dev/null
+++ b/include/ftl/details/cast.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <type_traits>
+
+namespace android::ftl::details {
+
+// Exponent whose power of 2 is the (exclusive) upper bound of T.
+template <typename T, typename L = std::numeric_limits<T>>
+constexpr int max_exponent = std::is_floating_point_v<T> ? L::max_exponent : L::digits;
+
+// Extension of std::numeric_limits<T> that reduces the maximum for integral types T such that it
+// has an exact representation for floating-point types F. For example, the maximum int32_t value
+// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot
+// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is
+// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the
+// minimum is representable.
+template <typename T, typename F>
+struct safe_limits : std::numeric_limits<T> {
+ static constexpr T max() {
+ using Base = std::numeric_limits<T>;
+
+ if constexpr (std::is_integral_v<T> && std::is_floating_point_v<F>) {
+ // Assume the mantissa is 24 bits for float, or 53 bits for double.
+ using Float = std::numeric_limits<F>;
+ static_assert(Float::is_iec559);
+
+ // If the integer is wider than the mantissa, clear the excess bits of precision.
+ constexpr int kShift = Base::digits - Float::digits;
+ if constexpr (kShift > 0) {
+ using U = std::make_unsigned_t<T>;
+ constexpr U kOne = static_cast<U>(1);
+ return static_cast<U>(Base::max()) & ~((kOne << kShift) - kOne);
+ }
+ }
+
+ return Base::max();
+ }
+};
+
+} // namespace android::ftl::details
diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h
new file mode 100644
index 0000000000..8ce949ef05
--- /dev/null
+++ b/include/ftl/details/concat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <string_view>
+
+#include <ftl/string.h>
+
+namespace android::ftl::details {
+
+template <typename T, typename = void>
+struct StaticString;
+
+template <typename T>
+struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> {
+ static constexpr std::size_t N = to_chars_length_v<T>;
+
+ explicit StaticString(T v) : view(to_chars(buffer, v)) {}
+
+ to_chars_buffer_t<T> buffer;
+ const std::string_view view;
+};
+
+template <std::size_t M>
+struct StaticString<const char (&)[M], void> {
+ static constexpr std::size_t N = M - 1;
+
+ explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {}
+
+ const std::string_view view;
+};
+
+template <std::size_t N>
+struct Truncated {
+ std::string_view view;
+};
+
+template <std::size_t M>
+struct StaticString<Truncated<M>, void> {
+ static constexpr std::size_t N = M;
+
+ explicit constexpr StaticString(Truncated<M> str) : view(str.view.substr(0, N)) {}
+
+ const std::string_view view;
+};
+
+} // namespace android::ftl::details
diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h
new file mode 100644
index 0000000000..df1323e8be
--- /dev/null
+++ b/include/ftl/details/future.h
@@ -0,0 +1,98 @@
+/*
+ * 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 {
+
+template <typename, template <typename> class>
+class Future;
+
+namespace details {
+
+template <typename T>
+struct future_result {
+ using type = T;
+};
+
+template <typename T>
+struct future_result<std::future<T>> {
+ using type = T;
+};
+
+template <typename T>
+struct future_result<std::shared_future<T>> {
+ using type = T;
+};
+
+template <typename T, template <typename> class FutureImpl>
+struct future_result<Future<T, FutureImpl>> {
+ using type = T;
+};
+
+template <typename T>
+using future_result_t = typename future_result<T>::type;
+
+struct ValueTag {};
+
+template <typename, typename T, template <typename> class>
+class BaseFuture;
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::future> {
+ using Impl = std::future<T>;
+
+ public:
+ Future<T, std::shared_future> share() {
+ if (T* value = std::get_if<T>(&self())) {
+ return {ValueTag{}, std::move(*value)};
+ }
+
+ return std::get<Impl>(self()).share();
+ }
+
+ protected:
+ T get() {
+ if (T* value = std::get_if<T>(&self())) {
+ return std::move(*value);
+ }
+
+ return std::get<Impl>(self()).get();
+ }
+
+ private:
+ auto& self() { return static_cast<Self&>(*this).future_; }
+};
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::shared_future> {
+ using Impl = std::shared_future<T>;
+
+ protected:
+ const T& get() const {
+ if (const T* value = std::get_if<T>(&self())) {
+ return *value;
+ }
+
+ return std::get<Impl>(self()).get();
+ }
+
+ private:
+ const auto& self() const { return static_cast<const Self&>(*this).future_; }
+};
+
+} // namespace details
+} // namespace android::ftl
diff --git a/include/ftl/enum.h b/include/ftl/enum.h
new file mode 100644
index 0000000000..82af1d6cf8
--- /dev/null
+++ b/include/ftl/enum.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <limits>
+#include <optional>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+#include <ftl/string.h>
+
+// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> by parsing the
+// compiler-generated string literal for the signature of this function. The function is defined in
+// the global namespace with a short name and inferred return type to reduce bloat in the read-only
+// data segment.
+template <typename E, E V>
+constexpr auto ftl_enum() {
+ static_assert(std::is_enum_v<E>);
+
+ using R = std::optional<std::string_view>;
+ using namespace std::literals;
+
+ // The "pretty" signature has the following format:
+ //
+ // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue]
+ //
+ std::string_view view = __PRETTY_FUNCTION__;
+ const auto template_begin = view.rfind('[');
+ const auto template_end = view.rfind(']');
+ if (template_begin == view.npos || template_end == view.npos) return R{};
+
+ // Extract the template parameters without the enclosing brackets. Example (cont'd):
+ //
+ // E = android::test::Enum, V = android::test::Enum::kValue
+ //
+ view = view.substr(template_begin + 1, template_end - template_begin - 1);
+ const auto value_begin = view.rfind("V = "sv);
+ if (value_begin == view.npos) return R{};
+
+ // Example (cont'd):
+ //
+ // V = android::test::Enum::kValue
+ //
+ view = view.substr(value_begin);
+ const auto name_begin = view.rfind("::"sv);
+ if (name_begin == view.npos) return R{};
+
+ // Chop off the leading "::".
+ const auto name = view.substr(name_begin + 2);
+
+ // A value that is not enumerated has the format "Enum)42".
+ return name.find(')') == view.npos ? R{name} : R{};
+}
+
+namespace android::ftl {
+
+// Trait for determining whether a type is specifically a scoped enum or not. By definition, a
+// scoped enum is one that is not implicitly convertible to its underlying type.
+//
+// TODO: Replace with std::is_scoped_enum in C++23.
+//
+template <typename T, bool = std::is_enum_v<T>>
+struct is_scoped_enum : std::false_type {};
+
+template <typename T>
+struct is_scoped_enum<T, true> : std::negation<std::is_convertible<T, std::underlying_type_t<T>>> {
+};
+
+template <typename T>
+inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value;
+
+// Shorthand for casting an enumerator to its integral value.
+//
+// TODO: Replace with std::to_underlying in C++23.
+//
+// enum class E { A, B, C };
+// static_assert(ftl::to_underlying(E::B) == 1);
+//
+template <typename E>
+constexpr auto to_underlying(E v) {
+ return static_cast<std::underlying_type_t<E>>(v);
+}
+
+// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named
+// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1
+// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the
+// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of-
+// range values results in undefined behavior if the underlying type is not fixed.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// static_assert(ftl::enum_begin_v<E> == E::A);
+// static_assert(ftl::enum_last_v<E> == E::F);
+// static_assert(ftl::enum_size_v<E> == 6);
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// static_assert(ftl::enum_begin_v<F> == F{0});
+// static_assert(ftl::enum_last_v<F> == F{15});
+// static_assert(ftl::enum_size_v<F> == 16);
+//
+template <typename E, typename = void>
+struct enum_begin {
+ static_assert(is_scoped_enum_v<E>, "Missing ftl_first enumerator");
+ static constexpr E value{0};
+};
+
+template <typename E>
+struct enum_begin<E, std::void_t<decltype(E::ftl_first)>> {
+ static constexpr E value = E::ftl_first;
+};
+
+template <typename E>
+inline constexpr E enum_begin_v = enum_begin<E>::value;
+
+template <typename E, typename = void>
+struct enum_end {
+ using U = std::underlying_type_t<E>;
+ static_assert(is_scoped_enum_v<E> && std::is_unsigned_v<U>, "Missing ftl_last enumerator");
+
+ static constexpr E value{std::numeric_limits<U>::digits};
+};
+
+template <typename E>
+struct enum_end<E, std::void_t<decltype(E::ftl_last)>> {
+ static constexpr E value = E{to_underlying(E::ftl_last) + 1};
+};
+
+template <typename E>
+inline constexpr E enum_end_v = enum_end<E>::value;
+
+template <typename E>
+inline constexpr E enum_last_v = E{to_underlying(enum_end_v<E>) - 1};
+
+template <typename E>
+struct enum_size {
+ static constexpr auto kBegin = to_underlying(enum_begin_v<E>);
+ static constexpr auto kEnd = to_underlying(enum_end_v<E>);
+ static_assert(kBegin < kEnd, "Invalid range");
+
+ static constexpr std::size_t value = kEnd - kBegin;
+ static_assert(value <= 64, "Excessive range size");
+};
+
+template <typename E>
+inline constexpr std::size_t enum_size_v = enum_size<E>::value;
+
+namespace details {
+
+template <auto V>
+struct Identity {
+ static constexpr auto value = V;
+};
+
+template <typename E>
+using make_enum_sequence = std::make_integer_sequence<std::underlying_type_t<E>, enum_size_v<E>>;
+
+template <typename E, template <E> class = Identity, typename = make_enum_sequence<E>>
+struct EnumRange;
+
+template <typename E, template <E> class F, typename T, T... Vs>
+struct EnumRange<E, F, std::integer_sequence<T, Vs...>> {
+ static constexpr auto kBegin = to_underlying(enum_begin_v<E>);
+ static constexpr auto kSize = enum_size_v<E>;
+
+ using R = decltype(F<E{}>::value);
+ const R values[kSize] = {F<static_cast<E>(Vs + kBegin)>::value...};
+
+ constexpr const auto* begin() const { return values; }
+ constexpr const auto* end() const { return values + kSize; }
+};
+
+template <auto V>
+struct EnumName {
+ static constexpr auto value = ftl_enum<decltype(V), V>();
+};
+
+template <auto I>
+struct FlagName {
+ using E = decltype(I);
+ using U = std::underlying_type_t<E>;
+
+ static constexpr E V{U{1} << to_underlying(I)};
+ static constexpr auto value = ftl_enum<E, V>();
+};
+
+} // namespace details
+
+// Returns an iterable over the range of an enum.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// std::string string;
+// for (E v : ftl::enum_range<E>()) {
+// string += ftl::enum_name(v).value_or("?");
+// }
+//
+// assert(string == "ABC??F");
+//
+template <typename E>
+constexpr auto enum_range() {
+ return details::EnumRange<E>{};
+}
+
+// Returns a stringified enumerator at compile time.
+//
+// enum class E { A, B, C };
+// static_assert(ftl::enum_name<E::B>() == "B");
+//
+template <auto V>
+constexpr std::string_view enum_name() {
+ constexpr auto kName = ftl_enum<decltype(V), V>();
+ static_assert(kName, "Unknown enumerator");
+ return *kName;
+}
+
+// Returns a stringified enumerator, possibly at compile time.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// static_assert(ftl::enum_name(E::C).value_or("?") == "C");
+// static_assert(ftl::enum_name(E{3}).value_or("?") == "?");
+//
+template <typename E>
+constexpr std::optional<std::string_view> enum_name(E v) {
+ const auto value = to_underlying(v);
+
+ constexpr auto kBegin = to_underlying(enum_begin_v<E>);
+ constexpr auto kLast = to_underlying(enum_last_v<E>);
+ if (value < kBegin || value > kLast) return {};
+
+ constexpr auto kRange = details::EnumRange<E, details::EnumName>{};
+ return kRange.values[value - kBegin];
+}
+
+// Returns a stringified flag enumerator, possibly at compile time.
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z");
+// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?");
+//
+template <typename E>
+constexpr std::optional<std::string_view> flag_name(E v) {
+ const auto value = to_underlying(v);
+
+ // TODO: Replace with std::popcount and std::countr_zero in C++20.
+ if (__builtin_popcountll(value) != 1) return {};
+
+ constexpr auto kRange = details::EnumRange<E, details::FlagName>{};
+ return kRange.values[__builtin_ctzll(value)];
+}
+
+// Returns a stringified enumerator, or its integral value if not named.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// assert(ftl::enum_string(E::C) == "C");
+// assert(ftl::enum_string(E{3}) == "3");
+//
+template <typename E>
+inline std::string enum_string(E v) {
+ if (const auto name = enum_name(v)) {
+ return std::string(*name);
+ }
+ return to_string(to_underlying(v));
+}
+
+// Returns a stringified flag enumerator, or its integral value if not named.
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// assert(ftl::flag_string(F::Z) == "Z");
+// assert(ftl::flag_string(F{7}) == "0b111");
+//
+template <typename E>
+inline std::string flag_string(E v) {
+ if (const auto name = flag_name(v)) {
+ return std::string(*name);
+ }
+ constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex;
+ return to_string(to_underlying(v), radix);
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h
new file mode 100644
index 0000000000..bacd1b29ef
--- /dev/null
+++ b/include/ftl/fake_guard.h
@@ -0,0 +1,90 @@
+/*
+ * 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
+
+#define FTL_ATTRIBUTE(a) __attribute__((a))
+
+namespace android::ftl {
+
+// Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object,
+// FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope.
+// While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as
+// well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function):
+//
+// struct {
+// std::mutex mutex;
+// int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+//
+// int f() {
+// {
+// ftl::FakeGuard guard(mutex);
+// x = 0;
+// }
+//
+// return FTL_FAKE_GUARD(mutex, x + 1);
+// }
+//
+// std::function<int()> g() const {
+// return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+// }
+// } s;
+//
+// assert(s.f() == 1);
+// assert(s.g()() == 0);
+//
+// An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and
+// reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can
+// use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting
+// exclusive access by a single thread. This is done by defining a global constant that represents a
+// thread context, and annotating guarded variables as if it were a mutex (though without any effect
+// at run time):
+//
+// constexpr class [[clang::capability("mutex")]] {
+// } kMainThreadContext;
+//
+template <typename Mutex>
+struct [[clang::scoped_lockable]] FakeGuard final {
+ explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {}
+ [[clang::release_capability()]] ~FakeGuard() {}
+
+ FakeGuard(const FakeGuard&) = delete;
+ FakeGuard& operator=(const FakeGuard&) = delete;
+};
+
+} // namespace android::ftl
+
+// TODO: Enable in C++23 once standard attributes can be used on lambdas.
+#if 0
+#define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]]
+#else
+#define FTL_FAKE_GUARD1(mutex) \
+ FTL_ATTRIBUTE(acquire_capability(mutex)) \
+ FTL_ATTRIBUTE(release_capability(mutex))
+#endif
+
+// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
+#define FTL_FAKE_GUARD2(mutex, expr) \
+ [&]() -> decltype(auto) { \
+ const android::ftl::FakeGuard guard(mutex); \
+ return (expr); \
+ }()
+
+#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard
+
+// The void argument suppresses a warning about zero variadic macro arguments.
+#define FTL_FAKE_GUARD(...) \
+ FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, void)(__VA_ARGS__)
diff --git a/include/input/Flags.h b/include/ftl/flags.h
index b12a9ed2c5..70aaa0e6dd 100644
--- a/include/input/Flags.h
+++ b/include/ftl/flags.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,79 +14,20 @@
* limitations under the License.
*/
-#include <android-base/stringprintf.h>
+#pragma once
-#include <array>
+#include <ftl/enum.h>
+#include <ftl/string.h>
+
+#include <bitset>
#include <cstdint>
-#include <optional>
+#include <iterator>
#include <string>
#include <type_traits>
-#include "NamedEnum.h"
-#include "utils/BitSet.h"
-
-#ifndef __UI_INPUT_FLAGS_H
-#define __UI_INPUT_FLAGS_H
-
-namespace android {
-
-namespace details {
-
-template <typename F>
-inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__;
-
-template <typename F, typename T, T... I>
-constexpr auto generate_flag_values(std::integer_sequence<T, I...> seq) {
- constexpr size_t count = seq.size();
-
- std::array<F, count> values{};
- for (size_t i = 0, v = 0; v < count; ++i) {
- values[v++] = static_cast<F>(T{1} << i);
- }
-
- return values;
-}
-
-template <typename F>
-inline constexpr auto flag_values = generate_flag_values<F>(
- std::make_integer_sequence<std::underlying_type_t<F>, flag_count<F>>{});
-
-template <typename F, std::size_t... I>
-constexpr auto generate_flag_names(std::index_sequence<I...>) noexcept {
- return std::array<std::optional<std::string_view>, sizeof...(I)>{
- {enum_value_name<F, flag_values<F>[I]>()...}};
-}
-
-template <typename F>
-inline constexpr auto flag_names =
- generate_flag_names<F>(std::make_index_sequence<flag_count<F>>{});
-
-// A trait for determining whether a type is specifically an enum class or not.
-template <typename T, bool = std::is_enum_v<T>>
-struct is_enum_class : std::false_type {};
-
-// By definition, an enum class is an enum that is not implicitly convertible to its underlying
-// type.
-template <typename T>
-struct is_enum_class<T, true>
- : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
-
-template <typename T>
-inline constexpr bool is_enum_class_v = is_enum_class<T>::value;
-} // namespace details
-
-template <auto V>
-constexpr auto flag_name() {
- using F = decltype(V);
- return details::enum_value_name<F, V>();
-}
+// TODO(b/185536303): Align with FTL style.
-template <typename F>
-constexpr std::optional<std::string_view> flag_name(F flag) {
- using U = std::underlying_type_t<F>;
- auto idx = static_cast<size_t>(__builtin_ctzl(static_cast<U>(flag)));
- return details::flag_names<F>[idx];
-}
+namespace android::ftl {
/* A class for handling flags defined by an enum or enum class in a type-safe way. */
template <typename F>
@@ -95,7 +36,7 @@ class Flags {
// further to avoid this restriction but in general we want to encourage the use of enums
// anyways.
static_assert(std::is_enum_v<F>, "Flags type must be an enum");
- using U = typename std::underlying_type_t<F>;
+ using U = std::underlying_type_t<F>;
public:
constexpr Flags(F f) : mFlags(static_cast<U>(f)) {}
@@ -107,29 +48,29 @@ public:
// should force them to be explicitly constructed from their underlying types to make full use
// of the type checker.
template <typename T = U>
- constexpr Flags(T t, typename std::enable_if_t<!details::is_enum_class_v<F>, T>* = nullptr)
- : mFlags(t) {}
+ constexpr Flags(T t, std::enable_if_t<!is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
+
template <typename T = U>
- explicit constexpr Flags(T t,
- typename std::enable_if_t<details::is_enum_class_v<F>, T>* = nullptr)
+ explicit constexpr Flags(T t, std::enable_if_t<is_scoped_enum_v<F>, T>* = nullptr)
: mFlags(t) {}
class Iterator {
- // The type can't be larger than 64-bits otherwise it won't fit in BitSet64.
- static_assert(sizeof(U) <= sizeof(uint64_t));
+ using Bits = std::uint64_t;
+ static_assert(sizeof(U) <= sizeof(Bits));
public:
+ constexpr Iterator() = default;
Iterator(Flags<F> flags) : mRemainingFlags(flags.mFlags) { (*this)++; }
- Iterator() : mRemainingFlags(0), mCurrFlag(static_cast<F>(0)) {}
// Pre-fix ++
Iterator& operator++() {
- if (mRemainingFlags.isEmpty()) {
- mCurrFlag = static_cast<F>(0);
+ if (mRemainingFlags.none()) {
+ mCurrFlag = 0;
} else {
- uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left
- const U flag = 1 << (64 - bit - 1);
- mCurrFlag = static_cast<F>(flag);
+ // TODO: Replace with std::countr_zero in C++20.
+ const Bits bit = static_cast<Bits>(__builtin_ctzll(mRemainingFlags.to_ullong()));
+ mRemainingFlags.reset(static_cast<std::size_t>(bit));
+ mCurrFlag = static_cast<U>(static_cast<Bits>(1) << bit);
}
return *this;
}
@@ -147,7 +88,7 @@ public:
bool operator!=(Iterator other) const { return !(*this == other); }
- F operator*() { return mCurrFlag; }
+ F operator*() const { return F{mCurrFlag}; }
// iterator traits
@@ -166,8 +107,8 @@ public:
using pointer = void;
private:
- BitSet64 mRemainingFlags;
- F mCurrFlag;
+ std::bitset<sizeof(Bits) * 8> mRemainingFlags;
+ U mCurrFlag = 0;
};
/*
@@ -179,10 +120,10 @@ public:
}
/* Tests whether any of the given flags are set */
- bool any(Flags<F> f) { return (mFlags & f.mFlags) != 0; }
+ bool any(Flags<F> f) const { return (mFlags & f.mFlags) != 0; }
/* Tests whether all of the given flags are set */
- bool all(Flags<F> f) { return (mFlags & f.mFlags) == f.mFlags; }
+ 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); }
Flags<F>& operator|=(Flags<F> rhs) {
@@ -212,6 +153,10 @@ public:
return *this;
}
+ inline Flags<F>& clear(Flags<F> f = static_cast<F>(~static_cast<U>(0))) {
+ return *this &= ~f;
+ }
+
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator(); }
@@ -230,16 +175,16 @@ public:
bool first = true;
U unstringified = 0;
for (const F f : *this) {
- std::optional<std::string_view> flagString = flag_name(f);
- if (flagString) {
- appendFlag(result, flagString.value(), first);
+ if (const auto flagName = flag_name(f)) {
+ appendFlag(result, flagName.value(), first);
} else {
unstringified |= static_cast<U>(f);
}
}
if (unstringified != 0) {
- appendFlag(result, base::StringPrintf("0x%08x", unstringified), first);
+ constexpr auto radix = sizeof(U) == 1 ? Radix::kBin : Radix::kHex;
+ appendFlag(result, to_string(unstringified, radix), first);
}
if (first) {
@@ -266,18 +211,15 @@ private:
// as flags. In order to use these, add them via a `using namespace` declaration.
namespace flag_operators {
-template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>>
+template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
inline Flags<F> operator~(F f) {
- using U = typename std::underlying_type_t<F>;
- return static_cast<F>(~static_cast<U>(f));
+ return static_cast<F>(~to_underlying(f));
}
-template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>>
+
+template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
Flags<F> operator|(F lhs, F rhs) {
- using U = typename std::underlying_type_t<F>;
- return static_cast<F>(static_cast<U>(lhs) | static_cast<U>(rhs));
+ return static_cast<F>(to_underlying(lhs) | to_underlying(rhs));
}
} // namespace flag_operators
-} // namespace android
-
-#endif // __UI_INPUT_FLAGS_H
+} // namespace android::ftl
diff --git a/include/ftl/future.h b/include/ftl/future.h
index dd6358fa7d..c78f9b76b6 100644
--- a/include/ftl/future.h
+++ b/include/ftl/future.h
@@ -19,91 +19,115 @@
#include <future>
#include <type_traits>
#include <utility>
+#include <variant>
+
+#include <ftl/details/future.h>
namespace android::ftl {
-// Creates a future that defers a function call until its result is queried.
+// Thin wrapper around FutureImpl<T> (concretely std::future<T> or std::shared_future<T>) with
+// extensions for pure values (created via ftl::yield) and continuations.
//
-// auto future = ftl::defer([](int x) { return x + 1; }, 99);
-// assert(future.get() == 100);
+// See also SharedFuture<T> shorthand below.
//
-template <typename F, typename... Args>
-inline auto defer(F&& f, Args&&... args) {
- return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
-}
+template <typename T, template <typename> class FutureImpl = std::future>
+class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, FutureImpl> {
+ using Base = details::BaseFuture<Future, T, FutureImpl>;
-// Creates a future that wraps a value.
-//
-// auto future = ftl::yield(42);
-// assert(future.get() == 42);
-//
-// auto ptr = std::make_unique<char>('!');
-// auto future = ftl::yield(std::move(ptr));
-// assert(*future.get() == '!');
-//
-template <typename T>
-inline std::future<T> yield(T&& v) {
- return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
-}
-
-namespace details {
-
-template <typename T>
-struct future_result {
- using type = T;
-};
+ friend Base; // For BaseFuture<...>::self.
+ friend details::BaseFuture<Future<T>, T, std::future>; // For BaseFuture<...>::share.
-template <typename T>
-struct future_result<std::future<T>> {
- using type = T;
-};
-
-template <typename T>
-using future_result_t = typename future_result<T>::type;
+ public:
+ // Constructs an invalid future.
+ Future() : future_(std::in_place_type<FutureImpl<T>>) {}
-// Attaches a continuation to a future. The continuation is a function that maps T to either R or
-// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield.
-//
-// auto future = ftl::yield(123);
-// std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
-//
-// std::future<char> chain =
-// ftl::chain(std::move(future))
-// .then([](int x) { return static_cast<std::size_t>(x % 2); })
-// .then([&futures](std::size_t i) { return std::move(futures[i]); });
-//
-// assert(chain.get() == 'b');
-//
-template <typename T>
-struct Chain {
- // Implicit conversion.
- Chain(std::future<T>&& f) : future(std::move(f)) {}
- operator std::future<T>&&() && { return std::move(future); }
+ // Constructs a future from its standard counterpart, implicitly.
+ Future(FutureImpl<T>&& f) : future_(std::move(f)) {}
- T get() && { return future.get(); }
+ bool valid() const {
+ return std::holds_alternative<T>(future_) || std::get<FutureImpl<T>>(future_).valid();
+ }
+ // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the
+ // following are defined for either FutureImpl:
+ using Base::get;
+
+ // Attaches a continuation to the future. The continuation is a function that maps T to either R
+ // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by
+ // ftl::yield.
+ //
+ // auto future = ftl::yield(123);
+ // ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+ //
+ // auto chain =
+ // ftl::Future(std::move(future))
+ // .then([](int x) { return static_cast<std::size_t>(x % 2); })
+ // .then([&futures](std::size_t i) { return std::move(futures[i]); });
+ //
+ // assert(chain.get() == 'b');
+ //
template <typename F, typename R = std::invoke_result_t<F, T>>
- auto then(F&& op) && -> Chain<future_result_t<R>> {
+ auto then(F&& op) && -> Future<details::future_result_t<R>> {
return defer(
[](auto&& f, F&& op) {
R r = op(f.get());
- if constexpr (std::is_same_v<R, future_result_t<R>>) {
+ if constexpr (std::is_same_v<R, details::future_result_t<R>>) {
return r;
} else {
return r.get();
}
},
- std::move(future), std::forward<F>(op));
+ std::move(*this), std::forward<F>(op));
}
- std::future<T> future;
-};
+ private:
+ template <typename V>
+ friend Future<V> yield(V&&);
-} // namespace details
+ template <typename V, typename... Args>
+ friend Future<V> yield(Args&&...);
+
+ template <typename... Args>
+ Future(details::ValueTag, Args&&... args)
+ : future_(std::in_place_type<T>, std::forward<Args>(args)...) {}
+
+ std::variant<T, FutureImpl<T>> future_;
+};
template <typename T>
-inline auto chain(std::future<T>&& f) -> details::Chain<T> {
- return std::move(f);
+using SharedFuture = Future<T, std::shared_future>;
+
+// Deduction guide for implicit conversion.
+template <typename T, template <typename> class FutureImpl>
+Future(FutureImpl<T>&&) -> Future<T, FutureImpl>;
+
+// Creates a future that wraps a value.
+//
+// auto future = ftl::yield(42);
+// assert(future.get() == 42);
+//
+// auto ptr = std::make_unique<char>('!');
+// auto future = ftl::yield(std::move(ptr));
+// assert(*future.get() == '!');
+//
+template <typename V>
+inline Future<V> yield(V&& value) {
+ return {details::ValueTag{}, std::move(value)};
+}
+
+template <typename V, typename... Args>
+inline Future<V> yield(Args&&... args) {
+ return {details::ValueTag{}, std::forward<Args>(args)...};
+}
+
+// Creates a future that defers a function call until its result is queried.
+//
+// auto future = ftl::defer([](int x) { return x + 1; }, 99);
+// assert(future.get() == 100);
+//
+template <typename F, typename... Args>
+inline auto defer(F&& f, Args&&... args) {
+ return Future(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...));
}
} // namespace android::ftl
diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h
index 769c09ff11..2102c253f1 100644
--- a/include/ftl/initializer_list.h
+++ b/include/ftl/initializer_list.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <tuple>
#include <utility>
@@ -65,18 +66,18 @@ struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
std::tuple<Types...> tuple;
};
-template <typename K, typename V>
+template <typename K, typename V, typename KeyEqual = std::equal_to<K>>
struct KeyValue {};
// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
// with the latter.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
+template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
+struct InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...> {
// Accumulate the three arguments to std::pair's piecewise constructor.
template <typename... Args>
[[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
- KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
+ KeyValue<K, V, E>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
std::tuple<K&&>, std::tuple<Args&&...>> {
return {std::tuple_cat(
std::move(tuple),
@@ -94,9 +95,9 @@ template <typename T, typename... Args>
return InitializerList<T>{}(std::forward<Args>(args)...);
}
-template <typename K, typename V, typename... Args>
+template <typename K, typename V, typename E = std::equal_to<K>, typename... Args>
[[nodiscard]] constexpr auto map(Args&&... args) {
- return list<KeyValue<K, V>>(std::forward<Args>(args)...);
+ return list<KeyValue<K, V, E>>(std::forward<Args>(args)...);
}
template <typename K, typename V>
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 84c15ebdca..5217e76064 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -19,6 +19,7 @@
#include <ftl/initializer_list.h>
#include <ftl/small_vector.h>
+#include <algorithm>
#include <functional>
#include <optional>
#include <type_traits>
@@ -28,7 +29,10 @@ namespace android::ftl {
// Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are
// stored in contiguous storage for cache efficiency. The map is allocated statically until its size
-// exceeds N, at which point mappings are relocated to dynamic memory.
+// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has
+// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place
+// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator,
+// but immutable getters that can optionally transform the value.
//
// SmallMap<K, V, 0> unconditionally allocates on the heap.
//
@@ -43,21 +47,27 @@ namespace android::ftl {
// assert(!map.dynamic());
//
// assert(map.contains(123));
-// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u);
+// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u);
//
-// const auto opt = map.find(-1);
+// const auto opt = map.get(-1);
// assert(opt);
//
// std::string& ref = *opt;
// assert(ref.empty());
// ref = "xyz";
//
-// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+// map.emplace_or_replace(0, "vanilla", 2u, 3u);
+// assert(map.dynamic());
//
-template <typename K, typename V, std::size_t N>
+// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc")));
+//
+template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>>
class SmallMap final {
using Map = SmallVector<std::pair<const K, V>, N>;
+ template <typename, typename, std::size_t, typename>
+ friend class SmallMap;
+
public:
using key_type = K;
using mapped_type = V;
@@ -80,12 +90,7 @@ class SmallMap final {
// The syntax for listing pairs is as follows:
//
// ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
- //
// static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>);
- // assert(map.size() == 3u);
- // assert(map.contains(-1) && map.find(-1)->get().empty());
- // assert(map.contains(42) && map.find(42)->get() == "???");
- // assert(map.contains(123) && map.find(123)->get() == "abc");
//
// The types of the key and value are deduced if the first pair contains exactly two arguments:
//
@@ -95,9 +100,13 @@ class SmallMap final {
template <typename U, std::size_t... Sizes, typename... Types>
SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
: map_(std::move(list)) {
- // TODO: Enforce unique keys.
+ deduplicate();
}
+ // Copies or moves key-value pairs from a convertible map.
+ template <typename Q, typename W, std::size_t M, typename E>
+ SmallMap(SmallMap<Q, W, M, E> other) : map_(std::move(other.map_)) {}
+
size_type max_size() const { return map_.max_size(); }
size_type size() const { return map_.size(); }
bool empty() const { return map_.empty(); }
@@ -115,27 +124,27 @@ class SmallMap final {
// Returns whether a mapping exists for the given key.
bool contains(const key_type& key) const {
- return find(key, [](const mapped_type&) {});
+ return get(key, [](const mapped_type&) {});
}
// Returns a reference to the value for the given key, or std::nullopt if the key was not found.
//
// ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
//
- // const auto opt = map.find('c');
+ // const auto opt = map.get('c');
// assert(opt == 'C');
//
// char d = 'd';
- // const auto ref = map.find('d').value_or(std::ref(d));
+ // const auto ref = map.get('d').value_or(std::ref(d));
// ref.get() = 'D';
// assert(d == 'D');
//
- auto find(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
- return find(key, [](const mapped_type& v) { return std::cref(v); });
+ auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
+ return get(key, [](const mapped_type& v) { return std::cref(v); });
}
- auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
- return find(key, [](mapped_type& v) { return std::ref(v); });
+ auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
+ return get(key, [](mapped_type& v) { return std::ref(v); });
}
// Returns the result R of a unary operation F on (a constant or mutable reference to) the value
@@ -144,14 +153,14 @@ class SmallMap final {
//
// ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
//
- // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z');
- // assert(map.find('c', [](char& c) { c = std::toupper(c); }));
+ // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z');
+ // assert(map.get('c', [](char& c) { c = std::toupper(c); }));
//
template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>>
- auto find(const key_type& key, F f) const
+ auto get(const key_type& key, F f) const
-> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
for (auto& [k, v] : *this) {
- if (k == key) {
+ if (KeyEqual{}(k, key)) {
if constexpr (std::is_void_v<R>) {
f(v);
return true;
@@ -165,28 +174,119 @@ class SmallMap final {
}
template <typename F>
- auto find(const key_type& key, F f) {
- return std::as_const(*this).find(
+ auto get(const key_type& key, F f) {
+ return std::as_const(*this).get(
key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); });
}
+ // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise.
+ const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); }
+ iterator find(const key_type& key) { return find(key, begin()); }
+
+ // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping,
+ // and whether the mapping was inserted.
+ //
+ // On emplace, if the map reaches its static or dynamic capacity, then all iterators are
+ // invalidated. Otherwise, only the end() iterator is invalidated.
+ //
+ template <typename... Args>
+ std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
+ if (const auto it = find(key); it != end()) {
+ return {it, false};
+ }
+
+ auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return {&ref, true};
+ }
+
+ // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator
+ // otherwise.
+ //
+ // The value is replaced via move constructor, so type V does not need to define copy/move
+ // assignment, e.g. its data members may be const.
+ //
+ // The arguments may directly or indirectly refer to the mapping being replaced.
+ //
+ // Iterators to the replaced mapping point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ iterator try_replace(const key_type& key, Args&&... args) {
+ const auto it = find(key);
+ if (it == end()) return it;
+ map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return it;
+ }
+
+ // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or
+ // false on replace.
+ //
+ // The value is emplaced and replaced via move constructor, so type V does not need to define
+ // copy/move assignment, e.g. its data members may be const.
+ //
+ // On emplace, if the map reaches its static or dynamic capacity, then all iterators are
+ // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators
+ // to the replaced mapping point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ std::pair<iterator, bool> emplace_or_replace(const key_type& key, Args&&... args) {
+ const auto [it, ok] = try_emplace(key, std::forward<Args>(args)...);
+ if (ok) return {it, ok};
+ map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return {it, ok};
+ }
+
+ // Removes a mapping if it exists, and returns whether it did.
+ //
+ // The last() and end() iterators, as well as those to the erased mapping, are invalidated.
+ //
+ bool erase(const key_type& key) { return erase(key, begin()); }
+
+ // Removes all mappings.
+ //
+ // All iterators are invalidated.
+ //
+ void clear() { map_.clear(); }
+
private:
+ iterator find(const key_type& key, iterator first) {
+ return std::find_if(first, end(),
+ [&key](const auto& pair) { return KeyEqual{}(pair.first, key); });
+ }
+
+ bool erase(const key_type& key, iterator first) {
+ const auto it = find(key, first);
+ if (it == end()) return false;
+ map_.unstable_erase(it);
+ return true;
+ }
+
+ void deduplicate() {
+ for (auto it = begin(); it != end();) {
+ if (const auto key = it->first; ++it != end()) {
+ while (erase(key, it));
+ }
+ }
+ }
+
Map map_;
};
// Deduction guide for in-place constructor.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
- -> SmallMap<K, V, sizeof...(Sizes)>;
+template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
+SmallMap(InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallMap<K, V, sizeof...(Sizes), E>;
// Returns whether the key-value pairs of two maps are equal.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
+bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
if (lhs.size() != rhs.size()) return false;
for (const auto& [k, v] : lhs) {
const auto& lv = v;
- if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
+ if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
return false;
}
}
@@ -195,8 +295,8 @@ bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
}
// TODO: Remove in C++20.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
+inline bool operator!=(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
return !(lhs == rhs);
}
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index cb0ae359eb..339726e4ea 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -16,7 +16,7 @@
#pragma once
-#include <ftl/array_traits.h>
+#include <ftl/details/array_traits.h>
#include <ftl/static_vector.h>
#include <algorithm>
@@ -37,6 +37,9 @@ struct is_small_vector;
// augmented by an unstable_erase operation that does not preserve order, and a replace operation
// that destructively emplaces.
//
+// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data
+// members, or be const itself.
+//
// SmallVector<T, 0> is a specialization that thinly wraps std::vector.
//
// Example usage:
@@ -73,7 +76,7 @@ struct is_small_vector;
// assert(strings[2] == "???");
//
template <typename T, std::size_t N>
-class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
+class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<SmallVector> {
using Static = StaticVector<T, N>;
using Dynamic = SmallVector<T, 0>;
@@ -105,10 +108,9 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
SmallVector(Arg&& arg, Args&&... args)
: vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {}
- // Copies at most N elements from a smaller convertible vector.
- template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
- SmallVector(const SmallVector<U, M>& other)
- : SmallVector(kIteratorRange, other.begin(), other.end()) {}
+ // Copies or moves elements from a smaller convertible vector.
+ template <typename U, std::size_t M, typename = std::enable_if_t<(M > 0)>>
+ SmallVector(SmallVector<U, M> other) : vector_(convert(std::move(other))) {}
void swap(SmallVector& other) { vector_.swap(other.vector_); }
@@ -151,8 +153,6 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
DISPATCH(reference, back, noexcept)
DISPATCH(const_reference, back, const)
-#undef DISPATCH
-
reference operator[](size_type i) {
return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i];
}
@@ -214,13 +214,15 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
//
// The last() and end() iterators are invalidated.
//
- void pop_back() {
- if (dynamic()) {
- std::get<Dynamic>(vector_).pop_back();
- } else {
- std::get<Static>(vector_).pop_back();
- }
- }
+ DISPATCH(void, pop_back, noexcept)
+
+ // Removes all elements.
+ //
+ // All iterators are invalidated.
+ //
+ DISPATCH(void, clear, noexcept)
+
+#undef DISPATCH
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
@@ -235,7 +237,30 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
}
}
+ // Extracts the elements as std::vector.
+ std::vector<T> promote() && {
+ if (dynamic()) {
+ return std::get<Dynamic>(std::move(vector_)).promote();
+ } else {
+ return {std::make_move_iterator(begin()), std::make_move_iterator(end())};
+ }
+ }
+
private:
+ template <typename, std::size_t>
+ friend class SmallVector;
+
+ template <typename U, std::size_t M>
+ static std::variant<Static, Dynamic> convert(SmallVector<U, M>&& other) {
+ using Other = SmallVector<U, M>;
+
+ if (other.dynamic()) {
+ return std::get<typename Other::Dynamic>(std::move(other.vector_));
+ } else {
+ return std::get<typename Other::Static>(std::move(other.vector_));
+ }
+ }
+
template <auto InsertStatic, auto InsertDynamic, typename... Args>
auto insert(Args&&... args) {
if (Dynamic* const vector = std::get_if<Dynamic>(&vector_)) {
@@ -266,12 +291,13 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
// Partial specialization without static storage.
template <typename T>
-class SmallVector<T, 0> final : ArrayTraits<T>,
- ArrayIterators<SmallVector<T, 0>, T>,
+class SmallVector<T, 0> final : details::ArrayTraits<T>,
+ details::ArrayComparators<SmallVector>,
+ details::ArrayIterators<SmallVector<T, 0>, T>,
std::vector<T> {
- using ArrayTraits<T>::construct_at;
+ using details::ArrayTraits<T>::replace_at;
- using Iter = ArrayIterators<SmallVector, T>;
+ using Iter = details::ArrayIterators<SmallVector, T>;
using Impl = std::vector<T>;
friend Iter;
@@ -291,8 +317,30 @@ class SmallVector<T, 0> final : ArrayTraits<T>,
FTL_ARRAY_TRAIT(T, const_iterator);
FTL_ARRAY_TRAIT(T, const_reverse_iterator);
+ // See std::vector for underlying constructors.
using Impl::Impl;
+ // Copies and moves a vector, respectively.
+ SmallVector(const SmallVector&) = default;
+ SmallVector(SmallVector&&) = default;
+
+ // Constructs elements in place. See StaticVector for underlying constructor.
+ template <typename U, std::size_t... Sizes, typename... Types>
+ SmallVector(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
+ : SmallVector(SmallVector<T, sizeof...(Sizes)>(std::move(list))) {}
+
+ // Copies or moves elements from a convertible vector.
+ template <typename U, std::size_t M>
+ SmallVector(SmallVector<U, M> other) : Impl(convert(std::move(other))) {}
+
+ SmallVector& operator=(SmallVector other) {
+ // Define copy/move assignment in terms of copy/move construction.
+ swap(other);
+ return *this;
+ }
+
+ void swap(SmallVector& other) { Impl::swap(other); }
+
using Impl::empty;
using Impl::max_size;
using Impl::size;
@@ -324,10 +372,7 @@ class SmallVector<T, 0> final : ArrayTraits<T>,
template <typename... Args>
reference replace(const_iterator it, Args&&... args) {
- value_type element{std::forward<Args>(args)...};
- std::destroy_at(it);
- // This is only safe because exceptions are disabled.
- return *construct_at(it, std::move(element));
+ return replace_at(it, std::forward<Args>(args)...);
}
template <typename... Args>
@@ -345,14 +390,34 @@ class SmallVector<T, 0> final : ArrayTraits<T>,
return true;
}
+ using Impl::clear;
using Impl::pop_back;
void unstable_erase(iterator it) {
- if (it != last()) std::iter_swap(it, last());
+ if (it != last()) replace(it, std::move(back()));
pop_back();
}
- void swap(SmallVector& other) { Impl::swap(other); }
+ std::vector<T> promote() && { return std::move(*this); }
+
+ private:
+ template <typename U, std::size_t M>
+ static Impl convert(SmallVector<U, M>&& other) {
+ if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) {
+ return std::move(other).promote();
+ } else {
+ SmallVector vector(other.size());
+
+ // Consistently with StaticVector, T only requires copy/move construction from U, rather than
+ // copy/move assignment.
+ auto it = vector.begin();
+ for (auto& element : other) {
+ vector.replace(it++, std::move(element));
+ }
+
+ return vector;
+ }
+ }
};
template <typename>
diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h
index 96a1ae853d..eb83b85bfe 100644
--- a/include/ftl/static_vector.h
+++ b/include/ftl/static_vector.h
@@ -16,7 +16,7 @@
#pragma once
-#include <ftl/array_traits.h>
+#include <ftl/details/array_traits.h>
#include <ftl/initializer_list.h>
#include <algorithm>
@@ -39,6 +39,9 @@ constexpr struct IteratorRangeTag {
// adheres to standard containers, except the unstable_erase operation that does not preserve order,
// and the replace operation that destructively emplaces.
//
+// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data
+// members, or be const itself.
+//
// StaticVector<T, 1> is analogous to an iterable std::optional.
// StaticVector<T, 0> is an error.
//
@@ -73,14 +76,21 @@ constexpr struct IteratorRangeTag {
// assert(strings[2] == "???");
//
template <typename T, std::size_t N>
-class StaticVector final : ArrayTraits<T>,
- ArrayIterators<StaticVector<T, N>, T>,
- ArrayComparators<StaticVector> {
+class StaticVector final : details::ArrayTraits<T>,
+ details::ArrayIterators<StaticVector<T, N>, T>,
+ details::ArrayComparators<StaticVector> {
static_assert(N > 0);
- using ArrayTraits<T>::construct_at;
+ // For constructor that moves from a smaller convertible vector.
+ template <typename, std::size_t>
+ friend class StaticVector;
+
+ using details::ArrayTraits<T>::construct_at;
+ using details::ArrayTraits<T>::replace_at;
+ using details::ArrayTraits<T>::in_place_swap_ranges;
+ using details::ArrayTraits<T>::uninitialized_copy;
- using Iter = ArrayIterators<StaticVector, T>;
+ using Iter = details::ArrayIterators<StaticVector, T>;
friend Iter;
// There is ambiguity when constructing from two iterator-like elements like pointers:
@@ -117,14 +127,18 @@ class StaticVector final : ArrayTraits<T>,
StaticVector(StaticVector&& other) { swap<true>(other); }
// Copies at most N elements from a smaller convertible vector.
- template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
+ template <typename U, std::size_t M>
StaticVector(const StaticVector<U, M>& other)
- : StaticVector(kIteratorRange, other.begin(), other.end()) {}
+ : StaticVector(kIteratorRange, other.begin(), other.end()) {
+ static_assert(N >= M, "Insufficient capacity");
+ }
- // Copies at most N elements from an array.
+ // Copies at most N elements from a smaller convertible array.
template <typename U, std::size_t M>
explicit StaticVector(U (&array)[M])
- : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {}
+ : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {
+ static_assert(N >= M, "Insufficient capacity");
+ }
// Copies at most N elements from the range [first, last).
//
@@ -139,7 +153,18 @@ class StaticVector final : ArrayTraits<T>,
template <typename Iterator>
StaticVector(IteratorRangeTag, Iterator first, Iterator last)
: size_(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
- std::uninitialized_copy(first, first + size_, begin());
+ uninitialized_copy(first, first + size_, begin());
+ }
+
+ // Moves at most N elements from a smaller convertible vector.
+ template <typename U, std::size_t M>
+ StaticVector(StaticVector<U, M>&& other) {
+ static_assert(N >= M, "Insufficient capacity");
+
+ // Same logic as swap<true>, though M need not be equal to N.
+ std::uninitialized_move(other.begin(), other.end(), begin());
+ std::destroy(other.begin(), other.end());
+ std::swap(size_, other.size_);
}
// Constructs at most N elements. The template arguments T and N are inferred using the
@@ -178,7 +203,9 @@ class StaticVector final : ArrayTraits<T>,
template <typename U, std::size_t Size, std::size_t... Sizes, typename... Types>
StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& list)
: StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{},
- std::index_sequence<Sizes...>{}, list.tuple) {}
+ std::index_sequence<Sizes...>{}, list.tuple) {
+ static_assert(sizeof...(Sizes) < N, "Too many elements");
+ }
~StaticVector() { std::destroy(begin(), end()); }
@@ -189,8 +216,7 @@ class StaticVector final : ArrayTraits<T>,
}
StaticVector& operator=(StaticVector&& other) {
- std::destroy(begin(), end());
- size_ = 0;
+ clear();
swap<true>(other);
return *this;
}
@@ -239,10 +265,7 @@ class StaticVector final : ArrayTraits<T>,
//
template <typename... Args>
reference replace(const_iterator it, Args&&... args) {
- value_type element{std::forward<Args>(args)...};
- std::destroy_at(it);
- // This is only safe because exceptions are disabled.
- return *construct_at(it, std::move(element));
+ return replace_at(it, std::forward<Args>(args)...);
}
// Appends an element, and returns an iterator to it. If the vector is full, the element is not
@@ -280,6 +303,15 @@ class StaticVector final : ArrayTraits<T>,
//
void pop_back() { unstable_erase(last()); }
+ // Removes all elements.
+ //
+ // All iterators are invalidated.
+ //
+ void clear() {
+ std::destroy(begin(), end());
+ size_ = 0;
+ }
+
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
//
@@ -372,7 +404,7 @@ void StaticVector<T, N>::swap(StaticVector& other) {
}
// Swap elements [0, min).
- std::swap_ranges(begin(), begin() + min, other.begin());
+ in_place_swap_ranges(begin(), begin() + min, other.begin());
// No elements to move if sizes are equal.
if (min == max) return;
diff --git a/include/ftl/string.h b/include/ftl/string.h
new file mode 100644
index 0000000000..2d96b06a2f
--- /dev/null
+++ b/include/ftl/string.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <charconv>
+#include <limits>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+namespace android::ftl {
+
+enum class Radix { kBin = 2, kDec = 10, kHex = 16 };
+
+template <typename T>
+struct to_chars_length {
+ static_assert(std::is_integral_v<T>);
+ // Maximum binary digits, plus minus sign and radix prefix.
+ static constexpr std::size_t value = std::numeric_limits<std::make_unsigned_t<T>>::digits + 3;
+};
+
+template <typename T>
+constexpr std::size_t to_chars_length_v = to_chars_length<T>::value;
+
+template <typename T = std::int64_t>
+using to_chars_buffer_t = char[to_chars_length_v<T>];
+
+// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with
+// optional radix. See also ftl::to_string below.
+//
+// ftl::to_chars_buffer_t<> buffer;
+//
+// assert(ftl::to_chars(buffer, 123u) == "123");
+// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010");
+// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe");
+// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a");
+//
+template <typename T, std::size_t N>
+std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) {
+ static_assert(N >= to_chars_length_v<T>);
+
+ auto begin = buffer + 2;
+ const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast<int>(radix));
+ assert(err == std::errc());
+
+ if (radix == Radix::kDec) {
+ // TODO: Replace with {begin, end} in C++20.
+ return {begin, static_cast<std::size_t>(end - begin)};
+ }
+
+ const auto prefix = radix == Radix::kBin ? 'b' : 'x';
+ if constexpr (std::is_unsigned_v<T>) {
+ buffer[0] = '0';
+ buffer[1] = prefix;
+ } else {
+ if (*begin == '-') {
+ *buffer = '-';
+ } else {
+ --begin;
+ }
+
+ *begin-- = prefix;
+ *begin = '0';
+ }
+
+ // TODO: Replace with {buffer, end} in C++20.
+ return {buffer, static_cast<std::size_t>(end - buffer)};
+}
+
+// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix.
+//
+// assert(ftl::to_string(123u) == "123");
+// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010");
+// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe");
+// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a");
+//
+template <typename T>
+inline std::string to_string(T v, Radix radix = Radix::kDec) {
+ to_chars_buffer_t<T> buffer;
+ return std::string(to_chars(buffer, v, radix));
+}
+
+std::string to_string(bool) = delete;
+std::string to_string(bool, Radix) = delete;
+
+} // namespace android::ftl
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 5e40ca7ece..9148fee532 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -18,8 +18,10 @@
#define _LIBINPUT_DISPLAY_VIEWPORT_H
#include <android-base/stringprintf.h>
+#include <ftl/enum.h>
+#include <ftl/string.h>
+#include <gui/constants.h>
#include <input/Input.h>
-#include <input/NamedEnum.h>
#include <cinttypes>
#include <optional>
@@ -43,6 +45,8 @@ enum class ViewportType : int32_t {
INTERNAL = 1,
EXTERNAL = 2,
VIRTUAL = 3,
+
+ ftl_last = VIRTUAL
};
/*
@@ -131,9 +135,8 @@ struct DisplayViewport {
"physicalFrame=[%d, %d, %d, %d], "
"deviceSize=[%d, %d], "
"isActive=[%d]",
- NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(),
- physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str()
- : "<none>",
+ ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(),
+ physicalPort ? ftl::to_string(*physicalPort).c_str() : "<none>",
orientation, logicalLeft, logicalTop, logicalRight, logicalBottom,
physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth,
deviceHeight, isActive);
diff --git a/include/input/Input.h b/include/input/Input.h
index 2e326cb102..e7d68fc349 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -31,10 +31,8 @@
#include <stdint.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
-#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include <utils/Vector.h>
#include <array>
#include <limits>
#include <queue>
@@ -88,7 +86,7 @@ enum {
*/
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
-#ifdef __linux__
+#if defined(__linux__)
/**
* This event was generated or modified by accessibility service.
*/
@@ -124,15 +122,6 @@ constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBS
constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20;
enum {
- /* Used when a motion event is not associated with any display.
- * Typically used for non-pointer events. */
- ADISPLAY_ID_NONE = -1,
-
- /* The default display id. */
- ADISPLAY_ID_DEFAULT = 0,
-};
-
-enum {
/*
* Indicates that an input device has switches.
* This input source flag is hidden from the API because switches are only used by the system
@@ -175,7 +164,7 @@ enum {
* (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
* will occasionally emit 11. There is not much harm making this constant bigger.)
*/
-#define MAX_POINTERS 16
+static constexpr size_t MAX_POINTERS = 16;
/*
* Maximum number of samples supported per motion event.
@@ -210,8 +199,17 @@ namespace android {
class Parcel;
#endif
+/*
+ * Apply the given transform to the point without applying any translation/offset.
+ */
+vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy);
+
const char* inputEventTypeToString(int32_t type);
+std::string inputEventSourceToString(int32_t source);
+
+bool isFromSource(uint32_t source, uint32_t test);
+
/*
* Flags that flow alongside events in the input dispatch system to help with certain
* policy decisions such as waking from device sleep.
@@ -277,23 +275,21 @@ enum {
/**
* Classifications of the current gesture, if available.
- *
- * The following values must be kept in sync with MotionEvent.java
*/
enum class MotionClassification : uint8_t {
/**
* No classification is available.
*/
- NONE = 0,
+ NONE = AMOTION_EVENT_CLASSIFICATION_NONE,
/**
* Too early to classify the current gesture. Need more events. Look for changes in the
* upcoming motion events.
*/
- AMBIGUOUS_GESTURE = 1,
+ AMBIGUOUS_GESTURE = AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE,
/**
* The current gesture likely represents a user intentionally exerting force on the touchscreen.
*/
- DEEP_PRESS = 2,
+ DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS,
};
/**
@@ -354,12 +350,6 @@ private:
*/
constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN();
-/**
- * Invalid value for display size. Used when display size isn't available for an event or doesn't
- * matter. This is just a constant 0 so that it has no effect if unused.
- */
-constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0;
-
/*
* Pointer coordinate data.
*/
@@ -384,13 +374,10 @@ struct PointerCoords {
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- void scale(float globalScale);
-
// Scale the pointer coordinates according to a global scale and a
// window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
// axes, however the window scaling will not.
void scale(float globalScale, float windowXScale, float windowYScale);
- void applyOffset(float xOffset, float yOffset);
void transform(const ui::Transform& transform);
@@ -541,13 +528,17 @@ public:
inline int32_t getAction() const { return mAction; }
- inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
+ static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; }
+
+ inline int32_t getActionMasked() const { return getActionMasked(mAction); }
- inline int32_t getActionIndex() const {
- return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
- >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ static uint8_t getActionIndex(int32_t action) {
+ return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
+ AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
+ inline int32_t getActionIndex() const { return getActionIndex(mAction); }
+
inline void setAction(int32_t action) { mAction = action; }
inline int32_t getFlags() const { return mFlags; }
@@ -576,7 +567,9 @@ public:
inline float getYOffset() const { return mTransform.ty(); }
- inline ui::Transform getTransform() const { return mTransform; }
+ inline const ui::Transform& getTransform() const { return mTransform; }
+
+ int getSurfaceRotation() const;
inline float getXPrecision() const { return mXPrecision; }
@@ -592,7 +585,7 @@ public:
void setCursorPosition(float x, float y);
- int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
+ inline const ui::Transform& getRawTransform() const { return mRawTransform; }
static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
@@ -768,8 +761,8 @@ public:
int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float rawXCursorPosition,
- float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight,
- nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+ float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime,
+ nsecs_t eventTime, size_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -802,11 +795,11 @@ public:
// Low-level accessors.
inline const PointerProperties* getPointerProperties() const {
- return mPointerProperties.array();
+ return mPointerProperties.data();
}
inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); }
inline const PointerCoords* getSamplePointerCoords() const {
- return mSamplePointerCoords.array();
+ return mSamplePointerCoords.data();
}
static const char* getLabel(int32_t axis);
@@ -814,6 +807,16 @@ public:
static std::string actionToString(int32_t action);
+ // MotionEvent will transform various axes in different ways, based on the source. For
+ // example, the x and y axes will not have any offsets/translations applied if it comes from a
+ // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods
+ // are used to apply these transformations for different axes.
+ static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
+ static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
+ const PointerCoords&);
+ static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&,
+ const PointerCoords&);
+
protected:
int32_t mAction;
int32_t mActionButton;
@@ -827,14 +830,15 @@ protected:
float mYPrecision;
float mRawXCursorPosition;
float mRawYCursorPosition;
- int32_t mDisplayWidth;
- int32_t mDisplayHeight;
+ ui::Transform mRawTransform;
nsecs_t mDownTime;
- Vector<PointerProperties> mPointerProperties;
+ std::vector<PointerProperties> mPointerProperties;
std::vector<nsecs_t> mSampleEventTimes;
- Vector<PointerCoords> mSamplePointerCoords;
+ std::vector<PointerCoords> mSamplePointerCoords;
};
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event);
+
/*
* Focus events.
*/
@@ -846,15 +850,12 @@ public:
inline bool getHasFocus() const { return mHasFocus; }
- inline bool getInTouchMode() const { return mInTouchMode; }
-
- void initialize(int32_t id, bool hasFocus, bool inTouchMode);
+ void initialize(int32_t id, bool hasFocus);
void initialize(const FocusEvent& from);
protected:
bool mHasFocus;
- bool mInTouchMode;
};
/*
@@ -900,6 +901,25 @@ protected:
float mX, mY;
};
+/*
+ * Touch mode events.
+ */
+class TouchModeEvent : public InputEvent {
+public:
+ virtual ~TouchModeEvent() {}
+
+ virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_TOUCH_MODE; }
+
+ inline bool isInTouchMode() const { return mIsInTouchMode; }
+
+ void initialize(int32_t id, bool isInTouchMode);
+
+ void initialize(const TouchModeEvent& from);
+
+protected:
+ bool mIsInTouchMode;
+};
+
/**
* Base class for verified events.
* Do not create a VerifiedInputEvent explicitly.
@@ -924,8 +944,8 @@ struct __attribute__((__packed__)) VerifiedInputEvent {
*/
struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent {
int32_t action;
- nsecs_t downTimeNanos;
int32_t flags;
+ nsecs_t downTimeNanos;
int32_t keyCode;
int32_t scanCode;
int32_t metaState;
@@ -940,8 +960,8 @@ struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEve
float rawX;
float rawY;
int32_t actionMasked;
- nsecs_t downTimeNanos;
int32_t flags;
+ nsecs_t downTimeNanos;
int32_t metaState;
int32_t buttonState;
};
@@ -964,6 +984,7 @@ public:
virtual FocusEvent* createFocusEvent() = 0;
virtual CaptureEvent* createCaptureEvent() = 0;
virtual DragEvent* createDragEvent() = 0;
+ virtual TouchModeEvent* createTouchModeEvent() = 0;
};
/*
@@ -980,6 +1001,7 @@ public:
virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; }
virtual DragEvent* createDragEvent() override { return &mDragEvent; }
+ virtual TouchModeEvent* createTouchModeEvent() override { return &mTouchModeEvent; }
private:
KeyEvent mKeyEvent;
@@ -987,6 +1009,7 @@ private:
FocusEvent mFocusEvent;
CaptureEvent mCaptureEvent;
DragEvent mDragEvent;
+ TouchModeEvent mTouchModeEvent;
};
/*
@@ -1002,6 +1025,7 @@ public:
virtual FocusEvent* createFocusEvent() override;
virtual CaptureEvent* createCaptureEvent() override;
virtual DragEvent* createDragEvent() override;
+ virtual TouchModeEvent* createTouchModeEvent() override;
void recycle(InputEvent* event);
@@ -1013,6 +1037,26 @@ private:
std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool;
std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool;
std::queue<std::unique_ptr<DragEvent>> mDragEventPool;
+ std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool;
+};
+
+/*
+ * Describes a unique request to enable or disable Pointer Capture.
+ */
+struct PointerCaptureRequest {
+public:
+ inline PointerCaptureRequest() : enable(false), seq(0) {}
+ inline PointerCaptureRequest(bool enable, uint32_t seq) : enable(enable), seq(seq) {}
+ inline bool operator==(const PointerCaptureRequest& other) const {
+ return enable == other.enable && seq == other.seq;
+ }
+ explicit inline operator bool() const { return enable; }
+
+ // True iff this is a request to enable Pointer Capture.
+ bool enable;
+
+ // The sequence number for the request.
+ uint32_t seq;
};
} // namespace android
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
deleted file mode 100644
index 8e4fe796a5..0000000000
--- a/include/input/InputApplication.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_APPLICATION_H
-#define _UI_INPUT_APPLICATION_H
-
-#include <string>
-
-#include <android/InputApplicationInfo.h>
-
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-
-#include <input/Input.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-namespace android {
-/*
- * Handle for an application that can receive input.
- *
- * Used by the native input dispatcher as a handle for the window manager objects
- * that describe an application.
- */
-class InputApplicationHandle {
-public:
- inline const InputApplicationInfo* getInfo() const {
- return &mInfo;
- }
-
- inline std::string getName() const {
- return !mInfo.name.empty() ? mInfo.name : "<invalid>";
- }
-
- inline std::chrono::nanoseconds getDispatchingTimeout(
- std::chrono::nanoseconds defaultValue) const {
- return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis)
- : defaultValue;
- }
-
- inline sp<IBinder> getApplicationToken() const {
- return mInfo.token;
- }
-
- bool operator==(const InputApplicationHandle& other) const {
- return getName() == other.getName() && getApplicationToken() == other.getApplicationToken();
- }
-
- bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); }
-
- /**
- * Requests that the state of this object be updated to reflect
- * the most current available information about the application.
- *
- * This method should only be called from within the input dispatcher's
- * critical section.
- *
- * Returns true on success, or false if the handle is no longer valid.
- */
- virtual bool updateInfo() = 0;
-
-protected:
- InputApplicationHandle() = default;
- virtual ~InputApplicationHandle() = default;
-
- InputApplicationInfo mInfo;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_APPLICATION_H
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 7f0324a4a8..c4f03c9119 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -84,6 +84,9 @@ enum class InputDeviceSensorType : int32_t {
GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR,
GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION,
+
+ ftl_first = ACCELEROMETER,
+ ftl_last = SIGNIFICANT_MOTION
};
enum class InputDeviceSensorAccuracy : int32_t {
@@ -105,6 +108,8 @@ enum class InputDeviceLightType : int32_t {
PLAYER_ID = 1,
RGB = 2,
MULTI_COLOR = 3,
+
+ ftl_last = MULTI_COLOR
};
struct InputDeviceSensorInfo {
@@ -230,7 +235,7 @@ public:
void addBatteryInfo(const InputDeviceBatteryInfo& info);
void addLightInfo(const InputDeviceLightInfo& info);
- inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
+ void setKeyboardType(int32_t keyboardType);
inline int32_t getKeyboardType() const { return mKeyboardType; }
inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 360dfbfd73..5f9a37d69c 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -72,6 +72,9 @@ struct InputMessage {
CAPTURE,
DRAG,
TIMELINE,
+ TOUCH_MODE,
+
+ ftl_last = TOUCH_MODE
};
struct Header {
@@ -111,7 +114,7 @@ struct InputMessage {
struct Motion {
int32_t eventId;
- uint32_t empty1;
+ uint32_t pointerCount;
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
@@ -126,20 +129,22 @@ struct InputMessage {
uint8_t empty2[3]; // 3 bytes to fill gap created by classification
int32_t edgeFlags;
nsecs_t downTime __attribute__((aligned(8)));
- float dsdx;
- float dtdx;
- float dtdy;
- float dsdy;
- float tx;
- float ty;
+ float dsdx; // Begin window transform
+ float dtdx; //
+ float dtdy; //
+ float dsdy; //
+ float tx; //
+ float ty; // End window transform
float xPrecision;
float yPrecision;
float xCursorPosition;
float yCursorPosition;
- int32_t displayWidth;
- int32_t displayHeight;
- uint32_t pointerCount;
- uint32_t empty3;
+ float dsdxRaw; // Begin raw transform
+ float dtdxRaw; //
+ float dtdyRaw; //
+ float dsdyRaw; //
+ float txRaw; //
+ float tyRaw; // End raw transform
/**
* The "pointers" field must be the last field of the struct InputMessage.
* When we send the struct InputMessage across the socket, we are not
@@ -173,10 +178,9 @@ struct InputMessage {
struct Focus {
int32_t eventId;
- // The following 3 fields take up 4 bytes total
+ // The following 2 fields take up 4 bytes total
bool hasFocus;
- bool inTouchMode;
- uint8_t empty[2];
+ uint8_t empty[3];
inline size_t size() const { return sizeof(Focus); }
} focus;
@@ -206,6 +210,15 @@ struct InputMessage {
inline size_t size() const { return sizeof(Timeline); }
} timeline;
+
+ struct TouchMode {
+ int32_t eventId;
+ // The following 2 fields take up 4 bytes total
+ bool isInTouchMode;
+ uint8_t empty[3];
+
+ inline size_t size() const { return sizeof(TouchMode); }
+ } touchMode;
} __attribute__((aligned(8))) body;
bool isValid(size_t actualSize) const;
@@ -355,7 +368,7 @@ public:
int32_t metaState, int32_t buttonState,
MotionClassification classification, const ui::Transform& transform,
float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, int32_t displayWidth, int32_t displayHeight,
+ float yCursorPosition, const ui::Transform& rawTransform,
nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
@@ -367,7 +380,7 @@ public:
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
+ status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus);
/* Publishes a capture event to the input channel.
*
@@ -387,6 +400,15 @@ public:
*/
status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting);
+ /* Publishes a touch mode event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode);
+
struct Finished {
uint32_t seq;
bool handled;
@@ -478,24 +500,6 @@ public:
status_t sendTimeline(int32_t inputEventId,
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
- /* Returns true if there is a deferred event waiting.
- *
- * Should be called after calling consume() to determine whether the consumer
- * has a deferred event to be processed. Deferred events are somewhat special in
- * that they have already been removed from the input channel. If the input channel
- * becomes empty, the client may need to do extra work to ensure that it processes
- * the deferred event despite the fact that the input channel's file descriptor
- * is not readable.
- *
- * One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
- * This guarantees that all deferred events will be processed.
- *
- * Alternately, the caller can call hasDeferredEvent() to determine whether there is
- * a deferred event waiting and then ensure that its event loop wakes up at least
- * one more time to consume the deferred event.
- */
- bool hasDeferredEvent() const;
-
/* Returns true if there is a pending batch.
*
* Should be called after calling consume() with consumeBatches == false to determine
@@ -657,6 +661,7 @@ private:
static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
static void initializeDragEvent(DragEvent* event, const InputMessage* msg);
+ static void initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
deleted file mode 100644
index cea57ec10d..0000000000
--- a/include/input/InputWindow.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_WINDOW_H
-#define _UI_INPUT_WINDOW_H
-
-#include <android/os/TouchOcclusionMode.h>
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <input/Flags.h>
-#include <input/Input.h>
-#include <input/InputTransport.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/Transform.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-#include "InputApplication.h"
-
-using android::os::TouchOcclusionMode;
-
-namespace android {
-
-/*
- * Describes the properties of a window that can receive input.
- */
-struct InputWindowInfo : public Parcelable {
- InputWindowInfo() = default;
-
- // Window flags from WindowManager.LayoutParams
- enum class Flag : uint32_t {
- ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
- DIM_BEHIND = 0x00000002,
- BLUR_BEHIND = 0x00000004,
- NOT_FOCUSABLE = 0x00000008,
- NOT_TOUCHABLE = 0x00000010,
- NOT_TOUCH_MODAL = 0x00000020,
- TOUCHABLE_WHEN_WAKING = 0x00000040,
- KEEP_SCREEN_ON = 0x00000080,
- LAYOUT_IN_SCREEN = 0x00000100,
- LAYOUT_NO_LIMITS = 0x00000200,
- FULLSCREEN = 0x00000400,
- FORCE_NOT_FULLSCREEN = 0x00000800,
- DITHER = 0x00001000,
- SECURE = 0x00002000,
- SCALED = 0x00004000,
- IGNORE_CHEEK_PRESSES = 0x00008000,
- LAYOUT_INSET_DECOR = 0x00010000,
- ALT_FOCUSABLE_IM = 0x00020000,
- WATCH_OUTSIDE_TOUCH = 0x00040000,
- SHOW_WHEN_LOCKED = 0x00080000,
- SHOW_WALLPAPER = 0x00100000,
- TURN_SCREEN_ON = 0x00200000,
- DISMISS_KEYGUARD = 0x00400000,
- SPLIT_TOUCH = 0x00800000,
- HARDWARE_ACCELERATED = 0x01000000,
- LAYOUT_IN_OVERSCAN = 0x02000000,
- TRANSLUCENT_STATUS = 0x04000000,
- TRANSLUCENT_NAVIGATION = 0x08000000,
- LOCAL_FOCUS_MODE = 0x10000000,
- SLIPPERY = 0x20000000,
- LAYOUT_ATTACHED_IN_DECOR = 0x40000000,
- DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000,
- }; // Window types from WindowManager.LayoutParams
-
- enum class Type : int32_t {
- UNKNOWN = 0,
- FIRST_APPLICATION_WINDOW = 1,
- BASE_APPLICATION = 1,
- APPLICATION = 2,
- APPLICATION_STARTING = 3,
- LAST_APPLICATION_WINDOW = 99,
- FIRST_SUB_WINDOW = 1000,
- APPLICATION_PANEL = FIRST_SUB_WINDOW,
- APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1,
- APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2,
- APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3,
- APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4,
- LAST_SUB_WINDOW = 1999,
- FIRST_SYSTEM_WINDOW = 2000,
- STATUS_BAR = FIRST_SYSTEM_WINDOW,
- SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1,
- PHONE = FIRST_SYSTEM_WINDOW + 2,
- SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3,
- KEYGUARD = FIRST_SYSTEM_WINDOW + 4,
- TOAST = FIRST_SYSTEM_WINDOW + 5,
- SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6,
- PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7,
- SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8,
- KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9,
- SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10,
- INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11,
- INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12,
- WALLPAPER = FIRST_SYSTEM_WINDOW + 13,
- STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14,
- SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15,
- DRAG = FIRST_SYSTEM_WINDOW + 16,
- STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17,
- POINTER = FIRST_SYSTEM_WINDOW + 18,
- NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19,
- VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20,
- BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21,
- INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22,
- NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24,
- MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
- ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
- DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
- ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39,
- NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
- LAST_SYSTEM_WINDOW = 2999,
- };
-
- enum class Feature {
- DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
- NO_INPUT_CHANNEL = 0x00000002,
- DISABLE_USER_ACTIVITY = 0x00000004,
- DROP_INPUT = 0x00000008,
- };
-
- /* These values are filled in by the WM and passed through SurfaceFlinger
- * unless specified otherwise.
- */
- // This value should NOT be used to uniquely identify the window. There may be different
- // input windows that have the same token.
- sp<IBinder> token;
- // This uniquely identifies the input window.
- int32_t id = -1;
- std::string name;
- Flags<Flag> flags;
- Type type = Type::UNKNOWN;
- std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
-
- /* These values are filled in by SurfaceFlinger. */
- int32_t frameLeft = -1;
- int32_t frameTop = -1;
- int32_t frameRight = -1;
- int32_t frameBottom = -1;
-
- /*
- * SurfaceFlinger consumes this value to shrink the computed frame. This is
- * different from shrinking the touchable region in that it DOES shift the coordinate
- * space where-as the touchable region does not and is more like "cropping". This
- * is used for window shadows.
- */
- int32_t surfaceInset = 0;
-
- // A global scaling factor for all windows. Unlike windowScaleX/Y this results
- // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis.
- float globalScaleFactor = 1.0f;
-
- // The opacity of this window, from 0.0 to 1.0 (inclusive).
- // An alpha of 1.0 means fully opaque and 0.0 means fully transparent.
- float alpha;
-
- // Transform applied to individual windows.
- ui::Transform transform;
-
- // Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
- int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
- int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
-
- /*
- * This is filled in by the WM relative to the frame and then translated
- * to absolute coordinates by SurfaceFlinger once the frame is computed.
- */
- Region touchableRegion;
- bool visible = false;
- bool focusable = false;
- bool hasWallpaper = false;
- bool paused = false;
- /* This flag is set when the window is of a trusted type that is allowed to silently
- * overlay other windows for the purpose of implementing the secure views feature.
- * Trusted overlays, such as IME windows, can partly obscure other windows without causing
- * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
- */
- bool trustedOverlay = false;
- TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED;
- int32_t ownerPid = -1;
- int32_t ownerUid = -1;
- std::string packageName;
- Flags<Feature> inputFeatures;
- int32_t displayId = ADISPLAY_ID_NONE;
- int32_t portalToDisplayId = ADISPLAY_ID_NONE;
- InputApplicationInfo applicationInfo;
- bool replaceTouchableRegionWithCrop = false;
- wp<IBinder> touchableRegionCropHandle;
-
- void addTouchableRegion(const Rect& region);
-
- bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
-
- bool frameContainsPoint(int32_t x, int32_t y) const;
-
- bool supportsSplitTouch() const;
-
- bool overlaps(const InputWindowInfo* other) const;
-
- bool operator==(const InputWindowInfo& inputChannel) const;
-
- status_t writeToParcel(android::Parcel* parcel) const override;
-
- status_t readFromParcel(const android::Parcel* parcel) override;
-};
-
-/*
- * Handle for a window that can receive input.
- *
- * Used by the native input dispatcher to indirectly refer to the window manager objects
- * that describe a window.
- */
-class InputWindowHandle : public RefBase {
-public:
- explicit InputWindowHandle();
- InputWindowHandle(const InputWindowHandle& other);
- InputWindowHandle(const InputWindowInfo& other);
-
- inline const InputWindowInfo* getInfo() const { return &mInfo; }
-
- sp<IBinder> getToken() const;
-
- int32_t getId() const { return mInfo.id; }
-
- sp<IBinder> getApplicationToken() { return mInfo.applicationInfo.token; }
-
- inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; }
-
- inline std::chrono::nanoseconds getDispatchingTimeout(
- std::chrono::nanoseconds defaultValue) const {
- return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue;
- }
-
- /**
- * Requests that the state of this object be updated to reflect
- * the most current available information about the application.
- * As this class is created as RefBase object, no pure virtual function is allowed.
- *
- * This method should only be called from within the input dispatcher's
- * critical section.
- *
- * Returns true on success, or false if the handle is no longer valid.
- */
- virtual bool updateInfo() { return false; }
-
- /**
- * Updates from another input window handle.
- */
- void updateFrom(const sp<InputWindowHandle> handle);
-
- /**
- * Releases the channel used by the associated information when it is
- * no longer needed.
- */
- void releaseChannel();
-
- // Not override since this class is not derrived from Parcelable.
- status_t readFromParcel(const android::Parcel* parcel);
- status_t writeToParcel(android::Parcel* parcel) const;
-
-protected:
- virtual ~InputWindowHandle();
-
- InputWindowInfo mInfo;
-};
-} // namespace android
-
-#endif // _UI_INPUT_WINDOW_H
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 451ca3c6cd..f6f8939b7a 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -84,7 +84,7 @@ public:
const std::string getLoadFileName() const;
- /* Combines this key character map with an overlay. */
+ /* Combines this key character map with the provided overlay. */
void combine(const KeyCharacterMap& overlay);
/* Gets the keyboard type. */
@@ -144,6 +144,8 @@ public:
bool operator==(const KeyCharacterMap& other) const;
+ bool operator!=(const KeyCharacterMap& other) const;
+
KeyCharacterMap(const KeyCharacterMap& other);
virtual ~KeyCharacterMap();
@@ -230,11 +232,12 @@ private:
KeyedVector<int32_t, Key*> mKeys;
KeyboardType mType;
std::string mLoadFileName;
+ bool mLayoutOverlayApplied;
KeyedVector<int32_t, int32_t> mKeysByScanCode;
KeyedVector<int32_t, int32_t> mKeysByUsageCode;
- KeyCharacterMap();
+ KeyCharacterMap(const std::string& filename);
bool getKey(int32_t keyCode, const Key** outKey) const;
bool getKeyBehavior(int32_t keyCode, int32_t metaState,
@@ -243,8 +246,6 @@ private:
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
- static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format);
-
static void addKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
static void addMetaKeys(Vector<KeyEvent>& outEvents,
@@ -264,6 +265,15 @@ private:
int32_t deviceId, int32_t metaState, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState);
+
+ /* Clears all data stored in this key character map */
+ void clear();
+
+ /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */
+ status_t load(Tokenizer* tokenizer, Format format);
+
+ /* Reloads the data from mLoadFileName and unapplies any overlay. */
+ status_t reloadBaseFromFile();
};
} // namespace android
diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h
deleted file mode 100644
index 6562348701..0000000000
--- a/include/input/NamedEnum.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/stringprintf.h>
-
-#include <array>
-#include <cstdint>
-#include <optional>
-#include <string>
-
-#ifndef __UI_INPUT_NAMEDENUM_H
-#define __UI_INPUT_NAMEDENUM_H
-
-namespace android {
-
-namespace details {
-template <typename E, E V>
-constexpr std::optional<std::string_view> enum_value_name() {
- // Should look something like (but all on one line):
- // std::optional<std::string_view>
- // android::details::enum_value_name()
- // [E = android::test::TestEnums, V = android::test::TestEnums::ONE]
- std::string_view view = __PRETTY_FUNCTION__;
- size_t templateStart = view.rfind("[");
- size_t templateEnd = view.rfind("]");
- if (templateStart == std::string::npos || templateEnd == std::string::npos) {
- return std::nullopt;
- }
-
- // Extract the template parameters without the enclosing braces.
- // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE
- view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
- size_t valStart = view.rfind("V = ");
- if (valStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Example (cont'd): V = android::test::TestEnums::ONE
- view = view.substr(valStart);
- size_t nameStart = view.rfind("::");
- if (nameStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Chop off the initial "::"
- nameStart += 2;
- return view.substr(nameStart);
-}
-
-template <typename E, typename T, T... I>
-constexpr auto generate_enum_values(std::integer_sequence<T, I...> seq) {
- constexpr size_t count = seq.size();
-
- std::array<E, count> values{};
- for (size_t i = 0, v = 0; v < count; ++i) {
- values[v++] = static_cast<E>(T{0} + i);
- }
-
- return values;
-}
-
-template <typename E, std::size_t N>
-inline constexpr auto enum_values =
- generate_enum_values<E>(std::make_integer_sequence<std::underlying_type_t<E>, N>{});
-
-template <typename E, std::size_t N, std::size_t... I>
-constexpr auto generate_enum_names(std::index_sequence<I...>) noexcept {
- return std::array<std::optional<std::string_view>, sizeof...(I)>{
- {enum_value_name<E, enum_values<E, N>[I]>()...}};
-}
-
-template <typename E, std::size_t N>
-inline constexpr auto enum_names = generate_enum_names<E, N>(std::make_index_sequence<N>{});
-
-} // namespace details
-
-class NamedEnum {
-public:
- // By default allowed enum value range is 0 ~ 7.
- template <typename E>
- static constexpr size_t max = 8;
-
- template <auto V>
- static constexpr auto enum_name() {
- using E = decltype(V);
- return details::enum_value_name<E, V>();
- }
-
- template <typename E>
- static constexpr std::optional<std::string_view> enum_name(E val) {
- auto idx = static_cast<size_t>(val);
- return idx < max<E> ? details::enum_names<E, max<E>>[idx] : std::nullopt;
- }
-
- // Helper function for parsing enum value to string.
- // Example : enum class TestEnums { ZERO = 0x0 };
- // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO".
- // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16,
- // it should be declared to specialized the maximum enum by below:
- // template <> constexpr size_t NamedEnum::max<TestEnums> = 16;
- // If the enum class definition is sparse and contains enum values starting from a large value,
- // Do not specialize it to a large number to avoid performance issues.
- // The recommended maximum enum number to specialize is 64.
- template <typename E>
- static const std::string string(E val, const char* fallbackFormat = "%02d") {
- std::string result;
- std::optional<std::string_view> enumString = enum_name(val);
- result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val);
- return result;
- }
-};
-
-} // namespace android
-
-#endif // __UI_INPUT_NAMEDENUM_H \ No newline at end of file
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
new file mode 100644
index 0000000000..0a75278494
--- /dev/null
+++ b/include/input/PrintTools.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <map>
+#include <set>
+#include <string>
+
+namespace android {
+
+template <typename T>
+std::string constToString(const T& v) {
+ return std::to_string(v);
+}
+
+/**
+ * Convert a set of integral types to string.
+ */
+template <typename T>
+std::string dumpSet(const std::set<T>& v, std::string (*toString)(const T&) = constToString) {
+ std::string out;
+ for (const T& entry : v) {
+ out += out.empty() ? "{" : ", ";
+ out += toString(entry);
+ }
+ return out.empty() ? "{}" : (out + "}");
+}
+
+/**
+ * Convert a map to string. Both keys and values of the map should be integral type.
+ */
+template <typename K, typename V>
+std::string dumpMap(const std::map<K, V>& map, std::string (*keyToString)(const K&) = constToString,
+ std::string (*valueToString)(const V&) = constToString) {
+ std::string out;
+ for (const auto& [k, v] : map) {
+ if (!out.empty()) {
+ out += "\n";
+ }
+ out += keyToString(k) + ":" + valueToString(v);
+ }
+ return out;
+}
+
+const char* toString(bool value);
+
+/**
+ * Add "prefix" to the beginning of each line in the provided string
+ * "str".
+ * The string 'str' is typically multi-line.
+ * The most common use case for this function is to add some padding
+ * when dumping state.
+ */
+std::string addLinePrefix(std::string str, const std::string& prefix);
+
+} // namespace android \ No newline at end of file
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 2c6eacbfaa..dfb0ff59a0 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -201,10 +201,8 @@ private:
std::array<std::atomic<HalSupport>,
static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1>
mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN};
- // Android framework only sends mode upto DISPLAY_INACTIVE.
- // Need to increase the array if more mode supported.
std::array<std::atomic<HalSupport>,
- static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1>
+ static_cast<int32_t>(*(android::enum_range<hardware::power::Mode>().end() - 1)) + 1>
mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN};
};
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index 5832bf49bd..f27f5f150f 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -17,124 +17,8 @@
#ifndef ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H
#define ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H
-#include <stdint.h>
-
__BEGIN_DECLS
-struct APerformanceHintManager;
-struct APerformanceHintSession;
-
-/**
- * An opaque type representing a handle to a performance hint manager.
- * It must be released after use.
- *
- * <p>To use:<ul>
- * <li>Obtain the performance hint manager instance by calling
- * {@link APerformanceHint_getManager} function.</li>
- * <li>Create an {@link APerformanceHintSession} with
- * {@link APerformanceHint_createSession}.</li>
- * <li>Get the preferred update rate in nanoseconds with
- * {@link APerformanceHint_getPreferredUpdateRateNanos}.</li>
- */
-typedef struct APerformanceHintManager APerformanceHintManager;
-
-/**
- * An opaque type representing a handle to a performance hint session.
- * A session can only be acquired from a {@link APerformanceHintManager}
- * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be
- * freed with {@link APerformanceHint_closeSession} after use.
- *
- * A Session represents a group of threads with an inter-related workload such that hints for
- * their performance should be considered as a unit. The threads in a given session should be
- * long-life and not created or destroyed dynamically.
- *
- * <p>Each session is expected to have a periodic workload with a target duration for each
- * cycle. The cycle duration is likely greater than the target work duration to allow other
- * parts of the pipeline to run within the available budget. For example, a renderer thread may
- * work at 60hz in order to produce frames at the display's frame but have a target work
- * duration of only 6ms.</p>
- *
- * <p>After each cycle of work, the client is expected to use
- * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to
- * complete.</p>
- *
- * <p>To use:<ul>
- * <li>Update a sessions target duration for each cycle of work
- * with {@link APerformanceHint_updateTargetWorkDuration}.</li>
- * <li>Report the actual duration for the last cycle of work with
- * {@link APerformanceHint_reportActualWorkDuration}.</li>
- * <li>Release the session instance with
- * {@link APerformanceHint_closeSession}.</li></ul></p>
- */
-typedef struct APerformanceHintSession APerformanceHintSession;
-
-/**
- * Acquire an instance of the performance hint manager.
- *
- * @return manager instance on success, nullptr on failure.
- */
-APerformanceHintManager* APerformanceHint_getManager();
-
-/**
- * Creates a session for the given set of threads and sets their initial target work
- * duration.
- * @param manager The performance hint manager instance.
- * @param threadIds The list of threads to be associated with this session. They must be part of
- * this app's thread group.
- * @param size the size of threadIds.
- * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session.
- * This must be positive.
- * @return manager instance on success, nullptr on failure.
- */
-APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
- const int32_t* threadIds, size_t size,
- int64_t initialTargetWorkDurationNanos);
-
-/**
- * Get preferred update rate information for this device.
- *
- * @param manager The performance hint manager instance.
- * @return the preferred update rate supported by device software.
- */
-int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager);
-
-/**
- * Updates this session's target duration for each cycle of work.
- *
- * @param session The performance hint session instance to update.
- * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive.
- * @return 0 on success
- * EINVAL if targetDurationNanos is not positive.
- * EPIPE if communication with the system service has failed.
- */
-int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
- int64_t targetDurationNanos);
-
-/**
- * Reports the actual duration for the last cycle of work.
- *
- * <p>The system will attempt to adjust the core placement of the threads within the thread
- * group and/or the frequency of the core on which they are run to bring the actual duration
- * close to the target duration.</p>
- *
- * @param session The performance hint session instance to update.
- * @param actualDurationNanos how long the thread group took to complete its last task in
- * nanoseconds. This must be positive.
- * @return 0 on success
- * EINVAL if actualDurationNanos is not positive.
- * EPIPE if communication with the system service has failed.
- */
-int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
- int64_t actualDurationNanos);
-
-/**
- * Release the performance hint manager pointer acquired via
- * {@link APerformanceHint_createSession}.
- *
- * @param session The performance hint session instance to release.
- */
-void APerformanceHint_closeSession(APerformanceHintSession* session);
-
/**
* For testing only.
*/
diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h
index 37a476e679..7e6c51587d 100644
--- a/include/private/surface_control_private.h
+++ b/include/private/surface_control_private.h
@@ -29,8 +29,8 @@ typedef struct ASurfaceControlStats ASurfaceControlStats;
/**
* Callback to be notified when surface stats for a specific surface control are available.
*/
-typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
- ASurfaceControl* control, ASurfaceControlStats* stats);
+typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, int32_t id,
+ ASurfaceControlStats* stats);
/**
* Registers a callback to be invoked when surface stats from a specific surface are available.
@@ -42,7 +42,7 @@ typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
*
* \param func The callback to be invoked when surface stats are available.
*/
-void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context,
+void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, int32_t id, void* context,
ASurfaceControl_SurfaceStatsListener func);
/**