commit 304defa642f4f952c184156e956d1502857f65e6
Author: IllusionMan1212 Two bits are used to encode alpha. Use {@link AndroidBitmapFlagsAlpha.MASK}
+ * and {@link AndroidBitmapFlagsAlpha.SHIFT} to retrieve them. One bit is used to encode whether the Bitmap uses the HARDWARE Config. Use
+ * {@link AndroidBitmapFlags.IS_HARDWARE} to know. These flags were introduced in API level 30.
+ *
+ *
+ * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc.
+ *
+ * The font file returned is guaranteed to be opend with O_RDONLY.
+ * Note that the returned pointer is valid until AFont_close() is called for the given font.
+ *
+ * Available since API level 29.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return a string of the font file path.
+ */
+ AFont_getFontFilePath :: proc(font: ^AFont) -> cstring ---
+
+ /**
+ * Return a weight value associated with the current font.
+ *
+ * The weight values are positive and less than or equal to 1000.
+ * Here are pairs of the common names and their values.
+ *
+ *
+ *
+ *
+ * Value
+ * Name
+ * NDK Definition
+ *
+ *
+ * 100
+ * Thin
+ * {@link AFONT_WEIGHT_THIN}
+ *
+ *
+ * 200
+ * Extra Light (Ultra Light)
+ * {@link AFONT_WEIGHT_EXTRA_LIGHT}
+ *
+ *
+ * 300
+ * Light
+ * {@link AFONT_WEIGHT_LIGHT}
+ *
+ *
+ * 400
+ * Normal (Regular)
+ * {@link AFONT_WEIGHT_NORMAL}
+ *
+ *
+ * 500
+ * Medium
+ * {@link AFONT_WEIGHT_MEDIUM}
+ *
+ *
+ * 600
+ * Semi Bold (Demi Bold)
+ * {@link AFONT_WEIGHT_SEMI_BOLD}
+ *
+ *
+ * 700
+ * Bold
+ * {@link AFONT_WEIGHT_BOLD}
+ *
+ *
+ * 800
+ * Extra Bold (Ultra Bold)
+ * {@link AFONT_WEIGHT_EXTRA_BOLD}
+ *
+ *
+ * 900
+ * Black (Heavy)
+ * {@link AFONT_WEIGHT_BLACK}
+ *
+ * AHardwareBuffer* buffer
+ * AHardwareBuffer_allocate(..., &buffer) // `buffer` has reference count 1
+ * jobject java_result = AHardwareBuffer_toHardwareBuffer(buffer) // `buffer` has reference count 2.
+ * AHardwareBuffer_release(buffer) // `buffer` has reference count 1
+ * return result // The underlying buffer is kept alive by `java_result` and
+ * // will be set to 0 when it is closed on the Java side with
+ * // HardwareBuffer::close().
+ *
+ *
+ * Available since API level 26.
+ */
+ AHardwareBuffer_toHardwareBuffer :: proc(env: ^JNIEnv, hardwareBuffer: ^AHardwareBuffer) -> jobject ---
+}
diff --git a/hdr_metadata.odin b/hdr_metadata.odin
new file mode 100644
index 0000000..6f18f27
--- /dev/null
+++ b/hdr_metadata.odin
@@ -0,0 +1,45 @@
+//+build android
+package android
+
+/**
+ * These structures are used to define the display's capabilities for HDR content.
+ * They can be used to better tone map content to user's display.
+ */
+
+/**
+ * HDR metadata standards that are supported by Android.
+ */
+AHdrMetadataType :: enum u32 {
+ HDR10_SMPTE2086 = 1,
+ HDR10_CTA861_3 = 2,
+ HDR10PLUS_SEI = 3,
+}
+
+/**
+ * Color is defined in CIE XYZ coordinates.
+ */
+AColor_xy :: struct {
+ x: f32,
+ y: f32,
+}
+
+/**
+ * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
+ */
+AHdrMetadata_smpte2086 :: struct {
+ displayPrimaryRed: AColor_xy,
+ displayPrimaryGreen: AColor_xy,
+ displayPrimaryBlue: AColor_xy,
+ whitePoint: AColor_xy,
+ maxLuminance: f32,
+ minLuminance: f32,
+}
+
+/**
+ * CTA 861.3 "HDR Static Metadata Extension" static metadata
+ */
+AHdrMetadata_cta861_3 :: struct {
+ maxContentLightLevel: f32,
+ maxFrameAverageLightLevel: f32,
+}
+
diff --git a/imagedecoder.odin b/imagedecoder.odin
new file mode 100644
index 0000000..7c8bca4
--- /dev/null
+++ b/imagedecoder.odin
@@ -0,0 +1,992 @@
+//+build android
+package android
+
+foreign import android "system:android"
+
+/**
+ * @defgroup ImageDecoder Android Image Decoder
+ *
+ * Functions for converting encoded images into RGBA pixels.
+ *
+ * Similar to the Java counterpart android.graphics.ImageDecoder, it can be used
+ * to decode images in the following formats:
+ * - JPEG
+ * - PNG
+ * - GIF
+ * - WebP
+ * - BMP
+ * - ICO
+ * - WBMP
+ * - HEIF
+ * - Digital negatives (via the DNG SDK)
+ * It has similar options for scaling, cropping, and choosing the output format.
+ * Unlike the Java API, which can create an android.graphics.Bitmap or
+ * android.graphics.drawable.Drawable object, AImageDecoder decodes directly
+ * into memory provided by the client. For more information, see the
+ * Image decoder
+ * developer guide.
+ * @{
+ */
+
+/**
+ * {@link AImageDecoder} functions result code.
+ *
+ * Introduced in API 30.
+ *
+ * Many functions will return this to indicate success
+ * ({@link ANDROID_IMAGE_DECODER_SUCCESS}) or the reason for the failure. On
+ * failure, any out-parameters should be considered uninitialized, except where
+ * specified. Use {@link AImageDecoder_resultToString} for a readable
+ * version of the result code.
+ */
+AImageDecoderResult :: enum i32 {
+ /**
+ * Decoding was successful and complete.
+ */
+ SUCCESS = 0,
+ /**
+ * The input is incomplete.
+ */
+ INCOMPLETE = -1,
+ /**
+ * The input contained an error after decoding some lines.
+ */
+ ERROR = -2,
+ /**
+ * Could not convert. For example, attempting to decode an image with
+ * alpha to an opaque format.
+ */
+ INVALID_CONVERSION = -3,
+ /**
+ * The scale is invalid. It may have overflowed, or it may be incompatible
+ * with the current alpha setting.
+ */
+ INVALID_SCALE = -4,
+ /**
+ * Some other parameter is invalid.
+ */
+ BAD_PARAMETER = -5,
+ /**
+ * Input was invalid before decoding any pixels.
+ */
+ INVALID_INPUT = -6,
+ /**
+ * A seek was required and it failed.
+ */
+ SEEK_ERROR = -7,
+ /**
+ * Some other error. For example, an internal allocation failed.
+ */
+ INTERNAL_ERROR = -8,
+ /**
+ * AImageDecoder did not recognize the format.
+ */
+ UNSUPPORTED_FORMAT = -9,
+ /**
+ * The animation has reached the end.
+ */
+ FINISHED = -10,
+ /**
+ * This method cannot be called while the AImageDecoder is in its current
+ * state. For example, various setters (like {@link AImageDecoder_setTargetSize})
+ * can only be called while the AImageDecoder is set to decode the first
+ * frame of an animation. This ensures that any blending and/or restoring
+ * prior frames works correctly.
+ */
+ INVALID_STATE = -11,
+}
+
+AImageDecoderRepeatCount :: enum i32 {
+ /**
+ * Reported by {@link AImageDecoder_getRepeatCount} if the
+ * animation should repeat forever.
+ *
+ * Introduced in API 31
+ */
+ INFINITE = max(i32),
+}
+
+/**
+* How a frame is “disposed” before showing the next one.
+*
+* Introduced in API 31.
+*
+* This, along with other information in AImageDecoderFrameInfo,
+* can be useful for determining whether a frame is independent, but
+* the decoder handles disposing of frames, so a simple
+* sequential client does not need this.
+*/
+AImageDecoderFrameDisposalOp :: enum i32 {
+ /// No disposal. The following frame will be drawn directly
+ /// on top of this one.
+ NONE = 1,
+ /// The frame’s rectangle is cleared to transparent (by AImageDecoder)
+ /// before decoding the next frame.
+ BACKGROUND = 2,
+ /// The frame’s rectangle is reverted to the prior frame before decoding
+ /// the next frame. This is handled by AImageDecoder, unless
+ /// {@link AImageDecoder_setInternallyHandleDisposePrevious} is set to false.
+ PREVIOUS = 3,
+}
+
+/**
+* How a frame is blended with the previous frame.
+*
+* Introduced in API 31.
+*
+* This, along with other information in AImageDecoderFrameInfo,
+* can be useful for determining whether a frame is independent, but
+* the decoder handles blending frames, so a simple
+* sequential client does not need this.
+*/
+AImageDecoderBlendOp :: enum i32 {
+ /// This frame replaces existing content. This corresponds
+ /// to webp’s “do not blend”.
+ SRC = 1,
+ /// This frame blends with the previous frame.
+ SRC_OVER = 2,
+}
+
+ResultOrRepeatCount :: union {
+ AImageDecoderResult,
+ AImageDecoderRepeatCount,
+ i32,
+}
+
+ResultOrFrameDuration :: union {
+ AImageDecoderResult,
+ i64,
+}
+
+ResultOrFrameDisposalOp :: union {
+ AImageDecoderResult,
+ AImageDecoderFrameDisposalOp,
+}
+
+ResultOrBlendOp :: union {
+ AImageDecoderResult,
+ AImageDecoderBlendOp,
+}
+
+/**
+ * Opaque handle for decoding images.
+ *
+ * Introduced in API 30
+ *
+ * Create using one of the following:
+ * - {@link AImageDecoder_createFromAAsset}
+ * - {@link AImageDecoder_createFromFd}
+ * - {@link AImageDecoder_createFromBuffer}
+ *
+ * After creation, {@link AImageDecoder_getHeaderInfo} can be used to retrieve
+ * information about the encoded image. Other functions, like
+ * {@link AImageDecoder_setTargetSize}, can be used to specify how to decode, and
+ * {@link AImageDecoder_decodeImage} will decode into client provided memory.
+ *
+ * {@link AImageDecoder} objects are NOT thread-safe, and should not be shared across
+ * threads.
+ */
+AImageDecoder :: struct{}
+
+/**
+* Opaque handle for representing information about the encoded image.
+*
+* Introduced in API 30
+*
+* Retrieved using {@link AImageDecoder_getHeaderInfo} and passed to methods
+* like {@link AImageDecoderHeaderInfo_getWidth} and
+* {@link AImageDecoderHeaderInfo_getHeight}.
+*/
+AImageDecoderHeaderInfo :: struct{}
+
+/**
+* Opaque handle to animation information about a single frame.
+*
+* Introduced in API 31
+*
+* The duration (retrieved with {@link AImageDecoderFrameInfo_getDuration}) is
+* necessary for clients to display the animation at the proper speed. The other
+* information is helpful for a client that wants to determine what frames are
+* independent (or what frames they depend on), but is unnecessary for
+* a simple client that wants to sequentially display all frames.
+*/
+AImageDecoderFrameInfo :: struct{}
+
+foreign android {
+ /**
+ * Return a constant string value representing the error code.
+ *
+ * Introduced in API 31.
+ *
+ * Pass the return value from an {@link AImageDecoder} method (e.g.
+ * {@link AImageDecoder_decodeImage}) for a text string representing the error
+ * code.
+ *
+ * Errors:
+ * - Returns null for a value out of range.
+ */
+ AImageDecoder_resultToString :: proc(result: AImageDecoderResult) -> cstring ---
+
+ /**
+ * Create a new {@link AImageDecoder} from an {@link AAsset}.
+ *
+ * Available since API level 30.
+ *
+ * @param asset {@link AAsset} containing encoded image data. Client is still
+ * responsible for calling {@link AAsset_close} on it, which may be
+ * done after deleting the returned {@link AImageDecoder}.
+ * @param outDecoder On success (i.e. return value is
+ * {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ * a newly created {@link AImageDecoder}. Caller is
+ * responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The asset was truncated before
+ * reading the image header.
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: One of the parameters is
+ * null.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_INPUT}: There is an error in the
+ * header.
+ * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The asset failed to seek.
+ * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
+ * failure to allocate memory.
+ * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
+ * supported.
+ */
+ AImageDecoder_createFromAAsset :: proc(asset: ^AAsset, outDecoder: ^^AImageDecoder) -> AImageDecoderResult ---
+
+ /**
+ * Create a new {@link AImageDecoder} from a file descriptor.
+ *
+ * Available since API level 30.
+ *
+ * @param fd Seekable, readable, open file descriptor for encoded data.
+ * Client is still responsible for closing it, which may be done
+ * after deleting the returned {@link AImageDecoder}.
+ * @param outDecoder On success (i.e. return value is
+ * {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ * a newly created {@link AImageDecoder}. Caller is
+ * responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The file was truncated before
+ * reading the image header.
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The {@link AImageDecoder} is
+ * null, or |fd| does not represent a valid, seekable file descriptor.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_INPUT}: There is an error in the
+ * header.
+ * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The descriptor failed to seek.
+ * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
+ * failure to allocate memory.
+ * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
+ * supported.
+ */
+ AImageDecoder_createFromFd :: proc(fd: i32, outDecoder: ^^AImageDecoder) -> AImageDecoderResult ---
+
+ /**
+ * Create a new AImageDecoder from a buffer.
+ *
+ * Available since API level 30.
+ *
+ * @param buffer Pointer to encoded data. Must be valid for the entire time
+ * the {@link AImageDecoder} is used.
+ * @param length Byte length of buffer.
+ * @param outDecoder On success (i.e. return value is
+ * {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ * a newly created {@link AImageDecoder}. Caller is
+ * responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The encoded image was truncated before
+ * reading the image header.
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: One of the parameters is
+ * invalid.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_INPUT}: There is an error in the
+ * header.
+ * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
+ * failure to allocate memory.
+ * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
+ * supported.
+ */
+ AImageDecoder_createFromBuffer :: proc(buffer: rawptr, length: uint, outDecoder: ^^AImageDecoder) -> AImageDecoderResult ---
+
+ /**
+ * Delete the AImageDecoder.
+ * @param decoder {@link AImageDecoder} object created with one of AImageDecoder_createFrom...
+ * functions.
+ * Available since API level 30.
+ */
+ AImageDecoder_delete :: proc(decoder: ^AImageDecoder) ---
+
+ /**
+ * Choose the desired output format.
+ *
+ * If the encoded image represents an animation, this must be called while on
+ * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
+ * after calling {@link AImageDecoder_rewind}).
+ *
+ * Available since API level 30.
+ *
+ * @param format {@link AndroidBitmapFormat} to use for the output.
+ * @param decoder an {@link AImageDecoder} object.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure. On failure, the
+ * {@link AImageDecoder} uses the format it was already planning
+ * to use (either its default or a previously successful setting
+ * from this function).
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
+ * {@link AImageDecoder} is null or |format| does not correspond to an
+ * {@link AndroidBitmapFormat}.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: The
+ * {@link AndroidBitmapFormat} is incompatible with the image.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
+ * the first frame.
+ */
+ AImageDecoder_setAndroidBitmapFormat :: proc(decoder: ^AImageDecoder, format: AndroidBitmapFormat) -> AImageDecoderResult ---
+
+ /**
+ * Specify whether the output's pixels should be unpremultiplied.
+ *
+ * By default, {@link AImageDecoder_decodeImage} will premultiply the pixels, if they have alpha.
+ * Pass true to this method to leave them unpremultiplied. This has no effect on an
+ * opaque image.
+ *
+ * If the encoded image represents an animation, this must be called while on
+ * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
+ * after calling {@link AImageDecoder_rewind}).
+ *
+ * Available since API level 30.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: Unpremultiplied is not
+ * possible due to an existing scale set by
+ * {@link AImageDecoder_setTargetSize}.
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
+ * {@link AImageDecoder} is null.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
+ * the first frame.
+ */
+ AImageDecoder_setUnpremultipliedRequired :: proc(decoder: ^AImageDecoder, unpremultipliedRequired: bool) -> AImageDecoderResult ---
+
+ /**
+ * Choose the dataspace for the output.
+ *
+ * Ignored by {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
+ * an {@link ADataSpace}.
+ *
+ * If the encoded image represents an animation, this must be called while on
+ * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
+ * after calling {@link AImageDecoder_rewind}).
+ *
+ * Available since API level 30.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
+ * specifies how to interpret the colors. By default,
+ * AImageDecoder will decode into the ADataSpace specified by
+ * {@link AImageDecoderHeaderInfo_getDataSpace}. If this
+ * parameter is set to a different ADataSpace, AImageDecoder
+ * will transform the output into the specified ADataSpace.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
+ * {@link AImageDecoder} is null or |dataspace| does not correspond to an
+ * {@link ADataSpace} value.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
+ * the first frame.
+ */
+ AImageDecoder_setDataSpace :: proc(decoder: ^AImageDecoder, dataspace: ADataSpace) -> AImageDecoderResult ---
+
+ /**
+ * Specify the output size for a decoded image.
+ *
+ * Future calls to {@link AImageDecoder_decodeImage} will sample or scale the
+ * encoded image to reach the desired size. If a crop rect is set (via
+ * {@link AImageDecoder_setCrop}), it must be contained within the dimensions
+ * specified by width and height, and the output image will be the size of the
+ * crop rect.
+ *
+ * If the encoded image represents an animation, this must be called while on
+ * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
+ * after calling {@link AImageDecoder_rewind}).
+ *
+ * It is strongly recommended to use setTargetSize only for downscaling, as it
+ * is often more efficient to scale-up when rendering than up-front due to
+ * reduced overall memory.
+ *
+ * Available since API level 30.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @param width Width of the output (prior to cropping).
+ * This will affect future calls to
+ * {@link AImageDecoder_getMinimumStride}, which will now return
+ * a value based on this width.
+ * @param height Height of the output (prior to cropping).
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
+ * {@link AImageDecoder} is null.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_SCALE}: |width| or |height| is <= 0,
+ * the size is too big, any existing crop is not contained by the new image
+ * dimensions, or the scale is incompatible with a previous call to
+ * {@link AImageDecoder_setUnpremultipliedRequired}(true).
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
+ * the first frame.
+ */
+ AImageDecoder_setTargetSize :: proc(decoder: ^AImageDecoder, width: i32, height: i32) -> AImageDecoderResult ---
+
+ /**
+ * Compute the dimensions to use for a given sampleSize.
+ *
+ * Although AImageDecoder can scale to an arbitrary target size (see
+ * {@link AImageDecoder_setTargetSize}), some sizes may be more efficient than
+ * others. This computes the most efficient target size to use to reach a
+ * particular sampleSize.
+ *
+ * Available since API level 30.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @param sampleSize A subsampling rate of the original image. Must be greater
+ * than or equal to 1. A sampleSize of 2 means to skip every
+ * other pixel/line, resulting in a width and height that are
+ * 1/2 of the original dimensions, with 1/4 the number of
+ * pixels.
+ * @param width Out parameter for the width sampled by sampleSize, and rounded
+ * in the direction that the decoder can do most efficiently.
+ * @param height Out parameter for the height sampled by sampleSize, and rounded
+ * in the direction that the decoder can do most efficiently.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
+ * {@link AImageDecoder}, |width| or |height| is null or |sampleSize| is < 1.
+ */
+ AImageDecoder_computeSampledSize :: proc(decoder: ^AImageDecoder, sampleSize: i32, width: ^i32, height: ^i32) -> AImageDecoderResult ---
+
+ /**
+ * Specify how to crop the output after scaling (if any).
+ *
+ * Future calls to {@link AImageDecoder_decodeImage} will crop their output to
+ * the specified {@link ARect}. Clients will only need to allocate enough memory
+ * for the cropped ARect.
+ *
+ * If the encoded image represents an animation, this must be called while on
+ * the first frame (e.g. before calling {@link AImageDecoder_advanceFrame} or
+ * after calling {@link AImageDecoder_rewind}).
+ *
+ * Available since API level 30.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @param crop Rectangle describing a crop of the decode. It must be contained inside of
+ * the (possibly scaled, by {@link AImageDecoder_setTargetSize})
+ * image dimensions. This will affect future calls to
+ * {@link AImageDecoder_getMinimumStride}, which will now return a
+ * value based on the width of the crop. An empty ARect -
+ * specifically { 0, 0, 0, 0 } - may be used to remove the cropping
+ * behavior. Any other empty or unsorted ARects will result in
+ * returning {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
+ * {@link AImageDecoder} is null, or the crop is not contained by the
+ * (possibly scaled) image dimensions.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE}: The animation is not on
+ * the first frame.
+ */
+ AImageDecoder_setCrop :: proc(decoder: ^AImageDecoder, crop: ARect) -> AImageDecoderResult ---
+
+ /**
+ * Return an opaque handle for reading header info.
+ *
+ * This is owned by the {@link AImageDecoder} and will be destroyed when the
+ * AImageDecoder is destroyed via {@link AImageDecoder_delete}.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ *
+ * Available since API level 30.
+ */
+ AImageDecoder_getHeaderInfo :: proc(decoder: ^AImageDecoder) -> ^AImageDecoderHeaderInfo ---
+
+ /**
+ * Report the native width of the encoded image. This is also the logical
+ * pixel width of the output, unless {@link AImageDecoder_setTargetSize} is
+ * used to choose a different size or {@link AImageDecoder_setCrop} is used to
+ * set a crop rect.
+ *
+ * Available since API level 30.
+ */
+ AImageDecoderHeaderInfo_getWidth :: proc(header_info: ^AImageDecoderHeaderInfo) -> i32 ---
+
+ /**
+ * Report the native height of the encoded image. This is also the logical
+ * pixel height of the output, unless {@link AImageDecoder_setTargetSize} is
+ * used to choose a different size or {@link AImageDecoder_setCrop} is used to
+ * set a crop rect.
+ *
+ * Available since API level 30.
+ */
+ AImageDecoderHeaderInfo_getHeight :: proc(header_info: ^AImageDecoderHeaderInfo) -> i32 ---
+
+ /**
+ * Report the mimeType of the encoded image.
+ *
+ * Available since API level 30.
+ *
+ * @return a string literal describing the mime type.
+ */
+ AImageDecoderHeaderInfo_getMimeType :: proc(header_info: ^AImageDecoderHeaderInfo) -> cstring ---
+
+ /**
+ * Report the {@link AndroidBitmapFormat} the AImageDecoder will decode to
+ * by default. {@link AImageDecoder} will try to choose one that is sensible
+ * for the image and the system. Note that this does not indicate the
+ * encoded format of the image.
+ *
+ * Available since API level 30.
+ */
+ AImageDecoderHeaderInfo_getAndroidBitmapFormat :: proc(header_info: ^AImageDecoderHeaderInfo) -> AndroidBitmapFormat ---
+
+ /**
+ * Report how the {@link AImageDecoder} will handle alpha by default. If the image
+ * contains no alpha (according to its header), this will return
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}. If the image may contain alpha,
+ * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}, because
+ * {@link AImageDecoder_decodeImage} will premultiply pixels by default.
+ *
+ * Available since API level 30.
+ *
+ * Starting in API level 31, an AImageDecoder may contain multiple frames of an
+ * animation, but this method still only reports whether the first frame has
+ * alpha.
+ */
+ AImageDecoderHeaderInfo_getAlphaFlags :: proc(header_info: ^AImageDecoderHeaderInfo) -> AndroidBitmapFlagsAlpha ---
+
+ /**
+ * Report the dataspace the AImageDecoder will decode to by default.
+ *
+ * By default, {@link AImageDecoder_decodeImage} will not do any color
+ * conversion.
+ *
+ * Available since API level 30.
+ *
+ * @return The {@link ADataSpace} representing the way the colors
+ * are encoded (or {@link ADATASPACE_UNKNOWN} if there is not a
+ * corresponding ADataSpace). This specifies how to interpret the colors
+ * in the decoded image, unless {@link AImageDecoder_setDataSpace} is
+ * called to decode to a different ADataSpace.
+ *
+ * Note that ADataSpace only exposes a few values. This may return
+ * {@link ADATASPACE_UNKNOWN}, even for Named ColorSpaces, if they have
+ * no corresponding {@link ADataSpace}.
+ */
+ AImageDecoderHeaderInfo_getDataSpace :: proc(header_info: ^AImageDecoderHeaderInfo) -> ADataSpace ---
+
+ /**
+ * Return the minimum stride that can be used in
+ * {@link AImageDecoder_decodeImage}.
+ *
+ * This stride provides no padding, meaning it will be exactly equal to the
+ * width times the number of bytes per pixel for the {@link AndroidBitmapFormat}
+ * being used.
+ *
+ * If the output is scaled (via {@link AImageDecoder_setTargetSize}) and/or
+ * cropped (via {@link AImageDecoder_setCrop}), this takes those into account.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ *
+ * Available since API level 30.
+ */
+ AImageDecoder_getMinimumStride :: proc(decoder: ^AImageDecoder) -> uint ---
+
+ /**
+ * Decode the image into pixels, using the settings of the {@link AImageDecoder}.
+ *
+ * Available since API level 30.
+ *
+ * Starting in API level 31, it can be used to decode all of the frames of an
+ * animated image (i.e. GIF, WebP) using new APIs. Internally,
+ * AImageDecoder keeps track of its "current frame" - that is, the frame that
+ * will be decoded by a call to AImageDecoder_decodeImage. At creation time, the
+ * current frame is always the first frame, and multiple calls to this method
+ * will each decode the first frame. {@link AImageDecoder_advanceFrame} advances
+ * the current frame to the following frame, so that future calls to this method
+ * will decode that frame. Some frames may update only part of the image. They
+ * may only update a sub-rectangle (see {@link
+ * AImageDecoderFrameInfo_getFrameRect}), or they may have alpha (see
+ * {@link AImageDecoderFrameInfo_hasAlphaWithinBounds}). In these cases, this
+ * method assumes that the prior frame is still residing in the |pixels| buffer,
+ * decodes only the new portion, and blends it with the buffer. Frames that change
+ * the entire |pixels| buffer are "independent", and do not require the prior
+ * frame to remain in the buffer. The first frame is always independent. A
+ * sophisticated client can use information from the {@link AImageDecoderFrameInfo}
+ * to determine whether other frames are independent, or what frames they rely on.
+ *
+ * If the current frame is marked {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS},
+ * AImageDecoder_decodeImage will store the |pixels| buffer prior to decoding
+ * (note: this only happens for the first in a string of consecutive
+ * ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS frames). After advancing to the
+ * following frame, AImageDecoder_decodeImage will restore that buffer prior to
+ * decoding that frame. This is the default behavior, but it can be disabled
+ * by passing false to {@link AImageDecoder_setInternallyHandleDisposePrevious}.
+ *
+ * Ignoring timing information, display, etc, a client wishing to decode all
+ * frames of an animated image may conceptually use code like the following:
+ *
+ * while (true) {
+ * int result = AImageDecoder_decodeImage(decoder, pixels, stride, size);
+ * if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
+ *
+ * // Display or save the image in |pixels|, keeping the buffer intact for
+ * // AImageDecoder to decode the next frame correctly.
+ * Application_viewImage(pixels);
+ *
+ * result = AImageDecoder_advanceFrame(decoder);
+ * if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
+ * }
+ *
+ * @param decoder Opaque object representing the decoder.
+ * @param pixels On success, will be filled with the result
+ * of the decode. Must be large enough to hold |size| bytes.
+ * @param stride Width in bytes of a single row. Must be at least
+ * {@link AImageDecoder_getMinimumStride} and a multiple of the
+ * bytes per pixel of the {@link AndroidBitmapFormat}.
+ * @param size Size of the pixel buffer in bytes. Must be at least
+ * stride * (height - 1) +
+ * {@link AImageDecoder_getMinimumStride}.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The image was truncated. A
+ * partial image was decoded, and undecoded lines have been initialized to all
+ * zeroes.
+ * - {@link ANDROID_IMAGE_DECODER_ERROR}: The image contained an error. A
+ * partial image was decoded, and undecoded lines have been initialized to all
+ * zeroes.
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The {@link AImageDecoder} or
+ * |pixels| is null, the stride is not large enough or not pixel aligned, or
+ * |size| is not large enough.
+ * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The asset or file descriptor
+ * failed to seek.
+ * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
+ * failure to allocate memory.
+ * - {@link ANDROID_IMAGE_DECODER_FINISHED}: The input contains no
+ * more frames. No decoding occurred. The client must call
+ * {@link AImageDecoder_rewind} before calling
+ * {@link AImageDecoder_decodeImage} again.
+ */
+ AImageDecoder_decodeImage :: proc(decoder: ^AImageDecoder, pixels: rawptr, stride: uint, size: uint) -> AImageDecoderResult ---
+
+ /**
+ * Return true iff the image is animated - i.e. has multiple frames.
+ *
+ * Introduced in API 31.
+ *
+ * A single frame GIF is considered to *not* be animated. This may require
+ * seeking past the first frame to verify whether there is a following frame.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ *
+ * Errors:
+ * - returns false if |decoder| is null.
+ */
+ AImageDecoder_isAnimated :: proc(decoder: ^AImageDecoder) -> bool ---
+
+
+ /**
+ * Report how many times the animation should repeat.
+ *
+ * Introduced in API 31.
+ *
+ * This does not include the first play through. e.g. a repeat
+ * count of 4 means that each frame is played 5 times.
+ *
+ * {@link ANDROID_IMAGE_DECODER_INFINITE} means to repeat forever.
+ *
+ * This may require seeking.
+ *
+ * For non-animated formats, this returns 0. It may return non-zero for
+ * an image with only one frame (i.e. {@link AImageDecoder_isAnimated} returns
+ * false) if the encoded image contains a repeat count.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @return Number of times to repeat on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
+ * is null.
+ */
+ AImageDecoder_getRepeatCount :: proc(decoder: ^AImageDecoder) -> ResultOrRepeatCount ---
+
+ /**
+ * Advance to the next frame in the animation.
+ *
+ * Introduced in API 31.
+ *
+ * The AImageDecoder keeps track internally which frame it is ready to decode
+ * (the "current frame"). Initially it is set to decode the first frame, and
+ * each call to {@link AImageDecoder_decodeImage} will continue to decode
+ * the same frame until this method (or {@link AImageDecoder_rewind})
+ * is called.
+ *
+ * Note that this can be used to skip a frame without decoding it. But
+ * some frames depend on (i.e. blend with) prior frames, and
+ * AImageDecoder_decodeImage assumes that the prior frame is in the
+ * |pixels| buffer. In addition, AImageDecoder_decodeImage handles caching and
+ * restoring frames (see {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS}), so
+ * skipping frames in an image with such frames may not produce the correct
+ * results.
+ *
+ * Only supported by {@link ANDROID_BITMAP_FORMAT_RGBA_8888} and
+ * {@link ANDROID_BITMAP_FORMAT_RGBA_F16}.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
+ * represents an image that is not animated (see
+ * {@link AImageDecoder_isAnimated}) or the AImageDecoder is null.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE): The requested
+ * {@link AndroidBitmapFormat} does not support animation.
+ * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The input appears
+ * to be truncated. The client must call {@link AImageDecoder_rewind}
+ * before calling {@link AImageDecoder_decodeImage} again.
+ * - {@link ANDROID_IMAGE_DECODER_ERROR}: The input contains an error.
+ * The client must call {@link AImageDecoder_rewind} before
+ * calling {@link AImageDecoder_decodeImage} again.
+ * - {@link ANDROID_IMAGE_DECODER_FINISHED}: The input contains no
+ * more frames. The client must call {@link AImageDecoder_rewind}
+ * before calling {@link AImageDecoder_decodeImage} again.
+ */
+ AImageDecoder_advanceFrame :: proc(decoder: ^AImageDecoder) -> AImageDecoderResult ---
+
+ /**
+ * Return to the beginning of the animation.
+ *
+ * Introduced in API 31.
+ *
+ * After this call, the AImageDecoder will be ready to decode the
+ * first frame of the animation. This can be called after reaching
+ * the end of the animation or an error or in the middle of the
+ * animation.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
+ * represents an image that is not animated (see
+ * {@link AImageDecoder_isAnimated}) or the AImageDecoder is
+ * null.
+ * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The asset or file
+ * descriptor failed to seek.
+ */
+ AImageDecoder_rewind :: proc(decoder: ^AImageDecoder) -> AImageDecoderResult ---
+
+ /**
+ * Create an uninitialized AImageDecoderFrameInfo.
+ *
+ * Introduced in API 31.
+ *
+ * This can be passed to {@link AImageDecoder_getFrameInfo} to fill
+ * in information about the current frame. It may be reused.
+ *
+ * Must be deleted with {@link AImageDecoderFrameInfo_delete}.
+ */
+ AImageDecoderFrameInfo_create :: proc() -> ^AImageDecoderFrameInfo ---
+
+ /**
+ * Delete an AImageDecoderFrameInfo.
+ *
+ * Introduced in API 31.
+ */
+ AImageDecoderFrameInfo_delete :: proc(info: ^AImageDecoderFrameInfo) ---
+
+ /**
+ * Fill |info| with information about the current frame.
+ *
+ * Introduced in API 31.
+ *
+ * Initially, this will return information about the first frame.
+ * {@link AImageDecoder_advanceFrame} and
+ * {@link AImageDecoder_rewind} can be used to change which frame
+ * is the current frame.
+ *
+ * If the image only has one frame, this will fill the {@link
+ * AImageDecoderFrameInfo} with the encoded info and reasonable
+ * defaults.
+ *
+ * If {@link AImageDecoder_advanceFrame} succeeded, this will succeed as well.
+ *
+ * @param decoder Opaque object representing the decoder.
+ * @param info Opaque object to hold frame information. On success, will be
+ * filled with information regarding the current frame.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ * indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: One of the parameters is null.
+ * - {@link ANDROID_IMAGE_DECODER_FINISHED}: The input contains no
+ * more frames. The client must call {@link AImageDecoder_rewind} to reset the
+ * current frame to a valid frame (0).
+ */
+ AImageDecoder_getFrameInfo :: proc(decoder: ^AImageDecoder, info: ^AImageDecoderFrameInfo) -> AImageDecoderResult ---
+
+ /**
+ * Report the number of nanoseconds to show the current frame.
+ *
+ * Introduced in API 31.
+ *
+ * Errors:
+ * - returns {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if |info| is null.
+ */
+ AImageDecoderFrameInfo_getDuration :: proc(info: ^AImageDecoderFrameInfo) -> ResultOrFrameDuration ---
+
+ /**
+ * The rectangle of the image (within 0, 0,
+ * {@link AImageDecoderHeaderInfo_getWidth}, {@link AImageDecoderHeaderInfo_getHeight})
+ * updated by this frame.
+ *
+ * Introduced in API 31.
+ *
+ * Note that this is unaffected by calls to
+ * {@link AImageDecoder_setTargetSize} or
+ * {@link AImageDecoder_setCrop}.
+ *
+ * A frame may update only part of the image. This will always be
+ * contained by the image’s dimensions.
+ *
+ * This, along with other information in AImageDecoderFrameInfo,
+ * can be useful for determining whether a frame is independent, but
+ * the decoder handles blending frames, so a simple
+ * sequential client does not need this.
+ *
+ * Errors:
+ * - returns an empty ARect if |info| is null.
+ */
+ AImageDecoderFrameInfo_getFrameRect :: proc(info: ^AImageDecoderFrameInfo) -> ARect ---
+
+ /**
+ * Whether the new portion of this frame may contain alpha.
+ *
+ * Introduced in API 31.
+ *
+ * Unless this frame is independent (see {@link AImageDecoder_decodeImage}),
+ * a single call to {@link AImageDecoder_decodeImage} will decode an updated
+ * rectangle of pixels and then blend it with the existing pixels in the
+ * |pixels| buffer according to {@link AImageDecoderFrameInfo_getBlendOp}. This
+ * method returns whether the updated rectangle has alpha, prior to blending.
+ * The return value is conservative for example, if a color-index-based frame
+ * has a color with alpha but does not use it, this will still return true.
+ *
+ * This, along with other information in AImageDecoderFrameInfo,
+ * can be useful for determining whether a frame is independent, but
+ * the decoder handles blending frames, so a simple
+ * sequential client does not need this.
+ *
+ * Note that this may differ from whether the composed frame (that is, the
+ * resulting image after blending) has alpha. If this frame does not fill the
+ * entire image dimensions (see {@link AImageDecoderFrameInfo_getFrameRect})
+ * or it blends with an opaque frame, for example, the composed frame’s alpha
+ * may not match.
+ *
+ * Errors:
+ * - returns false if |info| is null.
+ */
+ AImageDecoderFrameInfo_hasAlphaWithinBounds :: proc(info: ^AImageDecoderFrameInfo) -> bool ---
+
+ /**
+ * Return how this frame is “disposed” before showing the next one.
+ *
+ * Introduced in API 31.
+ *
+ * This, along with other information in AImageDecoderFrameInfo,
+ * can be useful for determining whether a frame is independent, but
+ * the decoder handles disposing of frames, so a simple
+ * sequential client does not need this.
+ *
+ * @return one of:
+ * - {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE}
+ * - {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND}
+ * - {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS}
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if |info| is null.
+ */
+ AImageDecoderFrameInfo_getDisposeOp :: proc(info: ^AImageDecoderFrameInfo) -> ResultOrFrameDisposalOp ---
+
+ /**
+ * Return how this frame is blended with the previous frame.
+ *
+ * Introduced in API 31.
+ *
+ * This, along with other information in AImageDecoderFrameInfo,
+ * can be useful for determining whether a frame is independent, but
+ * the decoder handles blending frames, so a simple
+ * sequential client does not need this.
+ *
+ * @return one of:
+ * - {@link ANDROID_IMAGE_DECODER_BLEND_OP_SRC}
+ * - {@link ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER}
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if |info| is null.
+ */
+ AImageDecoderFrameInfo_getBlendOp :: proc(info: ^AImageDecoderFrameInfo) -> ResultOrBlendOp ---
+
+ /**
+ * Whether to have AImageDecoder store the frame prior to a
+ * frame marked {@link ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS}.
+ *
+ * Introduced in API 31.
+ *
+ * The default is true. Many images will not have such a frame (it
+ * is not supported by WebP, and only some GIFs use it). But
+ * if frame i is ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS, then i+1
+ * may depend on i-1. When this setting is true, AImageDecoder will
+ * defensively copy frame i-1 (i.e. the contents of |pixels| in
+ * {@link AImageDecoder_decodeImage}) into an internal buffer so that
+ * it can be used to decode i+1.
+ *
+ * AImageDecoder will only store a single frame, at the size specified
+ * by {@link AImageDecoder_setTargetSize} (or the original dimensions
+ * if that method has not been called), and will discard it when it is
+ * no longer necessary.
+ *
+ * A client that desires to manually store such frames may set this to
+ * false, so that AImageDecoder does not need to store this extra
+ * frame. Instead, when decoding the same
+ * ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS frame i, AImageDecoder
+ * will decode directly into |pixels|, assuming the client stored i-1.
+ * When asked to decode frame i+1, AImageDecoder will now assume that
+ * the client provided i-1 in |pixels|.
+ *
+ * @param decoder an {@link AImageDecoder} object.
+ * @param handleInternally Whether AImageDecoder will internally
+ * handle ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS
+ * frames.
+ */
+ AImageDecoder_setInternallyHandleDisposePrevious :: proc(decoder: ^AImageDecoder, handleInternally: bool) ---
+}
diff --git a/input.odin b/input.odin
new file mode 100644
index 0000000..0bf3040
--- /dev/null
+++ b/input.odin
@@ -0,0 +1,1289 @@
+//+build android
+package android
+
+foreign import android "system:android"
+
+/**
+ * Key states (may be returned by queries about the current state of a
+ * particular key code, scan code or switch).
+ */
+KeyState :: enum {
+ /** The key state is unknown or the requested key itself is not supported. */
+ UNKNOWN = -1,
+
+ /** The key is up. */
+ UP = 0,
+
+ /** The key is down. */
+ DOWN = 1,
+
+ /** The key is down but is a virtual key press that is being emulated by the system. */
+ VIRTUAL = 2
+}
+
+/**
+ * Meta key / modifier state.
+ */
+MetaKeyStateBits :: enum i32 {
+ ALT_ON = 1,
+ ALT_LEFT_ON = 4,
+ ALT_RIGHT_ON = 5,
+
+ SHIFT_ON = 0,
+ SHIFT_LEFT_ON = 6,
+ SHIFT_RIGHT_ON = 7,
+
+ SYM_ON = 2,
+ FUNCTION_ON = 3,
+
+ CTRL_ON = 12,
+ CTRL_LEFT_ON = 13,
+ CTRL_RIGHT_ON = 14,
+
+ META_ON = 16,
+ META_LEFT_ON = 17,
+ META_RIGHT_ON = 18,
+
+ CAPS_LOCK_ON = 20,
+ NUM_LOCK_ON = 21,
+ SCROLL_LOCK_ON = 22,
+}
+
+MetaKeyState :: bit_set[MetaKeyStateBits; i32]
+
+/**
+ * Input event types.
+ */
+InputEventType :: enum i32 {
+ /** Indicates that the input event is a key event. */
+ KEY = 1,
+
+ /** Indicates that the input event is a motion event. */
+ MOTION = 2,
+
+ /** Focus event */
+ FOCUS = 3,
+
+ /** Capture event */
+ CAPTURE = 4,
+
+ /** Drag event */
+ DRAG = 5,
+
+ /** TouchMode event */
+ TOUCH_MODE = 6,
+}
+
+/**
+ * Key event actions.
+ */
+KeyEventAction :: enum i32 {
+ /** The key has been pressed down. */
+ DOWN = 0,
+
+ /** The key has been released. */
+ UP = 1,
+
+ /**
+ * Multiple duplicate key events have occurred in a row, or a
+ * complex string is being delivered. The repeat_count property
+ * of the key event contains the number of times the given key
+ * code should be executed.
+ */
+ MULTIPLE = 2
+}
+
+/**
+ * Key event flags.
+ */
+KeyEventFlagsBits :: enum {
+ /** This mask is set if the device woke because of this key event. */
+ WOKE_HERE = 0,
+
+ /** This mask is set if the key event was generated by a software keyboard. */
+ SOFT_KEYBOARD = 1,
+
+ /** This mask is set if we don't want the key event to cause us to leave touch mode. */
+ KEEP_TOUCH_MODE = 2,
+
+ /**
+ * This mask is set if an event was known to come from a trusted
+ * part of the system. That is, the event is known to come from
+ * the user, and could not have been spoofed by a third party
+ * component.
+ */
+ FROM_SYSTEM = 3,
+
+ /**
+ * This mask is used for compatibility, to identify enter keys that are
+ * coming from an IME whose enter key has been auto-labelled "next" or
+ * "done". This allows TextView to dispatch these as normal enter keys
+ * for old applications, but still do the appropriate action when
+ * receiving them.
+ */
+ EDITOR_ACTION = 4,
+
+ /**
+ * When associated with up key events, this indicates that the key press
+ * has been canceled. Typically this is used with virtual touch screen
+ * keys, where the user can slide from the virtual key area on to the
+ * display: in that case, the application will receive a canceled up
+ * event and should not perform the action normally associated with the
+ * key. Note that for this to work, the application can not perform an
+ * action for a key until it receives an up or the long press timeout has
+ * expired.
+ */
+ CANCELED = 5,
+
+ /**
+ * This key event was generated by a virtual (on-screen) hard key area.
+ * Typically this is an area of the touchscreen, outside of the regular
+ * display, dedicated to "hardware" buttons.
+ */
+ VIRTUAL_HARD_KEY = 6,
+
+ /**
+ * This flag is set for the first key repeat that occurs after the
+ * long press timeout.
+ */
+ LONG_PRESS = 7,
+
+ /**
+ * Set when a key event has #AKEY_EVENT_FLAG_CANCELED set because a long
+ * press action was executed while it was down.
+ */
+ CANCELED_LONG_PRESS = 8,
+
+ /**
+ * Set for #AKEY_EVENT_ACTION_UP when this event's key code is still being
+ * tracked from its initial down. That is, somebody requested that tracking
+ * started on the key down and a long press has not caused
+ * the tracking to be canceled.
+ */
+ FLAG_TRACKING = 9,
+
+ /**
+ * Set when a key event has been synthesized to implement default behavior
+ * for an event that the application did not handle.
+ * Fallback key events are generated by unhandled trackball motions
+ * (to emulate a directional keypad) and by certain unhandled key presses
+ * that are declared in the key map (such as special function numeric keypad
+ * keys when numlock is off).
+ */
+ FLAG_FALLBACK = 10,
+}
+
+KeyEventFlags :: bit_set[KeyEventFlagsBits]
+
+/**
+ * Bit shift for the action bits holding the pointer index as
+ * defined by #AMOTION_EVENT_ACTION_POINTER_INDEX_MASK.
+ */
+AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT :: 8
+
+MotionEventAction :: enum i32 {
+ /** Bit mask of the parts of the action code that are the action itself. */
+ MASK = 0xff,
+
+ /**
+ * Bits in the action code that represent a pointer index, used with
+ * #AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting
+ * down by #AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer
+ * index where the data for the pointer going up or down can be found.
+ */
+ INDEX_MASK = 0xff00,
+
+ /** A pressed gesture has started, the motion contains the initial starting location. */
+ DOWN = 0,
+
+ /**
+ * A pressed gesture has finished, the motion contains the final release location
+ * as well as any intermediate points since the last down or move event.
+ */
+ UP = 1,
+
+ /**
+ * A change has happened during a press gesture (between #AMOTION_EVENT_ACTION_DOWN and
+ * #AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as
+ * any intermediate points since the last down or move event.
+ */
+ MOVE = 2,
+
+ /**
+ * The current gesture has been aborted.
+ * You will not receive any more points in it. You should treat this as
+ * an up event, but not perform any action that you normally would.
+ */
+ CANCEL = 3,
+
+ /**
+ * A movement has happened outside of the normal bounds of the UI element.
+ * This does not provide a full gesture, but only the initial location of the movement/touch.
+ */
+ OUTSIDE = 4,
+
+ /**
+ * A non-primary pointer has gone down.
+ * The bits in #AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
+ */
+ POINTER_DOWN = 5,
+
+ /**
+ * A non-primary pointer has gone up.
+ * The bits in #AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
+ */
+ POINTER_UP = 6,
+
+ /**
+ * A change happened but the pointer is not down (unlike #AMOTION_EVENT_ACTION_MOVE).
+ * The motion contains the most recent point, as well as any intermediate points since
+ * the last hover move event.
+ */
+ HOVER_MOVE = 7,
+
+ /**
+ * The motion event contains relative vertical and/or horizontal scroll offsets.
+ * Use {@link AMotionEvent_getAxisValue} to retrieve the information from
+ * #AMOTION_EVENT_AXIS_VSCROLL and #AMOTION_EVENT_AXIS_HSCROLL.
+ * The pointer may or may not be down when this event is dispatched.
+ * This action is always delivered to the winder under the pointer, which
+ * may not be the window currently touched.
+ */
+ SCROLL = 8,
+
+ /** The pointer is not down but has entered the boundaries of a window or view. */
+ HOVER_ENTER = 9,
+
+ /** The pointer is not down but has exited the boundaries of a window or view. */
+ HOVER_EXIT = 10,
+
+ /* One or more buttons have been pressed. */
+ BUTTON_PRESS = 11,
+
+ /* One or more buttons have been released. */
+ BUTTON_RELEASE = 12,
+}
+
+/**
+ * Motion event flags.
+ */
+MotionEventFlagsBits :: enum i32 {
+ /**
+ * This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it. This flag is set to true
+ * even if the event did not directly pass through the obscured area.
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ */
+ WINDOW_IS_OBSCURED = 0,
+}
+
+MotionEventFlags :: bit_set[MotionEventFlagsBits; i32]
+
+/**
+ * Motion event edge touch flags.
+ */
+MotionEventEdgeFlagsBits :: enum i32 {
+ /** Flag indicating the motion event intersected the top edge of the screen. */
+ TOP = 0,
+ /** Flag indicating the motion event intersected the bottom edge of the screen. */
+ BOTTOM = 1,
+ /** Flag indicating the motion event intersected the left edge of the screen. */
+ LEFT = 2,
+ /** Flag indicating the motion event intersected the right edge of the screen. */
+ RIGHT = 3,
+}
+
+MotionEventEdgeFlags :: bit_set[MotionEventEdgeFlagsBits; i32]
+
+/**
+ * Constants that identify each individual axis of a motion event.
+ * @anchor AMOTION_EVENT_AXIS
+ */
+MotionEventAxis :: enum i32 {
+ /**
+ * Axis constant: X axis of a motion event.
+ *
+ * - For a touch screen, reports the absolute X screen position of the center of
+ * the touch contact area. The units are display pixels.
+ * - For a touch pad, reports the absolute X surface position of the center of the touch
+ * contact area. The units are device-dependent.
+ * - For a mouse, reports the absolute X screen position of the mouse pointer.
+ * The units are display pixels.
+ * - For a trackball, reports the relative horizontal displacement of the trackball.
+ * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+ * - For a joystick, reports the absolute X position of the joystick.
+ * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+ */
+ X = 0,
+ /**
+ * Axis constant: Y axis of a motion event.
+ *
+ * - For a touch screen, reports the absolute Y screen position of the center of
+ * the touch contact area. The units are display pixels.
+ * - For a touch pad, reports the absolute Y surface position of the center of the touch
+ * contact area. The units are device-dependent.
+ * - For a mouse, reports the absolute Y screen position of the mouse pointer.
+ * The units are display pixels.
+ * - For a trackball, reports the relative vertical displacement of the trackball.
+ * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+ * - For a joystick, reports the absolute Y position of the joystick.
+ * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near).
+ */
+ Y = 1,
+ /**
+ * Axis constant: Pressure axis of a motion event.
+ *
+ * - For a touch screen or touch pad, reports the approximate pressure applied to the surface
+ * by a finger or other tool. The value is normalized to a range from
+ * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1
+ * may be generated depending on the calibration of the input device.
+ * - For a trackball, the value is set to 1 if the trackball button is pressed
+ * or 0 otherwise.
+ * - For a mouse, the value is set to 1 if the primary mouse button is pressed
+ * or 0 otherwise.
+ */
+ PRESSURE = 2,
+ /**
+ * Axis constant: Size axis of a motion event.
+ *
+ * - For a touch screen or touch pad, reports the approximate size of the contact area in
+ * relation to the maximum detectable size for the device. The value is normalized
+ * to a range from 0 (smallest detectable size) to 1 (largest detectable size),
+ * although it is not a linear scale. This value is of limited use.
+ * To obtain calibrated size information, see
+ * {@link AMOTION_EVENT_AXIS_TOUCH_MAJOR} or {@link AMOTION_EVENT_AXIS_TOOL_MAJOR}.
+ */
+ SIZE = 3,
+ /**
+ * Axis constant: TouchMajor axis of a motion event.
+ *
+ * - For a touch screen, reports the length of the major axis of an ellipse that
+ * represents the touch area at the point of contact.
+ * The units are display pixels.
+ * - For a touch pad, reports the length of the major axis of an ellipse that
+ * represents the touch area at the point of contact.
+ * The units are device-dependent.
+ */
+ TOUCH_MAJOR = 4,
+ /**
+ * Axis constant: TouchMinor axis of a motion event.
+ *
+ * - For a touch screen, reports the length of the minor axis of an ellipse that
+ * represents the touch area at the point of contact.
+ * The units are display pixels.
+ * - For a touch pad, reports the length of the minor axis of an ellipse that
+ * represents the touch area at the point of contact.
+ * The units are device-dependent.
+ *
+ * When the touch is circular, the major and minor axis lengths will be equal to one another.
+ */
+ TOUCH_MINOR = 5,
+ /**
+ * Axis constant: ToolMajor axis of a motion event.
+ *
+ * - For a touch screen, reports the length of the major axis of an ellipse that
+ * represents the size of the approaching finger or tool used to make contact.
+ * - For a touch pad, reports the length of the major axis of an ellipse that
+ * represents the size of the approaching finger or tool used to make contact.
+ * The units are device-dependent.
+ *
+ * When the touch is circular, the major and minor axis lengths will be equal to one another.
+ *
+ * The tool size may be larger than the touch size since the tool may not be fully
+ * in contact with the touch sensor.
+ */
+ TOOL_MAJOR = 6,
+ /**
+ * Axis constant: ToolMinor axis of a motion event.
+ *
+ * - For a touch screen, reports the length of the minor axis of an ellipse that
+ * represents the size of the approaching finger or tool used to make contact.
+ * - For a touch pad, reports the length of the minor axis of an ellipse that
+ * represents the size of the approaching finger or tool used to make contact.
+ * The units are device-dependent.
+ *
+ * When the touch is circular, the major and minor axis lengths will be equal to one another.
+ *
+ * The tool size may be larger than the touch size since the tool may not be fully
+ * in contact with the touch sensor.
+ */
+ TOOL_MINOR = 7,
+ /**
+ * Axis constant: Orientation axis of a motion event.
+ *
+ * - For a touch screen or touch pad, reports the orientation of the finger
+ * or tool in radians relative to the vertical plane of the device.
+ * An angle of 0 radians indicates that the major axis of contact is oriented
+ * upwards, is perfectly circular or is of unknown orientation. A positive angle
+ * indicates that the major axis of contact is oriented to the right. A negative angle
+ * indicates that the major axis of contact is oriented to the left.
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
+ * (finger pointing fully right).
+ * - For a stylus, the orientation indicates the direction in which the stylus
+ * is pointing in relation to the vertical axis of the current orientation of the screen.
+ * The range is from -PI radians to PI radians, where 0 is pointing up,
+ * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians
+ * is pointing right. See also #AMOTION_EVENT_AXIS_TILT.
+ */
+ ORIENTATION = 8,
+ /**
+ * Axis constant: Vertical Scroll axis of a motion event.
+ *
+ * - For a mouse, reports the relative movement of the vertical scroll wheel.
+ * The value is normalized to a range from -1.0 (down) to 1.0 (up).
+ *
+ * This axis should be used to scroll views vertically.
+ */
+ VSCROLL = 9,
+ /**
+ * Axis constant: Horizontal Scroll axis of a motion event.
+ *
+ * - For a mouse, reports the relative movement of the horizontal scroll wheel.
+ * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+ *
+ * This axis should be used to scroll views horizontally.
+ */
+ HSCROLL = 10,
+ /**
+ * Axis constant: Z axis of a motion event.
+ *
+ * - For a joystick, reports the absolute Z position of the joystick.
+ * The value is normalized to a range from -1.0 (high) to 1.0 (low).
+ * On game pads with two analog joysticks, this axis is often reinterpreted
+ * to report the absolute X position of the second joystick instead.
+ */
+ Z = 11,
+ /**
+ * Axis constant: X Rotation axis of a motion event.
+ *
+ * - For a joystick, reports the absolute rotation angle about the X axis.
+ * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+ */
+ RX = 12,
+ /**
+ * Axis constant: Y Rotation axis of a motion event.
+ *
+ * - For a joystick, reports the absolute rotation angle about the Y axis.
+ * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+ */
+ RY = 13,
+ /**
+ * Axis constant: Z Rotation axis of a motion event.
+ *
+ * - For a joystick, reports the absolute rotation angle about the Z axis.
+ * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+ * On game pads with two analog joysticks, this axis is often reinterpreted
+ * to report the absolute Y position of the second joystick instead.
+ */
+ RZ = 14,
+ /**
+ * Axis constant: Hat X axis of a motion event.
+ *
+ * - For a joystick, reports the absolute X position of the directional hat control.
+ * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+ */
+ HAT_X = 15,
+ /**
+ * Axis constant: Hat Y axis of a motion event.
+ *
+ * - For a joystick, reports the absolute Y position of the directional hat control.
+ * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+ */
+ HAT_Y = 16,
+ /**
+ * Axis constant: Left Trigger axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the left trigger control.
+ * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
+ */
+ LTRIGGER = 17,
+ /**
+ * Axis constant: Right Trigger axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the right trigger control.
+ * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
+ */
+ RTRIGGER = 18,
+ /**
+ * Axis constant: Throttle axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the throttle control.
+ * The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
+ */
+ THROTTLE = 19,
+ /**
+ * Axis constant: Rudder axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the rudder control.
+ * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+ */
+ RUDDER = 20,
+ /**
+ * Axis constant: Wheel axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the steering wheel control.
+ * The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
+ */
+ WHEEL = 21,
+ /**
+ * Axis constant: Gas axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the gas (accelerator) control.
+ * The value is normalized to a range from 0.0 (no acceleration)
+ * to 1.0 (maximum acceleration).
+ */
+ GAS = 22,
+ /**
+ * Axis constant: Brake axis of a motion event.
+ *
+ * - For a joystick, reports the absolute position of the brake control.
+ * The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
+ */
+ BRAKE = 23,
+ /**
+ * Axis constant: Distance axis of a motion event.
+ *
+ * - For a stylus, reports the distance of the stylus from the screen.
+ * A value of 0.0 indicates direct contact and larger values indicate increasing
+ * distance from the surface.
+ */
+ DISTANCE = 24,
+ /**
+ * Axis constant: Tilt axis of a motion event.
+ *
+ * - For a stylus, reports the tilt angle of the stylus in radians where
+ * 0 radians indicates that the stylus is being held perpendicular to the
+ * surface, and PI/2 radians indicates that the stylus is being held flat
+ * against the surface.
+ */
+ TILT = 25,
+ /**
+ * Axis constant: Generic scroll axis of a motion event.
+ *
+ * - This is used for scroll axis motion events that can't be classified as strictly
+ * vertical or horizontal. The movement of a rotating scroller is an example of this.
+ */
+ SCROLL = 26,
+ /**
+ * Axis constant: The movement of x position of a motion event.
+ *
+ * - For a mouse, reports a difference of x position between the previous position.
+ * This is useful when pointer is captured, in that case the mouse pointer doesn't
+ * change the location but this axis reports the difference which allows the app
+ * to see how the mouse is moved.
+ */
+ RELATIVE_X = 27,
+ /**
+ * Axis constant: The movement of y position of a motion event.
+ *
+ * Same as #AMOTION_EVENT_AXIS_RELATIVE_X, but for y position.
+ */
+ RELATIVE_Y = 28,
+ /**
+ * Axis constant: Generic 1 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_1 = 32,
+ /**
+ * Axis constant: Generic 2 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_2 = 33,
+ /**
+ * Axis constant: Generic 3 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_3 = 34,
+ /**
+ * Axis constant: Generic 4 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_4 = 35,
+ /**
+ * Axis constant: Generic 5 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_5 = 36,
+ /**
+ * Axis constant: Generic 6 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_6 = 37,
+ /**
+ * Axis constant: Generic 7 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_7 = 38,
+ /**
+ * Axis constant: Generic 8 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_8 = 39,
+ /**
+ * Axis constant: Generic 9 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_9 = 40,
+ /**
+ * Axis constant: Generic 10 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_10 = 41,
+ /**
+ * Axis constant: Generic 11 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_11 = 42,
+ /**
+ * Axis constant: Generic 12 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_12 = 43,
+ /**
+ * Axis constant: Generic 13 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_13 = 44,
+ /**
+ * Axis constant: Generic 14 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_14 = 45,
+ /**
+ * Axis constant: Generic 15 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_15 = 46,
+ /**
+ * Axis constant: Generic 16 axis of a motion event.
+ * The interpretation of a generic axis is device-specific.
+ */
+ GENERIC_16 = 47,
+}
+
+/**
+ * Constants that identify buttons that are associated with motion events.
+ * Refer to the documentation on the MotionEvent class for descriptions of each button.
+ */
+// TODO: bit_set this?
+MotionEventButton :: enum {
+ PRIMARY = 1 << 0,
+ SECONDARY = 1 << 1,
+ TERTIARY = 1 << 2,
+ BACK = 1 << 3,
+ FORWARD = 1 << 4,
+ STYLUS_PRIMARY = 1 << 5,
+ STYLUS_SECONDARY = 1 << 6,
+}
+
+/**
+ * Constants that identify tool types.
+ * Refer to the documentation on the MotionEvent class for descriptions of each tool type.
+ */
+ToolType :: enum i32 {
+ UNKNOWN = 0,
+ FINGER = 1,
+ STYLUS = 2,
+ MOUSE = 3,
+ ERASER = 4,
+ PALM = 5,
+}
+
+/**
+ * Constants that identify different gesture classification types.
+ */
+AMotionClassification :: enum i32 {
+ /**
+ * Classification constant: None.
+ *
+ * No additional information is available about the current motion event stream.
+ */
+ NONE = 0,
+ /**
+ * Classification constant: Ambiguous gesture.
+ *
+ * The user's intent with respect to the current event stream is not yet determined. Events
+ * starting in #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE will eventually resolve into
+ * either #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS or #AMOTION_EVENT_CLASSIFICATION_NONE.
+ * Gestural actions, such as scrolling, should be inhibited until the classification resolves
+ * to another value or the event stream ends.
+ */
+ 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.
+ */
+ DEEP_PRESS = 2,
+}
+
+/**
+ * Input source masks.
+ *
+ * Refer to the documentation on android.view.InputDevice for more details about input sources
+ * and their correct interpretation.
+ */
+InputSourceClass :: enum i32 {
+ NONE = 0x00000000,
+ BUTTON = 0x00000001,
+ POINTER = 0x00000002,
+ NAVIGATION = 0x00000004,
+ POSITION = 0x00000008,
+ JOYSTICK = 0x00000010,
+ MASK = 0x000000ff,
+}
+
+/**
+ * Input sources.
+ */
+InputSource :: enum i32 {
+ UNKNOWN = 0x00000000,
+
+ KEYBOARD = 0x00000100 | i32(InputSourceClass.BUTTON),
+ DPAD = 0x00000200 | i32(InputSourceClass.BUTTON),
+ GAMEPAD = 0x00000400 | i32(InputSourceClass.BUTTON),
+ TOUCHSCREEN = 0x00001000 | i32(InputSourceClass.POINTER),
+ MOUSE = 0x00002000 | i32(InputSourceClass.POINTER),
+ STYLUS = 0x00004000 | i32(InputSourceClass.POINTER),
+ BLUETOOTH_STYLUS = 0x00008000 | STYLUS,
+ TRACKBALL = 0x00010000 | i32(InputSourceClass.NAVIGATION),
+ MOUSE_RELATIVE = 0x00020000 | i32(InputSourceClass.NAVIGATION),
+ TOUCHPAD = 0x00100000 | i32(InputSourceClass.POSITION),
+ TOUCH_NAVIGATION = 0x00200000 | i32(InputSourceClass.NONE),
+ JOYSTICK = 0x01000000 | i32(InputSourceClass.JOYSTICK),
+ HDMI = 0x02000000 | i32(InputSourceClass.BUTTON),
+ SENSOR = 0x04000000 | i32(InputSourceClass.NONE),
+ ROTARY_ENCODER = 0x00400000 | i32(InputSourceClass.NONE),
+
+ ANY = -256, // 0xffffff00
+}
+
+/**
+ * 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.
+ */
+KeyBoardType :: enum {
+ NONE = 0,
+ NON_ALPHABETIC = 1,
+ TYPE_ALPHABETIC = 2,
+}
+
+/**
+ * Constants used to retrieve information about the range of motion for a particular
+ * coordinate of a motion event.
+ *
+ * Refer to the documentation on android.view.InputDevice for more details about input sources
+ * and their correct interpretation.
+ *
+ * @deprecated These constants are deprecated. Use {@link AMOTION_EVENT_AXIS AMOTION_EVENT_AXIS_*}
+ * constants instead.
+ */
+// TODO: should I just delete this ??
+MotionRange :: enum {
+ X = 0,
+ Y = 1,
+ PRESSURE = 2,
+ SIZE = 3,
+ TOUCH_MAJOR = 4,
+ TOUCH_MINOR = 5,
+ TOOL_MAJOR = 6,
+ TOOL_MINOR = 7,
+ ORIENTATION = 8,
+}
+
+/**
+ * Input events.
+ *
+ * Input events are opaque structures. Use the provided accessors functions to
+ * read their properties.
+ */
+AInputEvent :: struct{}
+/**
+ * Input queue
+ *
+ * An input queue is the facility through which you retrieve input
+ * events.
+ */
+AInputQueue :: struct{}
+
+foreign android {
+ /** Get the input event type. */
+ AInputEvent_getType :: proc(event: ^AInputEvent) -> InputEventType ---
+
+ /** Get the id for the device that an input event came from.
+ *
+ * Input events can be generated by multiple different input devices.
+ * Use the input device id to obtain information about the input
+ * device that was responsible for generating a particular event.
+ *
+ * An input device id of 0 indicates that the event didn't come from a physical device
+ * other numbers are arbitrary and you shouldn't depend on the values.
+ * Use the provided input device query API to obtain information about input devices.
+ */
+ AInputEvent_getDeviceId :: proc(event: ^AInputEvent) -> i32 ---
+
+ /** Get the input event source. */
+ AInputEvent_getSource :: proc(event: ^AInputEvent) -> InputSource ---
+
+ /**
+ * Releases interface objects created by {@link AKeyEvent_fromJava()}
+ * and {@link AMotionEvent_fromJava()}.
+ * After returning, the specified {@link 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.
+ */
+ AInputEvent_release :: proc(event: ^AInputEvent) ---
+
+ /** Get the key event action. */
+ AKeyEvent_getAction :: proc(key_event: ^AInputEvent) -> KeyEventAction ---
+
+ /** Get the key event flags. */
+ AKeyEvent_getFlags :: proc(key_event: ^AInputEvent) -> KeyEventFlags ---
+
+ /**
+ * Get the key code of the key event.
+ * This is the physical key that was pressed, not the Unicode character.
+ */
+ AKeyEvent_getKeyCode :: proc(key_event: ^AInputEvent) -> i32 ---
+
+ /**
+ * Get the hardware key id of this key event.
+ * These values are not reliable and vary from device to device.
+ */
+ AKeyEvent_getScanCode :: proc(key_event: ^AInputEvent) -> i32 ---
+
+ /** Get the meta key state. */
+ AKeyEvent_getMetaState :: proc(key_event: ^AInputEvent) -> MetaKeyState ---
+
+ /**
+ * Get the repeat count of the event.
+ * For both key up an key down events, this is the number of times the key has
+ * repeated with the first down starting at 0 and counting up from there. For
+ * multiple key events, this is the number of down/up pairs that have occurred.
+ */
+ AKeyEvent_getRepeatCount :: proc(key_event: ^AInputEvent) -> i32 ---
+
+ /**
+ * Get the time of the most recent key down event, in the
+ * java.lang.System.nanoTime() time base. If this is a down event,
+ * this will be the same as eventTime.
+ * Note that when chording keys, this value is the down time of the most recently
+ * pressed key, which may not be the same physical key of this event.
+ */
+ AKeyEvent_getDownTime :: proc(key_event: ^AInputEvent) -> i64 ---
+
+ /**
+ * Get the time this event occurred, in the
+ * java.lang.System.nanoTime() time base.
+ */
+ AKeyEvent_getEventTime :: proc(key_event: ^AInputEvent) -> i64 ---
+
+ /**
+ * Creates a native {@link 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.
+ */
+ AKeyEvent_fromJava :: proc(env: ^JNIEnv, keyEvent: jobject) -> ^AInputEvent ---
+
+ /** Get the combined motion event action code and pointer index. */
+ AMotionEvent_getAction :: proc(motion_event: ^AInputEvent) -> MotionEventAction ---
+
+ /** Get the motion event flags. */
+ AMotionEvent_getFlags :: proc(motion_event: ^AInputEvent) -> MotionEventFlags ---
+
+ /**
+ * Get the state of any meta / modifier keys that were in effect when the
+ * event was generated.
+ */
+ AMotionEvent_getMetaState :: proc(motion_event: ^AInputEvent) -> MetaKeyState ---
+
+ /** Get the button state of all buttons that are pressed. */
+ // TODO: Do we have an enum or bit_set for this ??? this might be MotionEventButton but we'll double check by
+ // writing some code and printing values.
+ AMotionEvent_getButtonState :: proc(motion_event: ^AInputEvent) -> i32 ---
+
+ /**
+ * Get a bitfield indicating which edges, if any, were touched by this motion event.
+ * For touch events, clients can use this to determine if the user's finger was
+ * touching the edge of the display.
+ */
+ AMotionEvent_getEdgeFlags :: proc(motion_event: ^AInputEvent) -> MotionEventEdgeFlags ---
+
+ /**
+ * Get the time when the user originally pressed down to start a stream of
+ * position events, in the java.lang.System.nanoTime() time base.
+ */
+ AMotionEvent_getDownTime :: proc(motion_event: ^AInputEvent) -> i64 ---
+
+ /**
+ * Get the time when this specific event was generated,
+ * in the java.lang.System.nanoTime() time base.
+ */
+ AMotionEvent_getEventTime :: proc(motion_event: ^AInputEvent) -> i64 ---
+
+ /**
+ * Get the X coordinate offset.
+ * For touch events on the screen, this is the delta that was added to the raw
+ * screen coordinates to adjust for the absolute position of the containing windows
+ * and views.
+ */
+ AMotionEvent_getXOffset :: proc(motion_event: ^AInputEvent) -> f32 ---
+
+ /**
+ * Get the Y coordinate offset.
+ * For touch events on the screen, this is the delta that was added to the raw
+ * screen coordinates to adjust for the absolute position of the containing windows
+ * and views.
+ */
+ AMotionEvent_getYOffset :: proc(motion_event: ^AInputEvent) -> f32 ---
+
+ /**
+ * Get the precision of the X coordinates being reported.
+ * You can multiply this number with an X coordinate sample to find the
+ * actual hardware value of the X coordinate.
+ */
+ AMotionEvent_getXPrecision :: proc(#by_ptr motion_event: AInputEvent) -> f32 ---
+
+ /**
+ * Get the precision of the Y coordinates being reported.
+ * You can multiply this number with a Y coordinate sample to find the
+ * actual hardware value of the Y coordinate.
+ */
+ AMotionEvent_getYPrecision :: proc(#by_ptr motion_event: AInputEvent) -> f32 ---
+
+ /**
+ * Get the number of pointers of data contained in this event.
+ * Always >= 1.
+ */
+ AMotionEvent_getPointerCount :: proc(motion_event: ^AInputEvent) -> uint ---
+
+ /**
+ * Get the pointer identifier associated with a particular pointer
+ * data index in this event. The identifier tells you the actual pointer
+ * number associated with the data, accounting for individual pointers
+ * going up and down since the start of the current gesture.
+ */
+ AMotionEvent_getPointerId :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> i32 ---
+
+ /**
+ * Get the tool type of a pointer for the given pointer index.
+ * The tool type indicates the type of tool used to make contact such as a
+ * finger or stylus, if known.
+ */
+ AMotionEvent_getToolType :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> ToolType ---
+
+ /**
+ * Get the original raw X coordinate of this event.
+ * For touch events on the screen, this is the original location of the event
+ * on the screen, before it had been adjusted for the containing window
+ * and views.
+ */
+ AMotionEvent_getRawX :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the original raw X coordinate of this event.
+ * For touch events on the screen, this is the original location of the event
+ * on the screen, before it had been adjusted for the containing window
+ * and views.
+ */
+ AMotionEvent_getRawY :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current X coordinate of this event for the given pointer index.
+ * Whole numbers are pixels the value may have a fraction for input devices
+ * that are sub-pixel precise.
+ */
+ AMotionEvent_getX :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current Y coordinate of this event for the given pointer index.
+ * Whole numbers are pixels the value may have a fraction for input devices
+ * that are sub-pixel precise.
+ */
+ AMotionEvent_getY :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current pressure of this event for the given pointer index.
+ * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
+ * although values higher than 1 may be generated depending on the calibration of
+ * the input device.
+ */
+ AMotionEvent_getPressure :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current scaled value of the approximate size for the given pointer index.
+ * This represents some approximation of the area of the screen being
+ * pressed the actual value in pixels corresponding to the
+ * touch is normalized with the device specific range of values
+ * and scaled to a value between 0 and 1. The value of size can be used to
+ * determine fat touch events.
+ */
+ AMotionEvent_getSize :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current length of the major axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index.
+ */
+ AMotionEvent_getTouchMajor :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current length of the minor axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index.
+ */
+ AMotionEvent_getTouchMinor :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current length of the major axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact.
+ */
+ AMotionEvent_getToolMajor :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current length of the minor axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact.
+ */
+ AMotionEvent_getToolMinor :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the current orientation of the touch area and tool area in radians clockwise from
+ * vertical for the given pointer index.
+ * An angle of 0 degrees indicates that the major axis of contact is oriented
+ * upwards, is perfectly circular or is of unknown orientation. A positive angle
+ * indicates that the major axis of contact is oriented to the right. A negative angle
+ * indicates that the major axis of contact is oriented to the left.
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
+ * (finger pointing fully right).
+ */
+ AMotionEvent_getOrientation :: proc(motion_event: ^AInputEvent, pointer_index: uint) -> f32 ---
+
+ /** Get the value of the request axis for the given pointer index. */
+ AMotionEvent_getAxisValue :: proc(motion_event: ^AInputEvent, axis: MotionEventAxis, pointer_index: uint) -> f32 ---
+
+ /**
+ * Get the number of historical points in this event. These are movements that
+ * have occurred between this event and the previous event. This only applies
+ * to #AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0.
+ * Historical samples are indexed from oldest to newest.
+ */
+ AMotionEvent_getHistorySize :: proc(motion_event: ^AInputEvent) -> uint ---
+
+ /**
+ * Get the time that a historical movement occurred between this event and
+ * the previous event, in the java.lang.System.nanoTime() time base.
+ */
+ AMotionEvent_getHistoricalEventTime :: proc(motion_event: ^AInputEvent, history_index: uint) -> i64 ---
+
+ /**
+ * Get the historical raw X coordinate of this event for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * For touch events on the screen, this is the original location of the event
+ * on the screen, before it had been adjusted for the containing window
+ * and views.
+ * Whole numbers are pixels the value may have a fraction for input devices
+ * that are sub-pixel precise.
+ */
+ AMotionEvent_getHistoricalRawX :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical raw Y coordinate of this event for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * For touch events on the screen, this is the original location of the event
+ * on the screen, before it had been adjusted for the containing window
+ * and views.
+ * Whole numbers are pixels the value may have a fraction for input devices
+ * that are sub-pixel precise.
+ */
+ AMotionEvent_getHistoricalRawY :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical X coordinate of this event for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * Whole numbers are pixels the value may have a fraction for input devices
+ * that are sub-pixel precise.
+ */
+ AMotionEvent_getHistoricalX :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical Y coordinate of this event for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * Whole numbers are pixels the value may have a fraction for input devices
+ * that are sub-pixel precise.
+ */
+ AMotionEvent_getHistoricalY :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical pressure of this event for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
+ * although values higher than 1 may be generated depending on the calibration of
+ * the input device.
+ */
+ AMotionEvent_getHistoricalPressure :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the current scaled value of the approximate size for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * This represents some approximation of the area of the screen being
+ * pressed the actual value in pixels corresponding to the
+ * touch is normalized with the device specific range of values
+ * and scaled to a value between 0 and 1. The value of size can be used to
+ * determine fat touch events.
+ */
+ AMotionEvent_getHistoricalSize :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical length of the major axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index that
+ * occurred between this event and the previous motion event.
+ */
+ AMotionEvent_getHistoricalTouchMajor :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical length of the minor axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index that
+ * occurred between this event and the previous motion event.
+ */
+ AMotionEvent_getHistoricalTouchMinor :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical length of the major axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact.
+ */
+ AMotionEvent_getHistoricalToolMajor :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical length of the minor axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact.
+ */
+ AMotionEvent_getHistoricalToolMinor :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical orientation of the touch area and tool area in radians clockwise from
+ * vertical for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * An angle of 0 degrees indicates that the major axis of contact is oriented
+ * upwards, is perfectly circular or is of unknown orientation. A positive angle
+ * indicates that the major axis of contact is oriented to the right. A negative angle
+ * indicates that the major axis of contact is oriented to the left.
+ * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians
+ * (finger pointing fully right).
+ */
+ AMotionEvent_getHistoricalOrientation :: proc(motion_event: ^AInputEvent, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * Get the historical value of the request axis for the given pointer index
+ * that occurred between this event and the previous motion event.
+ */
+ AMotionEvent_getHistoricalAxisValue :: proc(motion_event: ^AInputEvent, axis: MotionEventAxis, pointer_index: uint, history_index: uint) -> f32 ---
+
+ /**
+ * 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.
+ *
+ * Available since API level 33.
+ *
+ * @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
+ */
+ AMotionEvent_getActionButton :: proc(motion_event: ^AInputEvent) -> MotionEventButton ---
+
+ /**
+ * Returns the classification for the current gesture.
+ * The classification may change as more events become available for the same gesture.
+ *
+ * Available since API level 33.
+ *
+ * @see #AMOTION_EVENT_CLASSIFICATION_NONE
+ * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE
+ * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS
+ */
+ AMotionEvent_getClassification :: proc(motion_event: ^AInputEvent) -> AMotionClassification ---
+
+ /**
+ * Creates a native {@link 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.
+ */
+ AMotionEvent_fromJava :: proc(env: ^JNIEnv, motionEvent: jobject) -> ^AInputEvent ---
+
+ /**
+ * Add this input queue to a looper for processing. See
+ * {@link ALooper_addFd()} for information on the ident, callback, and data params.
+ */
+ AInputQueue_attachLooper :: proc(queue: ^AInputQueue, looper: ^ALooper, ident: i32, callback: ALooper_callbackFunc, data: rawptr) ---
+
+ /**
+ * Remove the input queue from the looper it is currently attached to.
+ */
+ AInputQueue_detachLooper :: proc(queue: ^AInputQueue) ---
+
+ /**
+ * Returns true if there are one or more events available in the
+ * input queue. Returns 1 if the queue has events 0 if
+ * it does not have events and a negative value if there is an error.
+ */
+ AInputQueue_hasEvents :: proc(queue: ^AInputQueue) -> i32 ---
+
+ /**
+ * Returns the next available event from the queue. Returns a negative
+ * value if no events are available or an error has occurred.
+ */
+ AInputQueue_getEvent :: proc(queue: ^AInputQueue, outEvent: ^^AInputEvent) -> i32 ---
+
+ /**
+ * Sends the key for standard pre-dispatching -- that is, possibly deliver
+ * it to the current IME to be consumed before the app. Returns 0 if it
+ * was not pre-dispatched, meaning you can process it right now. If non-zero
+ * is returned, you must abandon the current event processing and allow the
+ * event to appear again in the event queue (if it does not get consumed during
+ * pre-dispatching).
+ */
+ AInputQueue_preDispatchEvent :: proc(queue: ^AInputQueue, event: ^AInputEvent) -> i32 ---
+
+ /**
+ * Report that dispatching has finished with the given event.
+ * This must be called after receiving an event with {@link AInputQueue_getEvent()}.
+ */
+ AInputQueue_finishEvent :: proc(queue: ^AInputQueue, event: ^AInputEvent, handled: i32) ---
+
+ /**
+ * Returns the {@link 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_fromJava :: proc(env: ^JNIEnv, inputQueue: jobject) -> ^AInputQueue ---
+}
diff --git a/jni.odin b/jni.odin
new file mode 100644
index 0000000..a013a84
--- /dev/null
+++ b/jni.odin
@@ -0,0 +1,367 @@
+//+build android
+package android
+
+import "core:c"
+
+/* Primitive types that match up with Java equivalents. */
+jboolean :: c.uint8_t /* unsigned 8 bits */
+jbyte :: c.int8_t /* signed 8 bits */
+jchar :: c.uint16_t /* unsigned 16 bits */
+jshort :: c.int16_t /* signed 16 bits */
+jint :: c.int32_t /* signed 32 bits */
+jlong :: c.int64_t /* signed 64 bits */
+jfloat :: c.float /* 32-bit IEEE 754 */
+jdouble :: c.double /* 64-bit IEEE 754 */
+
+/* "cardinal indices and sizes" */
+jsize :: jint
+
+/*
+ * Reference types, in C.
+ */
+jobject :: distinct rawptr
+jclass :: distinct jobject
+jstring :: distinct jobject
+jarray :: distinct jobject
+jobjectArray :: distinct jarray
+jbooleanArray :: distinct jarray
+jbyteArray :: distinct jarray
+jcharArray :: distinct jarray
+jshortArray :: distinct jarray
+jintArray :: distinct jarray
+jlongArray :: distinct jarray
+jfloatArray :: distinct jarray
+jdoubleArray :: distinct jarray
+jthrowable :: distinct jobject
+jweak :: distinct jobject
+
+// Opaque
+jfieldID :: rawptr
+jmethodID :: rawptr
+
+jvalue :: struct #raw_union {
+ z: jboolean,
+ b: jbyte,
+ c: jchar,
+ s: jshort,
+ i: jint,
+ j: jlong,
+ f: jfloat,
+ d: jdouble,
+ l: jobject,
+}
+
+jobjectRefType :: enum c.int {
+ JNIInvalidRefType = 0,
+ JNILocalRefType = 1,
+ JNIGlobalRefType = 2,
+ JNIWeakGlobalRefType = 3
+}
+
+JNINativeMethod :: struct {
+ name: cstring,
+ signature: cstring,
+ fnPtr: rawptr,
+}
+
+JavaVM :: ^JNIInvokeInterface
+JNIEnv :: ^JNINativeInterface
+
+// NOTE: JNINativeInterface and JNIInvokeInterface don't use the aliased pointer types because of they're considered
+// not defined when used inside the structs so we just refer to the struct itself and add an extra pointer hat ^
+
+/*
+ * Table of interface function pointers.
+ */
+JNINativeInterface :: struct {
+ reserved0: rawptr,
+ reserved1: rawptr,
+ reserved2: rawptr,
+ reserved3: rawptr,
+
+ GetVersion: #type proc "c" (jni: ^^JNINativeInterface) -> jint,
+
+ DefineClass: #type proc "c" (jni: ^^JNINativeInterface, name: cstring, loader: jobject, #by_ptr buf: jbyte, bufLen: jsize) -> jclass,
+ FindClass: #type proc "c" (jni: ^^JNINativeInterface, name: cstring) -> jclass,
+
+ FromReflectedMethod: #type proc "c" (jni: ^^JNINativeInterface, method: jobject) -> jmethodID,
+ FromReflectedField: #type proc "c" (jni: ^^JNINativeInterface, field: jobject) -> jfieldID,
+ /* spec doesn't show jboolean parameter */
+ ToReflectedMethod: #type proc "c" (jni: ^^JNINativeInterface, cls: jclass, methodID: jmethodID, isStatic: jboolean) -> jobject,
+
+ GetSuperclass: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass) -> jclass,
+ IsAssignableFrom: #type proc "c" (jni: ^^JNINativeInterface, clazz1: jclass, clazz2: jclass) -> jboolean,
+
+ /* spec doesn't show jboolean parameter */
+ ToReflectedField: #type proc "c" (jni: ^^JNINativeInterface, cls: jclass, fieldID: jfieldID, isStatic: jboolean) -> jobject,
+
+ Throw: #type proc "c" (jni: ^^JNINativeInterface, obj: jthrowable) -> jint,
+ ThrowNew: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, message: cstring) -> jint,
+ ExceptionOccurred: #type proc "c" (jni: ^^JNINativeInterface),
+ ExceptionDescribe: #type proc "c" (jni: ^^JNINativeInterface),
+ ExceptionClear: #type proc "c" (jni: ^^JNINativeInterface),
+ FatalError: #type proc "c" (jni: ^^JNINativeInterface, msg: cstring),
+
+ PushLocalFrame: #type proc "c" (jni: ^^JNINativeInterface, capacity: jint) -> jint,
+ PopLocalFrame: #type proc "c" (jni: ^^JNINativeInterface, result: jobject) -> jobject,
+
+ NewGlobalRef: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject) -> jobject,
+ DeleteGlobalRef: #type proc "c" (jni: ^^JNINativeInterface, globalRef: jobject),
+ DeleteLocalRef: #type proc "c" (jni: ^^JNINativeInterface, localRef: jobject),
+ IsSameObject: #type proc "c" (jni: ^^JNINativeInterface, ref1: jobject, ref2: jobject) -> jboolean,
+
+ NewLocalRef: #type proc "c" (jni: ^^JNINativeInterface, ref: jobject) -> jobject,
+ EnsureLocalCapacity: #type proc "c" (jni: ^^JNINativeInterface, capacity: jint) -> jint,
+
+ AllocObject: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass) -> jobject,
+ NewObject: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jobject,
+ NewObjectV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jobject,
+ NewObjectA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jobject,
+
+ GetObjectClass: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject) -> jclass,
+ IsInstanceOf: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass) -> jboolean,
+ GetMethodID: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, name: cstring, sig: cstring) -> jmethodID,
+
+ // TODO: should va_list args be pointers?
+ CallObjectMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jobject,
+ CallObjectMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jobject,
+ CallObjectMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jobject,
+ CallBooleanMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jboolean,
+ CallBooleanMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jboolean,
+ CallBooleanMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jboolean,
+ CallByteMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jbyte,
+ CallByteMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jbyte,
+ CallByteMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jbyte,
+ CallCharMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jchar,
+ CallCharMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jchar,
+ CallCharMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jchar,
+ CallShortMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jshort,
+ CallShortMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jshort,
+ CallShortMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jshort,
+ CallIntMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jint,
+ CallIntMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jint,
+ CallIntMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jint,
+ CallLongMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jlong,
+ CallLongMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jlong,
+ CallLongMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jlong,
+ CallFloatMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jfloat,
+ CallFloatMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jfloat,
+ CallFloatMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jfloat,
+ CallDoubleMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any) -> jdouble,
+ CallDoubleMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list) -> jdouble,
+ CallDoubleMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue) -> jdouble,
+ CallVoidMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #c_vararg args: ..any),
+ CallVoidMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, args: ^c.va_list),
+ CallVoidMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, methodID: jmethodID, #by_ptr args: jvalue),
+
+ CallNonvirtualObjectMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jobject,
+ CallNonvirtualObjectMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jobject,
+ CallNonvirtualObjectMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jobject,
+ CallNonvirtualBooleanMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jboolean,
+ CallNonvirtualBooleanMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jboolean,
+ CallNonvirtualBooleanMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jboolean,
+ CallNonvirtualByteMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jbyte,
+ CallNonvirtualByteMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jbyte,
+ CallNonvirtualByteMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jbyte,
+ CallNonvirtualCharMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jchar,
+ CallNonvirtualCharMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jchar,
+ CallNonvirtualCharMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jchar,
+ CallNonvirtualShortMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jshort,
+ CallNonvirtualShortMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jshort,
+ CallNonvirtualShortMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jshort,
+ CallNonvirtualIntMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jint,
+ CallNonvirtualIntMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jint,
+ CallNonvirtualIntMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jint,
+ CallNonvirtualLongMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jlong,
+ CallNonvirtualLongMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jlong,
+ CallNonvirtualLongMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jlong,
+ CallNonvirtualFloatMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jfloat,
+ CallNonvirtualFloatMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jfloat,
+ CallNonvirtualFloatMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jfloat,
+ CallNonvirtualDoubleMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jdouble,
+ CallNonvirtualDoubleMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jdouble,
+ CallNonvirtualDoubleMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jdouble,
+ CallNonvirtualVoidMethod: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any),
+ CallNonvirtualVoidMethodV: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, args: ^c.va_list),
+ CallNonvirtualVoidMethodA: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue),
+
+ GetFieldID: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, name: cstring, sig: cstring) -> jfieldID,
+
+ GetObjectField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jobject,
+ GetBooleanField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jboolean,
+ GetByteField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jbyte,
+ GetCharField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jchar,
+ GetShortField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jshort,
+ GetIntField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jint,
+ GetLongField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jlong,
+ GetFloatField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jfloat,
+ GetDoubleField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID) -> jdouble,
+
+ SetObjectField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jobject),
+ SetBooleanField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jboolean),
+ SetByteField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jbyte),
+ SetCharField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jchar),
+ SetShortField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jshort),
+ SetIntField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jint),
+ SetLongField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jlong),
+ SetFloatField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jfloat),
+ SetDoubleField: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject, fieldID: jfieldID, value: jdouble),
+
+ GetStaticMethodID: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, name: cstring, sig: cstring) -> jmethodID,
+
+ CallStaticObjectMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jobject,
+ CallStaticObjectMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jobject,
+ CallStaticObjectMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jobject,
+ CallStaticBooleanMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jboolean,
+ CallStaticBooleanMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jboolean,
+ CallStaticBooleanMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jboolean,
+ CallStaticByteMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jbyte,
+ CallStaticByteMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jbyte,
+ CallStaticByteMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jbyte,
+ CallStaticCharMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jchar,
+ CallStaticCharMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jchar,
+ CallStaticCharMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jchar,
+ CallStaticShortMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jshort,
+ CallStaticShortMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jshort,
+ CallStaticShortMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jshort,
+ CallStaticIntMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jint,
+ CallStaticIntMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jint,
+ CallStaticIntMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jint,
+ CallStaticLongMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jlong,
+ CallStaticLongMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jlong,
+ CallStaticLongMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jlong,
+ CallStaticFloatMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jfloat,
+ CallStaticFloatMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jfloat,
+ CallStaticFloatMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jfloat,
+ CallStaticDoubleMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any) -> jdouble,
+ CallStaticDoubleMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list) -> jdouble,
+ CallStaticDoubleMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue) -> jdouble,
+ CallStaticVoidMethod: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #c_vararg args: ..any),
+ CallStaticVoidMethodV: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, args: ^c.va_list),
+ CallStaticVoidMethodA: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methodID: jmethodID, #by_ptr args: jvalue),
+
+ GetStaticFieldID: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, name: cstring, sig: cstring) -> jfieldID,
+
+ GetStaticObjectField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jobject,
+ GetStaticBooleanField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jboolean,
+ GetStaticByteField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jbyte,
+ GetStaticCharField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jchar,
+ GetStaticShortField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jshort,
+ GetStaticIntField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jint,
+ GetStaticLongField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jlong,
+ GetStaticFloatField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jfloat,
+ GetStaticDoubleField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID) -> jdouble,
+
+ SetStaticObjectField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jobject),
+ SetStaticBooleanField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jboolean),
+ SetStaticByteField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jbyte),
+ SetStaticCharField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jchar),
+ SetStaticShortField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jshort),
+ SetStaticIntField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jint),
+ SetStaticLongField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jlong),
+ SetStaticFloatField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jfloat),
+ SetStaticDoubleField: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, fieldID: jfieldID, value: jdouble),
+
+ NewString: #type proc "c" (jni: ^^JNINativeInterface, unicodeChars: [^]jchar, len: jsize) -> jstring,
+ GetStringLength: #type proc "c" (jni: ^^JNINativeInterface, str: jstring) -> jsize,
+ GetStringChars: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, isCopy: ^jboolean) -> [^]jchar,
+ ReleaseStringChars: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, chars: [^]jchar),
+ NewStringUTF: #type proc "c" (jni: ^^JNINativeInterface, bytes: [^]c.char) -> jstring,
+ GetStringUTFLength: #type proc "c" (jni: ^^JNINativeInterface, str: jstring) -> jsize,
+ /* JNI spec says this returns const jbyte*, but that's inconsistent */
+ GetStringUTFChars: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, isCopy: ^jboolean) -> cstring,
+ ReleaseStringUTFChars: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, utf: cstring),
+ GetArrayLength: #type proc "c" (jni: ^^JNINativeInterface, array: jarray) -> jsize,
+ NewObjectArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize, elementClass: jclass, initialElement: jobject) -> jobjectArray,
+ GetObjectArrayElement: #type proc "c" (jni: ^^JNINativeInterface, array: jobjectArray, index: jsize) -> jobject,
+ SetObjectArrayElement: #type proc "c" (jni: ^^JNINativeInterface, array: jobjectArray, index: jsize, value: jobject),
+
+ NewBooleanArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jbooleanArray,
+ NewByteArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jbyteArray,
+ NewCharArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jcharArray,
+ NewShortArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jshortArray,
+ NewIntArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jintArray,
+ NewLongArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jlongArray,
+ NewFloatArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jfloatArray,
+ NewDoubleArray: #type proc "c" (jni: ^^JNINativeInterface, length: jsize) -> jdoubleArray,
+
+ GetBooleanArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jbooleanArray, isCopy: ^jboolean) -> [^]jboolean,
+ GetByteArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jbyteArray, isCopy: ^jboolean) -> [^]jbyte,
+ GetCharArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jcharArray, isCopy: ^jboolean) -> [^]jchar,
+ GetShortArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jshortArray, isCopy: ^jboolean) -> [^]jshort,
+ GetIntArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jintArray, isCopy: ^jboolean) -> [^]jint,
+ GetLongArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jlongArray, isCopy: ^jboolean) -> [^]jlong,
+ GetFloatArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jfloatArray, isCopy: ^jboolean) -> [^]jfloat,
+ GetDoubleArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jdoubleArray, isCopy: ^jboolean) -> [^]jdouble,
+
+ ReleaseBooleanArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jbooleanArray, elems: [^]jboolean, mode: jint),
+ ReleaseByteArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jbyteArray, elems: [^]jbyte, mode: jint),
+ ReleaseCharArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jcharArray, elems: [^]jchar, mode: jint),
+ ReleaseShortArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jshortArray, elems: [^]jshort, mode: jint),
+ ReleaseIntArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jintArray, elems: [^]jint, mode: jint),
+ ReleaseLongArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jlongArray, elems: [^]jlong, mode: jint),
+ ReleaseFloatArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jfloatArray, elems: [^]jfloat, mode: jint),
+ ReleaseDoubleArrayElements: #type proc "c" (jni: ^^JNINativeInterface, array: jdoubleArray, elems: [^]jdouble, mode: jint),
+
+ GetBooleanArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jbooleanArray, start: jsize, len: jsize, buf: [^]jboolean),
+ GetByteArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jbyteArray, start: jsize, len: jsize, buf: [^]jbyte),
+ GetCharArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jcharArray, start: jsize, len: jsize, buf: [^]jchar),
+ GetShortArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jshortArray, start: jsize, len: jsize, buf: [^]jshort),
+ GetIntArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jintArray, start: jsize, len: jsize, buf: [^]jint),
+ GetLongArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jlongArray, start: jsize, len: jsize, buf: [^]jlong),
+ GetFloatArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jfloatArray, start: jsize, len: jsize, buf: [^]jfloat),
+ GetDoubleArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jdoubleArray, start: jsize, len: jsize, buf: [^]jdouble),
+
+ /* spec shows these without const, some jni.h do, some don't */
+ SetBooleanArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jbooleanArray, start: jsize, len: jsize, buf: [^]jboolean),
+ SetByteArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jbyteArray, start: jsize, len: jsize, buf: [^]jbyte),
+ SetCharArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jcharArray, start: jsize, len: jsize, buf: [^]jchar),
+ SetShortArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jshortArray, start: jsize, len: jsize, buf: [^]jshort),
+ SetIntArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jintArray, start: jsize, len: jsize, buf: [^]jint),
+ SetLongArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jlongArray, start: jsize, len: jsize, buf: [^]jlong),
+ SetFloatArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jfloatArray, start: jsize, len: jsize, buf: [^]jfloat),
+ SetDoubleArrayRegion: #type proc "c" (jni: ^^JNINativeInterface, array: jdoubleArray, start: jsize, len: jsize, buf: [^]jdouble),
+
+ RegisterNatives: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass, methods: [^]JNINativeMethod, nMethods: jint) -> jint,
+ UnregisterNatives: #type proc "c" (jni: ^^JNINativeInterface, clazz: jclass) -> jint,
+ MonitorEnter: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject) -> jint,
+ MonitorExit: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject) -> jint,
+ GetJavaVM: #type proc "c" (jni: ^^JNINativeInterface, vm: ^^^JNIInvokeInterface) -> jint,
+
+ GetStringRegion: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, start: jsize, len: jsize, buf: [^]jchar),
+ GetStringUTFRegion: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, start: jsize, len: jsize, buf: [^]c.char),
+
+ GetPrimitiveArrayCritical: #type proc "c" (jni: ^^JNINativeInterface, array: jarray, isCopy: ^jboolean) -> rawptr,
+ ReleasePrimitiveArrayCritical: #type proc "c" (jni: ^^JNINativeInterface, array: jarray, carray: rawptr, mode: jint),
+
+ GetStringCritical: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, isCopy: ^jboolean) -> [^]jchar,
+ ReleaseStringCritical: #type proc "c" (jni: ^^JNINativeInterface, str: jstring, carray: [^]jchar),
+
+ NewWeakGlobalRef: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject) -> jweak,
+ DeleteWeakGlobalRef: #type proc "c" (jni: ^^JNINativeInterface, obj: jweak),
+
+ ExceptionCheck: #type proc "c" (jni: ^^JNINativeInterface),
+
+ NewDirectByteBuffer: #type proc "c" (jni: ^^JNINativeInterface, address: rawptr, capacity: jlong) -> jobject,
+ GetDirectBufferAddress: #type proc "c" (jni: ^^JNINativeInterface, buf: jobject) -> rawptr,
+ GetDirectBufferCapacity: #type proc "c" (jni: ^^JNINativeInterface, buf: jobject) -> jlong,
+
+ /* added in JNI 1.6 */
+ GetObjectRefType: #type proc "c" (jni: ^^JNINativeInterface, obj: jobject) -> jobjectRefType,
+}
+
+
+/*
+ * JNI invocation interface.
+ */
+JNIInvokeInterface :: struct {
+ reserved0: rawptr,
+ reserved1: rawptr,
+ reserved2: rawptr,
+
+ DestroyJavaVM: #type proc "c" (vm: ^^JNIInvokeInterface) -> jint,
+ AttachCurrentThread: #type proc "c" (vm: ^^JNIInvokeInterface, p_env: ^^JNIEnv, thr_args: rawptr) -> jint,
+ DetachCurrentThread: #type proc "c" (vm: ^^JNIInvokeInterface) -> jint,
+ GetEnv: #type proc "c" (vm: ^^JNIInvokeInterface, env: ^rawptr, version: jint) -> jint,
+ AttachCurrentThreadAsDaemon: #type proc "c" (vm: ^^JNIInvokeInterface, p_env: ^^JNIEnv, thr_args: ^rawptr) -> jint,
+}
diff --git a/log.odin b/log.odin
new file mode 100644
index 0000000..26e499d
--- /dev/null
+++ b/log.odin
@@ -0,0 +1,340 @@
+//+build android
+package android
+
+import "core:c"
+
+foreign import log "system:log"
+
+/**
+ * \file
+ *
+ * Support routines to send messages to the Android log buffer,
+ * which can later be accessed through the `logcat` utility.
+ *
+ * Each log message must have
+ * - a priority
+ * - a log tag
+ * - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (1023 bytes).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several
+ * messages and have them appear on a single line in logcat.
+ *
+ * Please use logging in moderation:
+ *
+ * - Sending log messages eats CPU and slow down your application and the
+ * system.
+ *
+ * - The circular log buffer is pretty small, so sending many messages
+ * will hide other important log messages.
+ *
+ * - In release builds, only send log messages to account for exceptional
+ * conditions.
+ */
+
+
+/**
+ * Android log priority values, in increasing order of priority.
+ */
+LogPriority :: enum i32 {
+ /** For internal use only. */
+ UNKNOWN = 0,
+ /** The default priority, for internal use only. */
+ DEFAULT, /* only for SetMinPriority() */
+ /** Verbose logging. Should typically be disabled for a release apk. */
+ VERBOSE,
+ /** Debug logging. Should typically be disabled for a release apk. */
+ DEBUG,
+ /** Informational logging. Should typically be disabled for a release apk. */
+ INFO,
+ /** Warning logging. For use with recoverable failures. */
+ WARN,
+ /** Error logging. For use with unrecoverable failures. */
+ ERROR,
+ /** Fatal logging. For use when aborting. */
+ FATAL,
+ /** For internal use only. */
+ SILENT, /* only for SetMinPriority(); must be last */
+}
+
+/**
+ * Identifies a specific log buffer for __android_log_buf_write()
+ * and __android_log_buf_print().
+ */
+LogId :: enum i32 {
+ MIN = 0,
+
+ /** The main log buffer. This is the only log buffer available to apps. */
+ MAIN = 0,
+ /** The radio log buffer. */
+ RADIO = 1,
+ /** The event log buffer. */
+ EVENTS = 2,
+ /** The system log buffer. */
+ SYSTEM = 3,
+ /** The crash log buffer. */
+ CRASH = 4,
+ /** The statistics log buffer. */
+ STATS = 5,
+ /** The security log buffer. */
+ SECURITY = 6,
+ /** The kernel log buffer. */
+ KERNEL = 7,
+
+ MAX,
+
+ /** Let the logging function choose the best log target. */
+ DEFAULT = 0x7FFFFFFF
+}
+
+/**
+ * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
+ * and sending log messages to user defined loggers specified in __android_log_set_logger().
+ */
+LogMessage :: struct {
+ /** Must be set to sizeof(LogMessage) and is used for versioning. */
+ struct_size: uint,
+
+ /** {@link log_id_t} values. */
+ buffer_id: i32,
+
+ /** {@link android_LogPriority} values. */
+ priority: i32,
+
+ /** The tag for the log message. */
+ tag: cstring,
+
+ /** Optional file name, may be set to nullptr. */
+ file: cstring,
+
+ /** Optional line number, ignore if file is nullptr. */
+ line: u32,
+
+ /** The log message itself. */
+ message: cstring,
+}
+
+/**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+__android_logger_function :: #type proc "c" (log_message: ^LogMessage)
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+__android_aborter_function :: #type proc "c" (abort_message: cstring)
+
+foreign log {
+ /**
+ * Writes the constant string `text` to the log, with priority `prio` and tag
+ * `tag`.
+ */
+ __android_log_write :: proc(prio: LogPriority, tag: cstring, text: cstring) -> i32 ---
+
+ /**
+ * Writes a formatted string to the log, with priority `prio` and tag `tag`.
+ * The details of formatting are the same as for
+ * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
+ */
+ __android_log_print :: proc(prio: LogPriority, tag: cstring, fmt: cstring, #c_vararg args: ..any) -> i32 ---
+
+ /**
+ * Equivalent to `__android_log_print`, but taking a `va_list`.
+ * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
+ */
+ __android_log_vprint :: proc(prio: LogPriority, tag: cstring, fmt: cstring, ap: c.va_list) -> i32 ---
+
+ /**
+ * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
+ * stderr, before calling
+ * [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
+ *
+ * If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
+ * `Assertion failed: %s` is used with `cond` as the string argument.
+ * If both `fmt` and `cond` are null, a default string is provided.
+ *
+ * Most callers should use
+ * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
+ * `<assert.h>` instead, or the `__assert` and `__assert2` functions
+ * provided by bionic if more control is needed. They support automatically
+ * including the source filename and line number more conveniently than this
+ * function.
+ */
+ __android_log_assert :: proc(cond: cstring, tag: cstring, fmt: cstring, #c_vararg args: ..any) ---
+
+ /**
+ * Writes the constant string `text` to the log buffer `id`,
+ * with priority `prio` and tag `tag`.
+ *
+ * Apps should use __android_log_write() instead.
+ */
+ __android_log_buf_write :: proc(bufID: LogId, prio: LogPriority, tag: cstring, text: cstring) -> i32 ---
+
+ /**
+ * Writes a formatted string to log buffer `id`,
+ * with priority `prio` and tag `tag`.
+ * The details of formatting are the same as for
+ * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
+ *
+ * Apps should use __android_log_print() instead.
+ */
+ __android_log_buf_print :: proc(bufID: LogId, prio: LogPriority, tag: cstring, fmt: cstring, #c_vararg args: ..any) -> i32 ---
+
+ /**
+ * Writes the log message specified by log_message. log_message includes additional file name and
+ * line number information that a logger may use. log_message is versioned for backwards
+ * compatibility.
+ * This assumes that loggability has already been checked through __android_log_is_loggable().
+ * Higher level logging libraries, such as libbase, first check loggability, then format their
+ * buffers, then pass the message to liblog via this function, and therefore we do not want to
+ * duplicate the loggability check here.
+ *
+ * @param log_message the log message itself, see __android_log_message.
+ *
+ * Available since API level 30.
+ */
+ __android_log_write_log_message :: proc(log_message: ^LogMessage) ---
+
+ /**
+ * Sets a user defined logger function. All log messages sent to liblog will be set to the
+ * function pointer specified by logger for processing. It is not expected that log messages are
+ * already terminated with a new line. This function should add new lines if required for line
+ * separation.
+ *
+ * @param logger the new function that will handle log messages.
+ *
+ * Available since API level 30.
+ */
+ __android_log_set_logger :: proc(logger: __android_logger_function) ---
+
+ /**
+ * Writes the log message to logd. This is an __android_logger_function and can be provided to
+ * __android_log_set_logger(). It is the default logger when running liblog on a device.
+ *
+ * @param log_message the log message to write, see __android_log_message.
+ *
+ * Available since API level 30.
+ */
+ __android_log_logd_logger :: proc(log_message: ^LogMessage) ---
+
+ /**
+ * Writes the log message to stderr. This is an __android_logger_function and can be provided to
+ * __android_log_set_logger(). It is the default logger when running liblog on host.
+ *
+ * @param log_message the log message to write, see __android_log_message.
+ *
+ * Available since API level 30.
+ */
+ __android_log_stderr_logger :: proc(log_message: ^LogMessage) ---
+
+ /**
+ * Sets a user defined aborter function that is called for __android_log_assert() failures. This
+ * user defined aborter function is highly recommended to abort and be noreturn, but is not strictly
+ * required to.
+ *
+ * @param aborter the new aborter function, see __android_aborter_function.
+ *
+ * Available since API level 30.
+ */
+ __android_log_set_aborter :: proc(aborter: __android_aborter_function) ---
+
+ /**
+ * Calls the stored aborter function. This allows for other logging libraries to use the same
+ * aborter function by calling this function in liblog.
+ *
+ * @param abort_message an additional message supplied when aborting, for example this is used to
+ * call android_set_abort_message() in __android_log_default_aborter().
+ *
+ * Available since API level 30.
+ */
+ __android_log_call_aborter :: proc(abort_message: cstring) ---
+
+ /**
+ * Sets android_set_abort_message() on device then aborts(). This is the default aborter.
+ *
+ * @param abort_message an additional message supplied when aborting. This functions calls
+ * android_set_abort_message() with its contents.
+ *
+ * Available since API level 30.
+ */
+ __android_log_default_aborter :: proc(abort_message: cstring) ---
+
+ /**
+ * Use the per-tag properties "log.tag.