diff --git a/android-activity/CHANGELOG.md b/android-activity/CHANGELOG.md index 373ad87e..16bf4f5f 100644 --- a/android-activity/CHANGELOG.md +++ b/android-activity/CHANGELOG.md @@ -53,7 +53,31 @@ fn android_on_create(state: &OnCreateState) { ### Changed - rust-version bumped to 1.85.0 ([#193](https://github.com/rust-mobile/android-activity/pull/193), [#219](https://github.com/rust-mobile/android-activity/pull/219)) -- GameActivity updated to 4.0.0 (requires the corresponding 4.0.0 `.aar` release from Google) ([#191](https://github.com/rust-mobile/android-activity/pull/191)) +- GameActivity updated to 4.4.0 ([#191](https://github.com/rust-mobile/android-activity/pull/191), [#240](https://github.com/rust-mobile/android-activity/pull/240)) + +**Important:** This release is no longer compatible with GameActivity 2.0.2 + +**Android Packaging:** Your Android application must be packaged with the corresponding androidX, GameActivity 4.x.x library from Google. + +This release has been tested with the [`androidx.games:games-activity:4.4.0` stable +release](https://developer.android.com/jetpack/androidx/releases/games#games-activity-4.4.0), and is backwards +compatible with the 4.0.0 stable release. + +If you use Gradle to build your Android application, you can depend on the 4.4.0 release of the GameActivity library via: + +```gradle +dependencies { + implementation 'androidx.appcompat:appcompat:1.7.1' + + // To use the Games Activity library + implementation "androidx.games:games-activity:4.4.0" + // Note: don't include game-text-input separately, since it's integrated into game-activity +} +``` + +Note: there is no guarantee that later 4.x.x releases of GameActivity will be compatible with this release of +`android-activity`, so please refer to the `android-activity` release notes for any future updates regarding +GameActivity compatibility. ### Fixed diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h index 42f450a1..aafe4fe0 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h @@ -43,30 +43,30 @@ extern "C" { #endif +#define GAMEACTIVITY_VERSION_REVISION a0e943c3a84fd7f344c3d36cdf4e88fd595f81b8 #define GAMEACTIVITY_MAJOR_VERSION 4 -#define GAMEACTIVITY_MINOR_VERSION 0 +#define GAMEACTIVITY_MINOR_VERSION 4 #define GAMEACTIVITY_BUGFIX_VERSION 0 -#define GAMEACTIVITY_PACKED_VERSION \ - ANDROID_GAMESDK_PACKED_VERSION(GAMEACTIVITY_MAJOR_VERSION, \ - GAMEACTIVITY_MINOR_VERSION, \ - GAMEACTIVITY_BUGFIX_VERSION) +#define GAMEACTIVITY_PACKED_VERSION \ + ANDROID_GAMESDK_PACKED_VERSION(GAMEACTIVITY_MAJOR_VERSION, GAMEACTIVITY_MINOR_VERSION, \ + GAMEACTIVITY_BUGFIX_VERSION) /** * The type of a component for which to retrieve insets. See * https://developer.android.com/reference/androidx/core/view/WindowInsetsCompat.Type */ typedef enum GameCommonInsetsType : uint8_t { - GAMECOMMON_INSETS_TYPE_CAPTION_BAR = 0, - GAMECOMMON_INSETS_TYPE_DISPLAY_CUTOUT, - GAMECOMMON_INSETS_TYPE_IME, - GAMECOMMON_INSETS_TYPE_MANDATORY_SYSTEM_GESTURES, - GAMECOMMON_INSETS_TYPE_NAVIGATION_BARS, - GAMECOMMON_INSETS_TYPE_STATUS_BARS, - GAMECOMMON_INSETS_TYPE_SYSTEM_BARS, - GAMECOMMON_INSETS_TYPE_SYSTEM_GESTURES, - GAMECOMMON_INSETS_TYPE_TAPABLE_ELEMENT, - GAMECOMMON_INSETS_TYPE_WATERFALL, - GAMECOMMON_INSETS_TYPE_COUNT + GAMECOMMON_INSETS_TYPE_CAPTION_BAR = 0, + GAMECOMMON_INSETS_TYPE_DISPLAY_CUTOUT, + GAMECOMMON_INSETS_TYPE_IME, + GAMECOMMON_INSETS_TYPE_MANDATORY_SYSTEM_GESTURES, + GAMECOMMON_INSETS_TYPE_NAVIGATION_BARS, + GAMECOMMON_INSETS_TYPE_STATUS_BARS, + GAMECOMMON_INSETS_TYPE_SYSTEM_BARS, + GAMECOMMON_INSETS_TYPE_SYSTEM_GESTURES, + GAMECOMMON_INSETS_TYPE_TAPABLE_ELEMENT, + GAMECOMMON_INSETS_TYPE_WATERFALL, + GAMECOMMON_INSETS_TYPE_COUNT } GameCommonInsetsType; /** @@ -80,74 +80,73 @@ struct GameActivityCallbacks; * code as it is being launched. */ typedef struct GameActivity { - /** - * Pointer to the callback function table of the native application. - * You can set the functions here to your own callbacks. The callbacks - * pointer itself here should not be changed; it is allocated and managed - * for you by the framework. - */ - struct GameActivityCallbacks* callbacks; - - /** - * The global handle on the process's Java VM. - */ - JavaVM* vm; - - /** - * JNI context for the main thread of the app. Note that this field - * can ONLY be used from the main thread of the process; that is, the - * thread that calls into the GameActivityCallbacks. - */ - JNIEnv* env; - - /** - * The GameActivity object handle. - */ - jobject javaGameActivity; - - /** - * Path to this application's internal data directory. - */ - const char* internalDataPath; - - /** - * Path to this application's external (removable/mountable) data directory. - */ - const char* externalDataPath; - - /** - * The platform's SDK version code. - */ - int32_t sdkVersion; - - /** - * This is the native instance of the application. It is not used by - * the framework, but can be set by the application to its own instance - * state. - */ - void* instance; - - /** - * Pointer to the Asset Manager instance for the application. The - * application uses this to access binary assets bundled inside its own .apk - * file. - */ - AAssetManager* assetManager; - - /** - * Available starting with Honeycomb: path to the directory containing - * the application's OBB files (if any). If the app doesn't have any - * OBB files, this directory may not exist. - */ - const char* obbPath; + /** + * Pointer to the callback function table of the native application. + * You can set the functions here to your own callbacks. The callbacks + * pointer itself here should not be changed; it is allocated and managed + * for you by the framework. + */ + struct GameActivityCallbacks* callbacks; + + /** + * The global handle on the process's Java VM. + */ + JavaVM* vm; + + /** + * JNI context for the main thread of the app. Note that this field + * can ONLY be used from the main thread of the process; that is, the + * thread that calls into the GameActivityCallbacks. + */ + JNIEnv* env; + + /** + * The GameActivity object handle. + */ + jobject javaGameActivity; + + /** + * Path to this application's internal data directory. + */ + const char* internalDataPath; + + /** + * Path to this application's external (removable/mountable) data directory. + */ + const char* externalDataPath; + + /** + * The platform's SDK version code. + */ + int32_t sdkVersion; + + /** + * This is the native instance of the application. It is not used by + * the framework, but can be set by the application to its own instance + * state. + */ + void* instance; + + /** + * Pointer to the Asset Manager instance for the application. The + * application uses this to access binary assets bundled inside its own .apk + * file. + */ + AAssetManager* assetManager; + + /** + * Available starting with Honeycomb: path to the directory containing + * the application's OBB files (if any). If the app doesn't have any + * OBB files, this directory may not exist. + */ + const char* obbPath; } GameActivity; /** * A function the user should call from their callback with the data, its length * and the library- supplied context. */ -typedef void (*SaveInstanceStateRecallback)(const char* bytes, int len, - void* context); +typedef void (*SaveInstanceStateRecallback)(const char* bytes, int len, void* context); /** * These are the callbacks the framework makes into a native application. @@ -156,153 +155,147 @@ typedef void (*SaveInstanceStateRecallback)(const char* bytes, int len, * to have it called. */ typedef struct GameActivityCallbacks { - /** - * GameActivity has started. See Java documentation for Activity.onStart() - * for more information. - */ - void (*onStart)(GameActivity* activity); - - /** - * GameActivity has resumed. See Java documentation for Activity.onResume() - * for more information. - */ - void (*onResume)(GameActivity* activity); - - /** - * The framework is asking GameActivity to save its current instance state. - * See the Java documentation for Activity.onSaveInstanceState() for more - * information. The user should call the recallback with their data, its - * length and the provided context; they retain ownership of the data. Note - * that the saved state will be persisted, so it can not contain any active - * entities (pointers to memory, file descriptors, etc). - */ - void (*onSaveInstanceState)(GameActivity* activity, - SaveInstanceStateRecallback recallback, - void* context); - - /** - * GameActivity has paused. See Java documentation for Activity.onPause() - * for more information. - */ - void (*onPause)(GameActivity* activity); - - /** - * GameActivity has stopped. See Java documentation for Activity.onStop() - * for more information. - */ - void (*onStop)(GameActivity* activity); - - /** - * GameActivity is being destroyed. See Java documentation for - * Activity.onDestroy() for more information. - */ - void (*onDestroy)(GameActivity* activity); - - /** - * Focus has changed in this GameActivity's window. This is often used, - * for example, to pause a game when it loses input focus. - */ - void (*onWindowFocusChanged)(GameActivity* activity, bool hasFocus); - - /** - * The drawing window for this native activity has been created. You - * can use the given native window object to start drawing. - */ - void (*onNativeWindowCreated)(GameActivity* activity, ANativeWindow* window); - - /** - * The drawing window for this native activity has been resized. You should - * retrieve the new size from the window and ensure that your rendering in - * it now matches. - */ - void (*onNativeWindowResized)(GameActivity* activity, ANativeWindow* window, - int32_t newWidth, int32_t newHeight); - - /** - * The drawing window for this native activity needs to be redrawn. To - * avoid transient artifacts during screen changes (such resizing after - * rotation), applications should not return from this function until they - * have finished drawing their window in its current state. - */ - void (*onNativeWindowRedrawNeeded)(GameActivity* activity, - ANativeWindow* window); - - /** - * The drawing window for this native activity is going to be destroyed. - * You MUST ensure that you do not touch the window object after returning - * from this function: in the common case of drawing to the window from - * another thread, that means the implementation of this callback must - * properly synchronize with the other thread to stop its drawing before - * returning from here. - */ - void (*onNativeWindowDestroyed)(GameActivity* activity, - ANativeWindow* window); - - /** - * The current device AConfiguration has changed. The new configuration can - * be retrieved from assetManager. - */ - void (*onConfigurationChanged)(GameActivity* activity); - - /** - * The system is running low on memory. Use this callback to release - * resources you do not need, to help the system avoid killing more - * important processes. - */ - void (*onTrimMemory)(GameActivity* activity, int level); - - /** - * Callback called for every MotionEvent done on the GameActivity - * SurfaceView. Ownership of `event` is maintained by the library and it is - * only valid during the callback. - */ - bool (*onTouchEvent)(GameActivity* activity, - const GameActivityMotionEvent* event); - - /** - * Callback called for every key down event on the GameActivity SurfaceView. - * Ownership of `event` is maintained by the library and it is only valid - * during the callback. - */ - bool (*onKeyDown)(GameActivity* activity, const GameActivityKeyEvent* event); - - /** - * Callback called for every key up event on the GameActivity SurfaceView. - * Ownership of `event` is maintained by the library and it is only valid - * during the callback. - */ - bool (*onKeyUp)(GameActivity* activity, const GameActivityKeyEvent* event); - - /** - * Callback called for every soft-keyboard text input event. - * Ownership of `state` is maintained by the library and it is only valid - * during the callback. - */ - void (*onTextInputEvent)(GameActivity* activity, - const GameTextInputState* state); - - /** - * Callback called when WindowInsets of the main app window have changed. - * Call GameActivity_getWindowInsets to retrieve the insets themselves. - */ - void (*onWindowInsetsChanged)(GameActivity* activity); - - /** - * Callback called when the rectangle in the window where the content - * should be placed has changed. - */ - void (*onContentRectChanged)(GameActivity* activity, const ARect* rect); - - /** - * Callback called when the software keyboard is shown or hidden. - */ - void (*onSoftwareKeyboardVisibilityChanged)(GameActivity* activity, - bool visible); - - /** - * Callback called when the software keyboard is shown or hidden. - */ - bool (*onEditorAction)(GameActivity* activity, int action); + /** + * GameActivity has started. See Java documentation for Activity.onStart() + * for more information. + */ + void (*onStart)(GameActivity* activity); + + /** + * GameActivity has resumed. See Java documentation for Activity.onResume() + * for more information. + */ + void (*onResume)(GameActivity* activity); + + /** + * The framework is asking GameActivity to save its current instance state. + * See the Java documentation for Activity.onSaveInstanceState() for more + * information. The user should call the recallback with their data, its + * length and the provided context; they retain ownership of the data. Note + * that the saved state will be persisted, so it can not contain any active + * entities (pointers to memory, file descriptors, etc). + */ + void (*onSaveInstanceState)(GameActivity* activity, SaveInstanceStateRecallback recallback, + void* context); + + /** + * GameActivity has paused. See Java documentation for Activity.onPause() + * for more information. + */ + void (*onPause)(GameActivity* activity); + + /** + * GameActivity has stopped. See Java documentation for Activity.onStop() + * for more information. + */ + void (*onStop)(GameActivity* activity); + + /** + * GameActivity is being destroyed. See Java documentation for + * Activity.onDestroy() for more information. + */ + void (*onDestroy)(GameActivity* activity); + + /** + * Focus has changed in this GameActivity's window. This is often used, + * for example, to pause a game when it loses input focus. + */ + void (*onWindowFocusChanged)(GameActivity* activity, bool hasFocus); + + /** + * The drawing window for this native activity has been created. You + * can use the given native window object to start drawing. + */ + void (*onNativeWindowCreated)(GameActivity* activity, ANativeWindow* window); + + /** + * The drawing window for this native activity has been resized. You should + * retrieve the new size from the window and ensure that your rendering in + * it now matches. + */ + void (*onNativeWindowResized)(GameActivity* activity, ANativeWindow* window, int32_t newWidth, + int32_t newHeight); + + /** + * The drawing window for this native activity needs to be redrawn. To + * avoid transient artifacts during screen changes (such resizing after + * rotation), applications should not return from this function until they + * have finished drawing their window in its current state. + */ + void (*onNativeWindowRedrawNeeded)(GameActivity* activity, ANativeWindow* window); + + /** + * The drawing window for this native activity is going to be destroyed. + * You MUST ensure that you do not touch the window object after returning + * from this function: in the common case of drawing to the window from + * another thread, that means the implementation of this callback must + * properly synchronize with the other thread to stop its drawing before + * returning from here. + */ + void (*onNativeWindowDestroyed)(GameActivity* activity, ANativeWindow* window); + + /** + * The current device AConfiguration has changed. The new configuration can + * be retrieved from assetManager. + */ + void (*onConfigurationChanged)(GameActivity* activity); + + /** + * The system is running low on memory. Use this callback to release + * resources you do not need, to help the system avoid killing more + * important processes. + */ + void (*onTrimMemory)(GameActivity* activity, int level); + + /** + * Callback called for every MotionEvent done on the GameActivity + * SurfaceView. Ownership of `event` is maintained by the library and it is + * only valid during the callback. + */ + bool (*onTouchEvent)(GameActivity* activity, const GameActivityMotionEvent* event); + + /** + * Callback called for every key down event on the GameActivity SurfaceView. + * Ownership of `event` is maintained by the library and it is only valid + * during the callback. + */ + bool (*onKeyDown)(GameActivity* activity, const GameActivityKeyEvent* event); + + /** + * Callback called for every key up event on the GameActivity SurfaceView. + * Ownership of `event` is maintained by the library and it is only valid + * during the callback. + */ + bool (*onKeyUp)(GameActivity* activity, const GameActivityKeyEvent* event); + + /** + * Callback called for every soft-keyboard text input event. + * Ownership of `state` is maintained by the library and it is only valid + * during the callback. + */ + void (*onTextInputEvent)(GameActivity* activity, const GameTextInputState* state); + + /** + * Callback called when WindowInsets of the main app window have changed. + * Call GameActivity_getWindowInsets to retrieve the insets themselves. + */ + void (*onWindowInsetsChanged)(GameActivity* activity); + + /** + * Callback called when the rectangle in the window where the content + * should be placed has changed. + */ + void (*onContentRectChanged)(GameActivity* activity, const ARect* rect); + + /** + * Callback called when the software keyboard is shown or hidden. + */ + void (*onSoftwareKeyboardVisibilityChanged)(GameActivity* activity, bool visible); + + /** + * Callback called when the software keyboard is shown or hidden. + */ + bool (*onEditorAction)(GameActivity* activity, int action); } GameActivityCallbacks; /** @@ -337,186 +330,186 @@ void GameActivity_finish(GameActivity* activity); * as per the Java API at android.view.WindowManager.LayoutParams. */ enum GameActivitySetWindowFlags : uint32_t { - /** - * As long as this window is visible to the user, allow the lock - * screen to activate while the screen is on. This can be used - * independently, or in combination with {@link - * GAMEACTIVITY_FLAG_KEEP_SCREEN_ON} and/or {@link - * GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED} - */ - GAMEACTIVITY_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - /** Everything behind this window will be dimmed. */ - GAMEACTIVITY_FLAG_DIM_BEHIND = 0x00000002, - /** - * Blur everything behind this window. - * @deprecated Blurring is no longer supported. - */ - GAMEACTIVITY_FLAG_BLUR_BEHIND = 0x00000004, - /** - * This window won't ever get key input focus, so the - * user can not send key or other button events to it. Those will - * instead go to whatever focusable window is behind it. This flag - * will also enable {@link GAMEACTIVITY_FLAG_NOT_TOUCH_MODAL} whether or not - * that is explicitly set. - * - * Setting this flag also implies that the window will not need to - * interact with - * a soft input method, so it will be Z-ordered and positioned - * independently of any active input method (typically this means it - * gets Z-ordered on top of the input method, so it can use the full - * screen for its content and cover the input method if needed. You - * can use {@link GAMEACTIVITY_FLAG_ALT_FOCUSABLE_IM} to modify this - * behavior. - */ - GAMEACTIVITY_FLAG_NOT_FOCUSABLE = 0x00000008, - /** This window can never receive touch events. */ - GAMEACTIVITY_FLAG_NOT_TOUCHABLE = 0x00000010, - /** - * Even when this window is focusable (its - * {@link GAMEACTIVITY_FLAG_NOT_FOCUSABLE} is not set), allow any pointer - * events outside of the window to be sent to the windows behind it. - * Otherwise it will consume all pointer events itself, regardless of - * whether they are inside of the window. - */ - GAMEACTIVITY_FLAG_NOT_TOUCH_MODAL = 0x00000020, - /** - * When set, if the device is asleep when the touch - * screen is pressed, you will receive this first touch event. Usually - * the first touch event is consumed by the system since the user can - * not see what they are pressing on. - * - * @deprecated This flag has no effect. - */ - GAMEACTIVITY_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, - /** - * As long as this window is visible to the user, keep - * the device's screen turned on and bright. - */ - GAMEACTIVITY_FLAG_KEEP_SCREEN_ON = 0x00000080, - /** - * Place the window within the entire screen, ignoring - * decorations around the border (such as the status bar). The - * window must correctly position its contents to take the screen - * decoration into account. - */ - GAMEACTIVITY_FLAG_LAYOUT_IN_SCREEN = 0x00000100, - /** Allows the window to extend outside of the screen. */ - GAMEACTIVITY_FLAG_LAYOUT_NO_LIMITS = 0x00000200, - /** - * Hide all screen decorations (such as the status - * bar) while this window is displayed. This allows the window to - * use the entire display space for itself -- the status bar will - * be hidden when an app window with this flag set is on the top - * layer. A fullscreen window will ignore a value of {@link - * GAMEACTIVITY_SOFT_INPUT_ADJUST_RESIZE}; the window will stay - * fullscreen and will not resize. - */ - GAMEACTIVITY_FLAG_FULLSCREEN = 0x00000400, - /** - * Override {@link GAMEACTIVITY_FLAG_FULLSCREEN} and force the - * screen decorations (such as the status bar) to be shown. - */ - GAMEACTIVITY_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, - /** - * Turn on dithering when compositing this window to - * the screen. - * @deprecated This flag is no longer used. - */ - GAMEACTIVITY_FLAG_DITHER = 0x00001000, - /** - * Treat the content of the window as secure, preventing - * it from appearing in screenshots or from being viewed on non-secure - * displays. - */ - GAMEACTIVITY_FLAG_SECURE = 0x00002000, - /** - * A special mode where the layout parameters are used - * to perform scaling of the surface when it is composited to the - * screen. - */ - GAMEACTIVITY_FLAG_SCALED = 0x00004000, - /** - * Intended for windows that will often be used when the user is - * holding the screen against their face, it will aggressively - * filter the event stream to prevent unintended presses in this - * situation that may not be desired for a particular window, when - * such an event stream is detected, the application will receive - * a {@link AMOTION_EVENT_ACTION_CANCEL} to indicate this so - * applications can handle this accordingly by taking no action on - * the event until the finger is released. - */ - GAMEACTIVITY_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, - /** - * A special option only for use in combination with - * {@link GAMEACTIVITY_FLAG_LAYOUT_IN_SCREEN}. When requesting layout in - * the screen your window may appear on top of or behind screen decorations - * such as the status bar. By also including this flag, the window - * manager will report the inset rectangle needed to ensure your - * content is not covered by screen decorations. - */ - GAMEACTIVITY_FLAG_LAYOUT_INSET_DECOR = 0x00010000, - /** - * Invert the state of {@link GAMEACTIVITY_FLAG_NOT_FOCUSABLE} with - * respect to how this window interacts with the current method. - * That is, if FLAG_NOT_FOCUSABLE is set and this flag is set, - * then the window will behave as if it needs to interact with the - * input method and thus be placed behind/away from it; if {@link - * GAMEACTIVITY_FLAG_NOT_FOCUSABLE} is not set and this flag is set, - * then the window will behave as if it doesn't need to interact - * with the input method and can be placed to use more space and - * cover the input method. - */ - GAMEACTIVITY_FLAG_ALT_FOCUSABLE_IM = 0x00020000, - /** - * If you have set {@link GAMEACTIVITY_FLAG_NOT_TOUCH_MODAL}, you - * can set this flag to receive a single special MotionEvent with - * the action - * {@link AMOTION_EVENT_ACTION_OUTSIDE} for - * touches that occur outside of your window. Note that you will not - * receive the full down/move/up gesture, only the location of the - * first down as an {@link AMOTION_EVENT_ACTION_OUTSIDE}. - */ - GAMEACTIVITY_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, - /** - * Special flag to let windows be shown when the screen - * is locked. This will let application windows take precedence over - * key guard or any other lock screens. Can be used with - * {@link GAMEACTIVITY_FLAG_KEEP_SCREEN_ON} to turn screen on and display - * windows directly before showing the key guard window. Can be used with - * {@link GAMEACTIVITY_FLAG_DISMISS_KEYGUARD} to automatically fully - * dismisss non-secure keyguards. This flag only applies to the top-most - * full-screen window. - */ - GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED = 0x00080000, - /** - * Ask that the system wallpaper be shown behind - * your window. The window surface must be translucent to be able - * to actually see the wallpaper behind it; this flag just ensures - * that the wallpaper surface will be there if this window actually - * has translucent regions. - */ - GAMEACTIVITY_FLAG_SHOW_WALLPAPER = 0x00100000, - /** - * When set as a window is being added or made - * visible, once the window has been shown then the system will - * poke the power manager's user activity (as if the user had woken - * up the device) to turn the screen on. - */ - GAMEACTIVITY_FLAG_TURN_SCREEN_ON = 0x00200000, - /** - * When set the window will cause the keyguard to - * be dismissed, only if it is not a secure lock keyguard. Because such - * a keyguard is not needed for security, it will never re-appear if - * the user navigates to another window (in contrast to - * {@link GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED}, which will only temporarily - * hide both secure and non-secure keyguards but ensure they reappear - * when the user moves to another UI that doesn't hide them). - * If the keyguard is currently active and is secure (requires an - * unlock pattern) than the user will still need to confirm it before - * seeing this window, unless {@link GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED} has - * also been set. - */ - GAMEACTIVITY_FLAG_DISMISS_KEYGUARD = 0x00400000, + /** + * As long as this window is visible to the user, allow the lock + * screen to activate while the screen is on. This can be used + * independently, or in combination with {@link + * GAMEACTIVITY_FLAG_KEEP_SCREEN_ON} and/or {@link + * GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED} + */ + GAMEACTIVITY_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + /** Everything behind this window will be dimmed. */ + GAMEACTIVITY_FLAG_DIM_BEHIND = 0x00000002, + /** + * Blur everything behind this window. + * @deprecated Blurring is no longer supported. + */ + GAMEACTIVITY_FLAG_BLUR_BEHIND = 0x00000004, + /** + * This window won't ever get key input focus, so the + * user can not send key or other button events to it. Those will + * instead go to whatever focusable window is behind it. This flag + * will also enable {@link GAMEACTIVITY_FLAG_NOT_TOUCH_MODAL} whether or not + * that is explicitly set. + * + * Setting this flag also implies that the window will not need to + * interact with + * a soft input method, so it will be Z-ordered and positioned + * independently of any active input method (typically this means it + * gets Z-ordered on top of the input method, so it can use the full + * screen for its content and cover the input method if needed. You + * can use {@link GAMEACTIVITY_FLAG_ALT_FOCUSABLE_IM} to modify this + * behavior. + */ + GAMEACTIVITY_FLAG_NOT_FOCUSABLE = 0x00000008, + /** This window can never receive touch events. */ + GAMEACTIVITY_FLAG_NOT_TOUCHABLE = 0x00000010, + /** + * Even when this window is focusable (its + * {@link GAMEACTIVITY_FLAG_NOT_FOCUSABLE} is not set), allow any pointer + * events outside of the window to be sent to the windows behind it. + * Otherwise it will consume all pointer events itself, regardless of + * whether they are inside of the window. + */ + GAMEACTIVITY_FLAG_NOT_TOUCH_MODAL = 0x00000020, + /** + * When set, if the device is asleep when the touch + * screen is pressed, you will receive this first touch event. Usually + * the first touch event is consumed by the system since the user can + * not see what they are pressing on. + * + * @deprecated This flag has no effect. + */ + GAMEACTIVITY_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + /** + * As long as this window is visible to the user, keep + * the device's screen turned on and bright. + */ + GAMEACTIVITY_FLAG_KEEP_SCREEN_ON = 0x00000080, + /** + * Place the window within the entire screen, ignoring + * decorations around the border (such as the status bar). The + * window must correctly position its contents to take the screen + * decoration into account. + */ + GAMEACTIVITY_FLAG_LAYOUT_IN_SCREEN = 0x00000100, + /** Allows the window to extend outside of the screen. */ + GAMEACTIVITY_FLAG_LAYOUT_NO_LIMITS = 0x00000200, + /** + * Hide all screen decorations (such as the status + * bar) while this window is displayed. This allows the window to + * use the entire display space for itself -- the status bar will + * be hidden when an app window with this flag set is on the top + * layer. A fullscreen window will ignore a value of {@link + * GAMEACTIVITY_SOFT_INPUT_ADJUST_RESIZE}; the window will stay + * fullscreen and will not resize. + */ + GAMEACTIVITY_FLAG_FULLSCREEN = 0x00000400, + /** + * Override {@link GAMEACTIVITY_FLAG_FULLSCREEN} and force the + * screen decorations (such as the status bar) to be shown. + */ + GAMEACTIVITY_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + /** + * Turn on dithering when compositing this window to + * the screen. + * @deprecated This flag is no longer used. + */ + GAMEACTIVITY_FLAG_DITHER = 0x00001000, + /** + * Treat the content of the window as secure, preventing + * it from appearing in screenshots or from being viewed on non-secure + * displays. + */ + GAMEACTIVITY_FLAG_SECURE = 0x00002000, + /** + * A special mode where the layout parameters are used + * to perform scaling of the surface when it is composited to the + * screen. + */ + GAMEACTIVITY_FLAG_SCALED = 0x00004000, + /** + * Intended for windows that will often be used when the user is + * holding the screen against their face, it will aggressively + * filter the event stream to prevent unintended presses in this + * situation that may not be desired for a particular window, when + * such an event stream is detected, the application will receive + * a {@link AMOTION_EVENT_ACTION_CANCEL} to indicate this so + * applications can handle this accordingly by taking no action on + * the event until the finger is released. + */ + GAMEACTIVITY_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + /** + * A special option only for use in combination with + * {@link GAMEACTIVITY_FLAG_LAYOUT_IN_SCREEN}. When requesting layout in + * the screen your window may appear on top of or behind screen decorations + * such as the status bar. By also including this flag, the window + * manager will report the inset rectangle needed to ensure your + * content is not covered by screen decorations. + */ + GAMEACTIVITY_FLAG_LAYOUT_INSET_DECOR = 0x00010000, + /** + * Invert the state of {@link GAMEACTIVITY_FLAG_NOT_FOCUSABLE} with + * respect to how this window interacts with the current method. + * That is, if FLAG_NOT_FOCUSABLE is set and this flag is set, + * then the window will behave as if it needs to interact with the + * input method and thus be placed behind/away from it; if {@link + * GAMEACTIVITY_FLAG_NOT_FOCUSABLE} is not set and this flag is set, + * then the window will behave as if it doesn't need to interact + * with the input method and can be placed to use more space and + * cover the input method. + */ + GAMEACTIVITY_FLAG_ALT_FOCUSABLE_IM = 0x00020000, + /** + * If you have set {@link GAMEACTIVITY_FLAG_NOT_TOUCH_MODAL}, you + * can set this flag to receive a single special MotionEvent with + * the action + * {@link AMOTION_EVENT_ACTION_OUTSIDE} for + * touches that occur outside of your window. Note that you will not + * receive the full down/move/up gesture, only the location of the + * first down as an {@link AMOTION_EVENT_ACTION_OUTSIDE}. + */ + GAMEACTIVITY_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + /** + * Special flag to let windows be shown when the screen + * is locked. This will let application windows take precedence over + * key guard or any other lock screens. Can be used with + * {@link GAMEACTIVITY_FLAG_KEEP_SCREEN_ON} to turn screen on and display + * windows directly before showing the key guard window. Can be used with + * {@link GAMEACTIVITY_FLAG_DISMISS_KEYGUARD} to automatically fully + * dismisss non-secure keyguards. This flag only applies to the top-most + * full-screen window. + */ + GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED = 0x00080000, + /** + * Ask that the system wallpaper be shown behind + * your window. The window surface must be translucent to be able + * to actually see the wallpaper behind it; this flag just ensures + * that the wallpaper surface will be there if this window actually + * has translucent regions. + */ + GAMEACTIVITY_FLAG_SHOW_WALLPAPER = 0x00100000, + /** + * When set as a window is being added or made + * visible, once the window has been shown then the system will + * poke the power manager's user activity (as if the user had woken + * up the device) to turn the screen on. + */ + GAMEACTIVITY_FLAG_TURN_SCREEN_ON = 0x00200000, + /** + * When set the window will cause the keyguard to + * be dismissed, only if it is not a secure lock keyguard. Because such + * a keyguard is not needed for security, it will never re-appear if + * the user navigates to another window (in contrast to + * {@link GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED}, which will only temporarily + * hide both secure and non-secure keyguards but ensure they reappear + * when the user moves to another UI that doesn't hide them). + * If the keyguard is currently active and is secure (requires an + * unlock pattern) than the user will still need to confirm it before + * seeing this window, unless {@link GAMEACTIVITY_FLAG_SHOW_WHEN_LOCKED} has + * also been set. + */ + GAMEACTIVITY_FLAG_DISMISS_KEYGUARD = 0x00400000, }; /** @@ -529,26 +522,25 @@ enum GameActivitySetWindowFlags : uint32_t { * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ -void GameActivity_setWindowFlags(GameActivity* activity, uint32_t addFlags, - uint32_t removeFlags); +void GameActivity_setWindowFlags(GameActivity* activity, uint32_t addFlags, uint32_t removeFlags); /** * Flags for GameActivity_showSoftInput; see the Java InputMethodManager * API for documentation. */ enum GameActivityShowSoftInputFlags : uint8_t { - /** - * Implicit request to show the input window, not as the result - * of a direct request by the user. - */ - GAMEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001, - - /** - * The user has forced the input method open (such as by - * long-pressing menu) so it should not be closed until they - * explicitly do so. - */ - GAMEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, + /** + * Implicit request to show the input window, not as the result + * of a direct request by the user. + */ + GAMEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001, + + /** + * The user has forced the input method open (such as by + * long-pressing menu) so it should not be closed until they + * explicitly do so. + */ + GAMEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, }; /** @@ -572,16 +564,14 @@ void GameActivity_restartInput(GameActivity* activity); * * Ownership of the state is maintained by the caller. */ -void GameActivity_setTextInputState(GameActivity* activity, - const GameTextInputState* state); +void GameActivity_setTextInputState(GameActivity* activity, const GameTextInputState* state); /** * Get the last-received text entry state (see documentation of the * GameTextInputState struct in the Game Text Input library reference). * */ -void GameActivity_getTextInputState(GameActivity* activity, - GameTextInputGetStateCallback callback, +void GameActivity_getTextInputState(GameActivity* activity, GameTextInputGetStateCallback callback, void* context); /** @@ -594,16 +584,16 @@ GameTextInput* GameActivity_getTextInput(const GameActivity* activity); * API for documentation. */ enum GameActivityHideSoftInputFlags : uint16_t { - /** - * The soft input window should only be hidden if it was not - * explicitly shown by the user. - */ - GAMEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001, - /** - * The soft input window should normally be hidden, unless it was - * originally shown with {@link GAMEACTIVITY_SHOW_SOFT_INPUT_FORCED}. - */ - GAMEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, + /** + * The soft input window should only be hidden if it was not + * explicitly shown by the user. + */ + GAMEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001, + /** + * The soft input window should normally be hidden, unless it was + * originally shown with {@link GAMEACTIVITY_SHOW_SOFT_INPUT_FORCED}. + */ + GAMEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, }; /** @@ -620,8 +610,7 @@ void GameActivity_hideSoftInput(GameActivity* activity, uint32_t flags); * for more details. * You can use these insets to influence what you show on the screen. */ -void GameActivity_getWindowInsets(GameActivity* activity, - GameCommonInsetsType type, ARect* insets); +void GameActivity_getWindowInsets(GameActivity* activity, GameCommonInsetsType type, ARect* insets); /** * Tells whether the software keyboard is visible or not. @@ -636,8 +625,7 @@ bool GameActivity_isSoftwareKeyboardVisible(GameActivity* activity); * * Note: currently only TYPE_NULL AND TYPE_CLASS_NUMBER are supported. */ -void GameActivity_setImeEditorInfo(GameActivity* activity, - enum GameTextInputType inputType, +void GameActivity_setImeEditorInfo(GameActivity* activity, enum GameTextInputType inputType, enum GameTextInputActionType actionId, enum GameTextInputImeOptions imeOptions); @@ -693,14 +681,14 @@ int GameActivity_getUIMode(GameActivity* activity); * * Refer to Java documentation of locales for more information. */ -int GameActivity_getLocaleLanguage(char* dst, size_t dst_size, - GameActivity* activity, size_t localeIdx); -int GameActivity_getLocaleScript(char* dst, size_t dst_size, - GameActivity* activity, size_t localeIdx); -int GameActivity_getLocaleCountry(char* dst, size_t dst_size, - GameActivity* activity, size_t localeIdx); -int GameActivity_getLocaleVariant(char* dst, size_t dst_size, - GameActivity* activity, size_t localeIdx); +int GameActivity_getLocaleLanguage(char* dst, size_t dst_size, GameActivity* activity, + size_t localeIdx); +int GameActivity_getLocaleScript(char* dst, size_t dst_size, GameActivity* activity, + size_t localeIdx); +int GameActivity_getLocaleCountry(char* dst, size_t dst_size, GameActivity* activity, + size_t localeIdx); +int GameActivity_getLocaleVariant(char* dst, size_t dst_size, GameActivity* activity, + size_t localeIdx); #ifdef __cplusplus } @@ -708,4 +696,4 @@ int GameActivity_getLocaleVariant(char* dst, size_t dst_size, /** @} */ -#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_H +#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_H diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h index 2a7982af..64c70e02 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h @@ -57,29 +57,26 @@ extern "C" { * \see GameActivityMotionEvent */ typedef struct GameActivityPointerAxes { - int32_t id; - int32_t toolType; - float axisValues[GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT]; - float rawX; - float rawY; + int32_t id; + int32_t toolType; + float axisValues[GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT]; + float rawX; + float rawY; } GameActivityPointerAxes; /** \brief Get the toolType of the pointer. */ -inline int32_t GameActivityPointerAxes_getToolType( - const GameActivityPointerAxes* pointerInfo) { - return pointerInfo->toolType; +inline int32_t GameActivityPointerAxes_getToolType(const GameActivityPointerAxes* pointerInfo) { + return pointerInfo->toolType; } /** \brief Get the current X coordinate of the pointer. */ -inline float GameActivityPointerAxes_getX( - const GameActivityPointerAxes* pointerInfo) { - return pointerInfo->axisValues[AMOTION_EVENT_AXIS_X]; +inline float GameActivityPointerAxes_getX(const GameActivityPointerAxes* pointerInfo) { + return pointerInfo->axisValues[AMOTION_EVENT_AXIS_X]; } /** \brief Get the current Y coordinate of the pointer. */ -inline float GameActivityPointerAxes_getY( - const GameActivityPointerAxes* pointerInfo) { - return pointerInfo->axisValues[AMOTION_EVENT_AXIS_Y]; +inline float GameActivityPointerAxes_getY(const GameActivityPointerAxes* pointerInfo) { + return pointerInfo->axisValues[AMOTION_EVENT_AXIS_Y]; } /** @@ -121,49 +118,35 @@ void GameActivityPointerAxes_disableAxis(int32_t axis); * @return The value of the axis, or 0 if the axis is invalid or was not * enabled. */ -float GameActivityPointerAxes_getAxisValue( - const GameActivityPointerAxes* pointerInfo, int32_t axis); +float GameActivityPointerAxes_getAxisValue(const GameActivityPointerAxes* pointerInfo, + int32_t axis); -inline float GameActivityPointerAxes_getPressure( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_PRESSURE); +inline float GameActivityPointerAxes_getPressure(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_PRESSURE); } -inline float GameActivityPointerAxes_getSize( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_SIZE); +inline float GameActivityPointerAxes_getSize(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_SIZE); } -inline float GameActivityPointerAxes_getTouchMajor( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_TOUCH_MAJOR); +inline float GameActivityPointerAxes_getTouchMajor(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_TOUCH_MAJOR); } -inline float GameActivityPointerAxes_getTouchMinor( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_TOUCH_MINOR); +inline float GameActivityPointerAxes_getTouchMinor(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_TOUCH_MINOR); } -inline float GameActivityPointerAxes_getToolMajor( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_TOOL_MAJOR); +inline float GameActivityPointerAxes_getToolMajor(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_TOOL_MAJOR); } -inline float GameActivityPointerAxes_getToolMinor( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_TOOL_MINOR); +inline float GameActivityPointerAxes_getToolMinor(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_TOOL_MINOR); } -inline float GameActivityPointerAxes_getOrientation( - const GameActivityPointerAxes* pointerInfo) { - return GameActivityPointerAxes_getAxisValue(pointerInfo, - AMOTION_EVENT_AXIS_ORIENTATION); +inline float GameActivityPointerAxes_getOrientation(const GameActivityPointerAxes* pointerInfo) { + return GameActivityPointerAxes_getAxisValue(pointerInfo, AMOTION_EVENT_AXIS_ORIENTATION); } /** @@ -171,7 +154,7 @@ inline float GameActivityPointerAxes_getOrientation( */ #if (defined GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE) #define GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT \ - GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE + GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE #else #define GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT 8 #endif @@ -183,95 +166,92 @@ inline float GameActivityPointerAxes_getOrientation( * (see https://developer.android.com/reference/android/view/MotionEvent). */ typedef struct GameActivityMotionEvent { - int32_t deviceId; - int32_t source; - int32_t action; + int32_t deviceId; + int32_t source; + int32_t action; - int64_t eventTime; - int64_t downTime; + int64_t eventTime; + int64_t downTime; - int32_t flags; - int32_t metaState; + int32_t flags; + int32_t metaState; - int32_t actionButton; - int32_t buttonState; - int32_t classification; - int32_t edgeFlags; + int32_t actionButton; + int32_t buttonState; + int32_t classification; + int32_t edgeFlags; - uint32_t pointerCount; - GameActivityPointerAxes - pointers[GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT]; + uint32_t pointerCount; + GameActivityPointerAxes pointers[GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT]; - int historySize; - int64_t* historicalEventTimesMillis; - int64_t* historicalEventTimesNanos; - float* historicalAxisValues; + int historySize; + int64_t* historicalEventTimesMillis; + int64_t* historicalEventTimesNanos; + float* historicalAxisValues; - float precisionX; - float precisionY; + float precisionX; + float precisionY; } GameActivityMotionEvent; -float GameActivityMotionEvent_getHistoricalAxisValue( - const GameActivityMotionEvent* event, int axis, int pointerIndex, - int historyPos); +float GameActivityMotionEvent_getHistoricalAxisValue(const GameActivityMotionEvent* event, int axis, + int pointerIndex, int historyPos); -inline int GameActivityMotionEvent_getHistorySize( - const GameActivityMotionEvent* event) { - return event->historySize; +inline int GameActivityMotionEvent_getHistorySize(const GameActivityMotionEvent* event) { + return event->historySize; } -inline float GameActivityMotionEvent_getHistoricalX( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_X, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalX(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_X, pointerIndex, + historyPos); } -inline float GameActivityMotionEvent_getHistoricalY( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_Y, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalY(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_Y, pointerIndex, + historyPos); } -inline float GameActivityMotionEvent_getHistoricalPressure( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalPressure(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_PRESSURE, + pointerIndex, historyPos); } -inline float GameActivityMotionEvent_getHistoricalSize( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_SIZE, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalSize(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_SIZE, + pointerIndex, historyPos); } -inline float GameActivityMotionEvent_getHistoricalTouchMajor( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalTouchMajor(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_TOUCH_MAJOR, + pointerIndex, historyPos); } -inline float GameActivityMotionEvent_getHistoricalTouchMinor( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalTouchMinor(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_TOUCH_MINOR, + pointerIndex, historyPos); } -inline float GameActivityMotionEvent_getHistoricalToolMajor( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalToolMajor(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_TOOL_MAJOR, + pointerIndex, historyPos); } -inline float GameActivityMotionEvent_getHistoricalToolMinor( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalToolMinor(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_TOOL_MINOR, + pointerIndex, historyPos); } -inline float GameActivityMotionEvent_getHistoricalOrientation( - const GameActivityMotionEvent* event, int pointerIndex, int historyPos) { - return GameActivityMotionEvent_getHistoricalAxisValue( - event, AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historyPos); +inline float GameActivityMotionEvent_getHistoricalOrientation(const GameActivityMotionEvent* event, + int pointerIndex, int historyPos) { + return GameActivityMotionEvent_getHistoricalAxisValue(event, AMOTION_EVENT_AXIS_ORIENTATION, + pointerIndex, historyPos); } /** \brief Handle the freeing of the GameActivityMotionEvent struct. */ @@ -286,21 +266,21 @@ void GameActivityMotionEvent_destroy(GameActivityMotionEvent* c_event); * nanoseconds in this struct. */ typedef struct GameActivityKeyEvent { - int32_t deviceId; - int32_t source; - int32_t action; + int32_t deviceId; + int32_t source; + int32_t action; - int64_t eventTime; - int64_t downTime; + int64_t eventTime; + int64_t downTime; - int32_t flags; - int32_t metaState; + int32_t flags; + int32_t metaState; - int32_t modifiers; - int32_t repeatCount; - int32_t keyCode; - int32_t scanCode; - // int32_t unicodeChar; + int32_t modifiers; + int32_t repeatCount; + int32_t keyCode; + int32_t scanCode; + // int32_t unicodeChar; } GameActivityKeyEvent; #ifdef __cplusplus @@ -309,4 +289,4 @@ typedef struct GameActivityKeyEvent { /** @} */ -#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_H +#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_H diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h index 311b3c4d..c9554b61 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h @@ -25,8 +25,7 @@ #ifdef NDEBUG #define ALOGV(...) #else -#define ALOGV(...) \ - __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__); +#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__); #endif /* Returns 2nd arg. Used to substitute default value if caller's vararg list @@ -40,36 +39,30 @@ #define __android_rest(first, ...) , ##__VA_ARGS__ #define android_printAssert(cond, tag, fmt...) \ - __android_log_assert(cond, tag, \ - __android_second(0, ##fmt, NULL) __android_rest(fmt)) + __android_log_assert(cond, tag, __android_second(0, ##fmt, NULL) __android_rest(fmt)) #define CONDITION(cond) (__builtin_expect((cond) != 0, 0)) #ifndef LOG_ALWAYS_FATAL_IF -#define LOG_ALWAYS_FATAL_IF(cond, ...) \ - ((CONDITION(cond)) \ - ? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) \ - : (void)0) +#define LOG_ALWAYS_FATAL_IF(cond, ...) \ + ((CONDITION(cond)) ? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) : (void)0) #endif #ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) \ - (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__))) +#define LOG_ALWAYS_FATAL(...) (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__))) #endif /* * Simplified macro to send a warning system log message using current LOG_TAG. */ #ifndef SLOGW -#define SLOGW(...) \ - ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#define SLOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) #endif #ifndef SLOGW_IF -#define SLOGW_IF(cond, ...) \ - ((__predict_false(cond)) \ - ? ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0) +#define SLOGW_IF(cond, ...) \ + ((__predict_false(cond)) ? ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ + : (void)0) #endif /* @@ -106,4 +99,4 @@ #define LOG_TRACE(...) -#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_LOG_H_ +#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_LOG_H_ diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/native_app_glue/android_native_app_glue.h b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/native_app_glue/android_native_app_glue.h index 6029bc9c..5aa37434 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/native_app_glue/android_native_app_glue.h +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/include/game-activity/native_app_glue/android_native_app_glue.h @@ -87,54 +87,54 @@ struct android_app; * when that source has data ready. */ struct android_poll_source { - /** - * The identifier of this source. May be LOOPER_ID_MAIN or - * LOOPER_ID_INPUT. - */ - int32_t id; - - /** The android_app this ident is associated with. */ - struct android_app* app; - - /** - * Function to call to perform the standard processing of data from - * this source. - */ - void (*process)(struct android_app* app, struct android_poll_source* source); + /** + * The identifier of this source. May be LOOPER_ID_MAIN or + * LOOPER_ID_INPUT. + */ + int32_t id; + + /** The android_app this ident is associated with. */ + struct android_app* app; + + /** + * Function to call to perform the standard processing of data from + * this source. + */ + void (*process)(struct android_app* app, struct android_poll_source* source); }; struct android_input_buffer { - /** - * Pointer to a read-only array of GameActivityMotionEvent. - * Only the first motionEventsCount events are valid. - */ - GameActivityMotionEvent* motionEvents; - - /** - * The number of valid motion events in `motionEvents`. - */ - uint64_t motionEventsCount; - - /** - * The size of the `motionEvents` buffer. - */ - uint64_t motionEventsBufferSize; - - /** - * Pointer to a read-only array of GameActivityKeyEvent. - * Only the first keyEventsCount events are valid. - */ - GameActivityKeyEvent* keyEvents; - - /** - * The number of valid "Key" events in `keyEvents`. - */ - uint64_t keyEventsCount; - - /** - * The size of the `keyEvents` buffer. - */ - uint64_t keyEventsBufferSize; + /** + * Pointer to a read-only array of GameActivityMotionEvent. + * Only the first motionEventsCount events are valid. + */ + GameActivityMotionEvent* motionEvents; + + /** + * The number of valid motion events in `motionEvents`. + */ + uint64_t motionEventsCount; + + /** + * The size of the `motionEvents` buffer. + */ + uint64_t motionEventsBufferSize; + + /** + * Pointer to a read-only array of GameActivityKeyEvent. + * Only the first keyEventsCount events are valid. + */ + GameActivityKeyEvent* keyEvents; + + /** + * The number of valid "Key" events in `keyEvents`. + */ + uint64_t keyEventsCount; + + /** + * The size of the `keyEvents` buffer. + */ + uint64_t keyEventsBufferSize; }; /** @@ -164,150 +164,150 @@ typedef bool (*android_motion_event_filter)(const GameActivityMotionEvent*); * Java objects. */ struct android_app { - /** - * An optional pointer to application-defined state. - */ - void* userData; - - /** - * A required callback for processing main app commands (`APP_CMD_*`). - * This is called each frame if there are app commands that need processing. - */ - void (*onAppCmd)(struct android_app* app, int32_t cmd); - - /** The GameActivity object instance that this app is running in. */ - GameActivity* activity; - - /** The current configuration the app is running in. */ - AConfiguration* config; - - /** - * The last activity saved state, as provided at creation time. - * It is NULL if there was no state. You can use this as you need; the - * memory will remain around until you call android_app_exec_cmd() for - * APP_CMD_RESUME, at which point it will be freed and savedState set to - * NULL. These variables should only be changed when processing a - * APP_CMD_SAVE_STATE, at which point they will be initialized to NULL and - * you can malloc your state and place the information here. In that case - * the memory will be freed for you later. - */ - void* savedState; - - /** - * The size of the activity saved state. It is 0 if `savedState` is NULL. - */ - size_t savedStateSize; - - /** The ALooper associated with the app's thread. */ - ALooper* looper; - - /** The ALooper associated with the app's Java main/UI thread. */ - ALooper* mainLooper; - - /** When non-NULL, this is the window surface that the app can draw in. */ - ANativeWindow* window; - - /** - * Current content rectangle of the window; this is the area where the - * window's content should be placed to be seen by the user. - */ - ARect contentRect; - - /** - * Whether the software keyboard is visible or not. - */ - bool softwareKeyboardVisible; - - /** - * Last editor action. Valid within APP_CMD_SOFTWARE_KB_VIS_CHANGED handler. - * - * Note: the upstream comment above isn't accurate. - * - `APP_CMD_SOFTWARE_KB_VIS_CHANGED` is associated with `softwareKeyboardVisible` - * changes, not `editorAction`. - * - `APP_CMD_EDITOR_ACTION` is associated with this state but unlike for - * `window` state there's no synchonization that blocks the Java main - * thread, so we can't say that this is only valid within the `APP_CMD_` handler. - */ - int editorAction; - /** - * true when editorAction has been set - */ - bool pendingEditorAction; - - /** - * Current state of the app's activity. May be either APP_CMD_START, - * APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP. - */ - int activityState; - - /** - * This is non-zero when the application's GameActivity is being - * destroyed and waiting for the app thread to complete. - */ - int destroyRequested; + /** + * An optional pointer to application-defined state. + */ + void* userData; + + /** + * A required callback for processing main app commands (`APP_CMD_*`). + * This is called each frame if there are app commands that need processing. + */ + void (*onAppCmd)(struct android_app* app, int32_t cmd); + + /** The GameActivity object instance that this app is running in. */ + GameActivity* activity; + + /** The current configuration the app is running in. */ + AConfiguration* config; + + /** + * The last activity saved state, as provided at creation time. + * It is NULL if there was no state. You can use this as you need; the + * memory will remain around until you call android_app_exec_cmd() for + * APP_CMD_RESUME, at which point it will be freed and savedState set to + * NULL. These variables should only be changed when processing a + * APP_CMD_SAVE_STATE, at which point they will be initialized to NULL and + * you can malloc your state and place the information here. In that case + * the memory will be freed for you later. + */ + void* savedState; + + /** + * The size of the activity saved state. It is 0 if `savedState` is NULL. + */ + size_t savedStateSize; + + /** The ALooper associated with the app's thread. */ + ALooper* looper; + + /** The ALooper associated with the app's Java main/UI thread. */ + ALooper* mainLooper; + + /** When non-NULL, this is the window surface that the app can draw in. */ + ANativeWindow* window; + + /** + * Current content rectangle of the window; this is the area where the + * window's content should be placed to be seen by the user. + */ + ARect contentRect; + + /** + * Whether the software keyboard is visible or not. + */ + bool softwareKeyboardVisible; + + /** + * Last editor action. Valid within APP_CMD_SOFTWARE_KB_VIS_CHANGED handler. + * + * Note: the upstream comment above isn't accurate. + * - `APP_CMD_SOFTWARE_KB_VIS_CHANGED` is associated with `softwareKeyboardVisible` + * changes, not `editorAction`. + * - `APP_CMD_EDITOR_ACTION` is associated with this state but unlike for + * `window` state there's no synchonization that blocks the Java main + * thread, so we can't say that this is only valid within the `APP_CMD_` handler. + */ + int editorAction; + /** + * true when editorAction has been set + */ + bool pendingEditorAction; + + /** + * Current state of the app's activity. May be either APP_CMD_START, + * APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP. + */ + int activityState; + + /** + * This is non-zero when the application's GameActivity is being + * destroyed and waiting for the app thread to complete. + */ + int destroyRequested; #define NATIVE_APP_GLUE_MAX_INPUT_BUFFERS 2 - /** - * This is used for buffering input from GameActivity. Once ready, the - * application thread switches the buffers and processes what was - * accumulated. - */ - struct android_input_buffer inputBuffers[NATIVE_APP_GLUE_MAX_INPUT_BUFFERS]; - - int currentInputBuffer; - - /** - * 0 if no text input event is outstanding, 1 if it is. - * Use `GameActivity_getTextInputState` to get information - * about the text entered by the user. - */ - int textInputState; - - // Below are "private" implementation of the glue code. - /** @cond INTERNAL */ - - pthread_mutex_t mutex; - pthread_cond_t cond; - - int msgread; - int msgwrite; - - pthread_t thread; - - struct android_poll_source cmdPollSource; - - int running; - int stateSaved; - int destroyed; - int redrawNeeded; - ANativeWindow* pendingWindow; - ARect pendingContentRect; - - android_key_event_filter keyEventFilter; - android_motion_event_filter motionEventFilter; - - // When new input is received we set both of these flags and use the looper to - // wake up the application mainloop. - // - // To avoid spamming the mainloop with wake ups from lots of input though we - // don't sent a wake up if the inputSwapPending flag is already set. (i.e. - // we already expect input to be processed in a finite amount of time due to - // our previous wake up) - // - // When a wake up is received then we will check this flag (clearing it - // at the same time). If it was set then an InputAvailable event is sent to - // the application - which should lead to all input being processed within - // a finite amount of time. - // - // The next time android_app_swap_input_buffers is called, both flags will be - // cleared. - // - // NB: both of these should only be read with the app mutex held - bool inputAvailableWakeUp; - bool inputSwapPending; - - /** @endcond */ + /** + * This is used for buffering input from GameActivity. Once ready, the + * application thread switches the buffers and processes what was + * accumulated. + */ + struct android_input_buffer inputBuffers[NATIVE_APP_GLUE_MAX_INPUT_BUFFERS]; + + int currentInputBuffer; + + /** + * 0 if no text input event is outstanding, 1 if it is. + * Use `GameActivity_getTextInputState` to get information + * about the text entered by the user. + */ + int textInputState; + + // Below are "private" implementation of the glue code. + /** @cond INTERNAL */ + + pthread_mutex_t mutex; + pthread_cond_t cond; + + int msgread; + int msgwrite; + + pthread_t thread; + + struct android_poll_source cmdPollSource; + + int running; + int stateSaved; + int destroyed; + int redrawNeeded; + ANativeWindow* pendingWindow; + ARect pendingContentRect; + + android_key_event_filter keyEventFilter; + android_motion_event_filter motionEventFilter; + + // When new input is received we set both of these flags and use the looper to + // wake up the application mainloop. + // + // To avoid spamming the mainloop with wake ups from lots of input though we + // don't sent a wake up if the inputSwapPending flag is already set. (i.e. + // we already expect input to be processed in a finite amount of time due to + // our previous wake up) + // + // When a wake up is received then we will check this flag (clearing it + // at the same time). If it was set then an InputAvailable event is sent to + // the application - which should lead to all input being processed within + // a finite amount of time. + // + // The next time android_app_swap_input_buffers is called, both flags will be + // cleared. + // + // NB: both of these should only be read with the app mutex held + bool inputAvailableWakeUp; + bool inputSwapPending; + + /** @endcond */ }; /** @@ -315,25 +315,25 @@ struct android_app { * user-defined sources. */ enum NativeAppGlueLooperId : int8_t { - /** - * Looper data ID of commands coming from the app's main thread, which - * is returned as an identifier from ALooper_pollOnce(). The data for this - * identifier is a pointer to an android_poll_source structure. - * These can be retrieved and processed with android_app_read_cmd() - * and android_app_exec_cmd(). - */ - LOOPER_ID_MAIN = 1, - - /** - * Unused. Reserved for future use when usage of AInputQueue will be - * supported. - */ - LOOPER_ID_INPUT = 2, - - /** - * Start of user-defined ALooper identifiers. - */ - LOOPER_ID_USER = 3, + /** + * Looper data ID of commands coming from the app's main thread, which + * is returned as an identifier from ALooper_pollOnce(). The data for this + * identifier is a pointer to an android_poll_source structure. + * These can be retrieved and processed with android_app_read_cmd() + * and android_app_exec_cmd(). + */ + LOOPER_ID_MAIN = 1, + + /** + * Unused. Reserved for future use when usage of AInputQueue will be + * supported. + */ + LOOPER_ID_INPUT = 2, + + /** + * Start of user-defined ALooper identifiers. + */ + LOOPER_ID_USER = 3, }; /** @@ -343,134 +343,134 @@ enum NativeAppGlueLooperId : int8_t { * can be used for custom user's events. */ enum NativeAppGlueAppCmd : int8_t { - /** - * Unused. Reserved for future use when usage of AInputQueue will be - * supported. - */ - UNUSED_APP_CMD_INPUT_CHANGED, - - /** - * Command from main thread: a new ANativeWindow is ready for use. Upon - * receiving this command, android_app->window will contain the new window - * surface. - */ - APP_CMD_INIT_WINDOW, - - /** - * Command from main thread: the existing ANativeWindow needs to be - * terminated. Upon receiving this command, android_app->window still - * contains the existing window; after calling android_app_exec_cmd - * it will be set to NULL. - */ - APP_CMD_TERM_WINDOW, - - /** - * Command from main thread: the current ANativeWindow has been resized. - * Please redraw with its new size. - */ - APP_CMD_WINDOW_RESIZED, - - /** - * Command from main thread: the system needs that the current ANativeWindow - * be redrawn. You should redraw the window before handing this to - * android_app_exec_cmd() in order to avoid transient drawing glitches. - */ - APP_CMD_WINDOW_REDRAW_NEEDED, - - /** - * Command from main thread: the content area of the window has changed, - * such as from the soft input window being shown or hidden. You can - * find the new content rect in android_app::contentRect. - */ - APP_CMD_CONTENT_RECT_CHANGED, - - /** - * Command from main thread: the software keyboard was shown or hidden. - */ - APP_CMD_SOFTWARE_KB_VIS_CHANGED, - - /** - * Command from main thread: the app's activity window has gained - * input focus. - */ - APP_CMD_GAINED_FOCUS, - - /** - * Command from main thread: the app's activity window has lost - * input focus. - */ - APP_CMD_LOST_FOCUS, - - /** - * Command from main thread: the current device configuration has changed. - */ - APP_CMD_CONFIG_CHANGED, - - /** - * Command from main thread: the system is running low on memory. - * Try to reduce your memory use. - */ - APP_CMD_LOW_MEMORY, - - /** - * Command from main thread: the app's activity has been started. - */ - APP_CMD_START, - - /** - * Command from main thread: the app's activity has been resumed. - */ - APP_CMD_RESUME, - - /** - * Command from main thread: the app should generate a new saved state - * for itself, to restore from later if needed. If you have saved state, - * allocate it with malloc and place it in android_app.savedState with - * the size in android_app.savedStateSize. The will be freed for you - * later. - */ - APP_CMD_SAVE_STATE, - - /** - * Command from main thread: the app's activity has been paused. - */ - APP_CMD_PAUSE, - - /** - * Command from main thread: the app's activity has been stopped. - */ - APP_CMD_STOP, - - /** - * Command from main thread: the app's activity is being destroyed, - * and waiting for the app thread to clean up and exit before proceeding. - */ - APP_CMD_DESTROY, - - /** - * Command from main thread: the app's insets have changed. - */ - APP_CMD_WINDOW_INSETS_CHANGED, - - /** - * Command from main thread: an editor action has been triggered. - */ - //APP_CMD_EDITOR_ACTION, - - /** - * Command from main thread: a keyboard event has been received. - */ - //APP_CMD_KEY_EVENT, - - /** - * Command from main thread: a touch event has been received. - */ - //APP_CMD_TOUCH_EVENT, + /** + * Unused. Reserved for future use when usage of AInputQueue will be + * supported. + */ + UNUSED_APP_CMD_INPUT_CHANGED, + + /** + * Command from main thread: a new ANativeWindow is ready for use. Upon + * receiving this command, android_app->window will contain the new window + * surface. + */ + APP_CMD_INIT_WINDOW, + + /** + * Command from main thread: the existing ANativeWindow needs to be + * terminated. Upon receiving this command, android_app->window still + * contains the existing window; after calling android_app_exec_cmd + * it will be set to NULL. + */ + APP_CMD_TERM_WINDOW, + + /** + * Command from main thread: the current ANativeWindow has been resized. + * Please redraw with its new size. + */ + APP_CMD_WINDOW_RESIZED, + + /** + * Command from main thread: the system needs that the current ANativeWindow + * be redrawn. You should redraw the window before handing this to + * android_app_exec_cmd() in order to avoid transient drawing glitches. + */ + APP_CMD_WINDOW_REDRAW_NEEDED, + + /** + * Command from main thread: the content area of the window has changed, + * such as from the soft input window being shown or hidden. You can + * find the new content rect in android_app::contentRect. + */ + APP_CMD_CONTENT_RECT_CHANGED, + + /** + * Command from main thread: the software keyboard was shown or hidden. + */ + APP_CMD_SOFTWARE_KB_VIS_CHANGED, + + /** + * Command from main thread: the app's activity window has gained + * input focus. + */ + APP_CMD_GAINED_FOCUS, + + /** + * Command from main thread: the app's activity window has lost + * input focus. + */ + APP_CMD_LOST_FOCUS, + + /** + * Command from main thread: the current device configuration has changed. + */ + APP_CMD_CONFIG_CHANGED, + + /** + * Command from main thread: the system is running low on memory. + * Try to reduce your memory use. + */ + APP_CMD_LOW_MEMORY, + + /** + * Command from main thread: the app's activity has been started. + */ + APP_CMD_START, + + /** + * Command from main thread: the app's activity has been resumed. + */ + APP_CMD_RESUME, + + /** + * Command from main thread: the app should generate a new saved state + * for itself, to restore from later if needed. If you have saved state, + * allocate it with malloc and place it in android_app.savedState with + * the size in android_app.savedStateSize. The will be freed for you + * later. + */ + APP_CMD_SAVE_STATE, + + /** + * Command from main thread: the app's activity has been paused. + */ + APP_CMD_PAUSE, + + /** + * Command from main thread: the app's activity has been stopped. + */ + APP_CMD_STOP, + + /** + * Command from main thread: the app's activity is being destroyed, + * and waiting for the app thread to clean up and exit before proceeding. + */ + APP_CMD_DESTROY, + + /** + * Command from main thread: the app's insets have changed. + */ + APP_CMD_WINDOW_INSETS_CHANGED, + + /** + * Command from main thread: an editor action has been triggered. + */ + // APP_CMD_EDITOR_ACTION, + + /** + * Command from main thread: a keyboard event has been received. + */ + // APP_CMD_KEY_EVENT, + + /** + * Command from main thread: a touch event has been received. + */ + // APP_CMD_TOUCH_EVENT, }; /** - * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next + * Call when ALooper_pollOnce() returns LOOPER_ID_MAIN, reading the next * app command message. */ int8_t android_app_read_cmd(struct android_app* android_app); @@ -493,8 +493,7 @@ void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); * Call this before processing input events to get the events buffer. * The function returns NULL if there are no events to process. */ -struct android_input_buffer* android_app_swap_input_buffers( - struct android_app* android_app); +struct android_input_buffer* android_app_swap_input_buffers(struct android_app* android_app); /** * Clear the array of motion events that were waiting to be handled, and release @@ -527,8 +526,7 @@ extern void _rust_glue_entry(struct android_app* app); * * The default key filter will filter out volume and camera button presses. */ -void android_app_set_key_event_filter(struct android_app* app, - android_key_event_filter filter); +void android_app_set_key_event_filter(struct android_app* app, android_key_event_filter filter); /** * Set the filter to use when processing touch and motion events. @@ -549,8 +547,10 @@ void android_app_set_motion_event_filter(struct android_app* app, * * Values from 0 to 127 are reserved for this library; values from -128 to -1 * can be used for custom user's events. + * + * The function returns true if the write operation was successful. */ -void android_app_write_cmd(struct android_app* android_app, int8_t cmd); +bool android_app_write_cmd(struct android_app* android_app, int8_t cmd); /** * Determines if a looper wake up was due to new input becoming available diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivity.cpp b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivity.cpp index 045dbdf7..e4987249 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivity.cpp +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivity.cpp @@ -44,18 +44,20 @@ namespace { +static std::atomic g_methodsRegistered(false); + struct OwnedGameTextInputState { - OwnedGameTextInputState &operator=(const GameTextInputState &rhs) { - inner = rhs; - owned_string = std::string(rhs.text_UTF8, rhs.text_length); - inner.text_UTF8 = owned_string.data(); - return *this; - } - GameTextInputState inner; - std::string owned_string; + OwnedGameTextInputState& operator=(const GameTextInputState& rhs) { + inner = rhs; + owned_string = std::string(rhs.text_UTF8, rhs.text_length); + inner.text_UTF8 = owned_string.data(); + return *this; + } + GameTextInputState inner; + std::string owned_string; }; -} // anonymous namespace +} // anonymous namespace #ifndef NELEM #define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0]))) @@ -65,73 +67,73 @@ struct OwnedGameTextInputState { * JNI methods of the GameActivity Java class. */ static struct { - jmethodID finish; - jmethodID setWindowFlags; - jmethodID getWindowInsets; - jmethodID getWaterfallInsets; - jmethodID setImeEditorInfoFields; + jmethodID finish; + jmethodID setWindowFlags; + jmethodID getWindowInsets; + jmethodID getWaterfallInsets; + jmethodID setImeEditorInfoFields; } gGameActivityClassInfo; /* * JNI methods of the android.os.LocaleList class. */ static struct { - jmethodID size; - jmethodID get; + jmethodID size; + jmethodID get; } gLocaleListClassInfo; /* * JNI methods of the java.util.Locale class. */ static struct { - jmethodID getLanguage; - jmethodID getScript; - jmethodID getCountry; - jmethodID getVariant; + jmethodID getLanguage; + jmethodID getScript; + jmethodID getCountry; + jmethodID getVariant; } gLocaleClassInfo; /* * JNI fields of the androidx.core.graphics.Insets Java class. */ static struct { - jfieldID left; - jfieldID right; - jfieldID top; - jfieldID bottom; + jfieldID left; + jfieldID right; + jfieldID top; + jfieldID bottom; } gInsetsClassInfo; /* * JNI fields of the Configuration Java class. */ static struct ConfigurationClassInfo { - jfieldID colorMode; - jfieldID densityDpi; - jfieldID fontScale; - jfieldID fontWeightAdjustment; - jfieldID hardKeyboardHidden; - jfieldID keyboard; - jfieldID keyboardHidden; - jfieldID mcc; - jfieldID mnc; - jfieldID navigation; - jfieldID navigationHidden; - jfieldID orientation; - jfieldID screenHeightDp; - jfieldID screenLayout; - jfieldID screenWidthDp; - jfieldID smallestScreenWidthDp; - jfieldID touchscreen; - jfieldID uiMode; - - jmethodID getLocales; + jfieldID colorMode; + jfieldID densityDpi; + jfieldID fontScale; + jfieldID fontWeightAdjustment; + jfieldID hardKeyboardHidden; + jfieldID keyboard; + jfieldID keyboardHidden; + jfieldID mcc; + jfieldID mnc; + jfieldID navigation; + jfieldID navigationHidden; + jfieldID orientation; + jfieldID screenHeightDp; + jfieldID screenLayout; + jfieldID screenWidthDp; + jfieldID smallestScreenWidthDp; + jfieldID touchscreen; + jfieldID uiMode; + + jmethodID getLocales; } gConfigurationClassInfo; /* * JNI methods of the WindowInsetsCompat.Type Java class. */ static struct { - jmethodID methods[GAMECOMMON_INSETS_TYPE_COUNT]; - jclass clazz; + jmethodID methods[GAMECOMMON_INSETS_TYPE_COUNT]; + jclass clazz; } gWindowInsetsCompatTypeClassInfo; /* @@ -139,10 +141,10 @@ static struct { * on the application main thread. */ struct ActivityWork { - int32_t cmd; - int64_t arg1; - int64_t arg2; - int64_t arg3; + int32_t cmd; + int64_t arg1; + int64_t arg2; + int64_t arg3; }; /* @@ -150,24 +152,24 @@ struct ActivityWork { * are executed on the application main thread. */ enum { - CMD_FINISH = 1, - CMD_SET_WINDOW_FORMAT, - CMD_SET_WINDOW_FLAGS, - CMD_SHOW_SOFT_INPUT, - CMD_HIDE_SOFT_INPUT, - CMD_SET_SOFT_INPUT_STATE, - CMD_SET_IME_EDITOR_INFO, - CMD_RESTART_INPUT + CMD_FINISH = 1, + CMD_SET_WINDOW_FORMAT, + CMD_SET_WINDOW_FLAGS, + CMD_SHOW_SOFT_INPUT, + CMD_HIDE_SOFT_INPUT, + CMD_SET_SOFT_INPUT_STATE, + CMD_SET_IME_EDITOR_INFO, + CMD_RESTART_INPUT }; /* * A class for locale information, matching Android Java Locale class. */ struct Locale { - std::string language; - std::string script; - std::string country; - std::string variant; + std::string language; + std::string script; + std::string country; + std::string variant; }; /* @@ -175,25 +177,25 @@ struct Locale { * thread, this is why they are made atomic. */ static struct Configuration { - int colorMode; - int densityDpi; - float fontScale; - int fontWeightAdjustment; - int hardKeyboardHidden; - int keyboard; - int keyboardHidden; - int mcc; - int mnc; - int navigation; - int navigationHidden; - int orientation; - int screenHeightDp; - int screenLayout; - int screenWidthDp; - int smallestScreenWidthDp; - int touchscreen; - int uiMode; - std::vector locales; + int colorMode; + int densityDpi; + float fontScale; + int fontWeightAdjustment; + int hardKeyboardHidden; + int keyboard; + int keyboardHidden; + int mcc; + int mnc; + int navigation; + int navigationHidden; + int orientation; + int screenHeightDp; + int screenLayout; + int screenWidthDp; + int smallestScreenWidthDp; + int touchscreen; + int uiMode; + std::vector locales; } gConfiguration; static std::mutex gConfigMutex; @@ -202,1184 +204,1098 @@ static std::mutex gConfigMutex; * Write a command to be executed by the GameActivity on the application main * thread. */ -static void write_work(int fd, int32_t cmd, int64_t arg1 = 0, int64_t arg2 = 0, - int64_t arg3 = 0) { - ActivityWork work; - work.cmd = cmd; - work.arg1 = arg1; - work.arg2 = arg2; - work.arg3 = arg3; - - LOG_TRACE("write_work: cmd=%d", cmd); +static void write_work(int fd, int32_t cmd, int64_t arg1 = 0, int64_t arg2 = 0, int64_t arg3 = 0) { + ActivityWork work; + work.cmd = cmd; + work.arg1 = arg1; + work.arg2 = arg2; + work.arg3 = arg3; + + LOG_TRACE("write_work: cmd=%d", cmd); restart: - int res = write(fd, &work, sizeof(work)); - if (res < 0 && errno == EINTR) { - goto restart; - } + int res = write(fd, &work, sizeof(work)); + if (res < 0 && errno == EINTR) { + goto restart; + } - if (res == sizeof(work)) return; + if (res == sizeof(work)) return; - if (res < 0) { - ALOGW("Failed writing to work fd: %s", strerror(errno)); - } else { - ALOGW("Truncated writing to work fd: %d", res); - } + if (res < 0) { + ALOGW("Failed writing to work fd: %s", strerror(errno)); + } else { + ALOGW("Truncated writing to work fd: %d", res); + } } /* * Read commands to be executed by the GameActivity on the application main * thread. */ -static bool read_work(int fd, ActivityWork *outWork) { - int res = read(fd, outWork, sizeof(ActivityWork)); - // no need to worry about EINTR, poll loop will just come back again. - if (res == sizeof(ActivityWork)) return true; +static bool read_work(int fd, ActivityWork* outWork) { + int res = read(fd, outWork, sizeof(ActivityWork)); + // no need to worry about EINTR, poll loop will just come back again. + if (res == sizeof(ActivityWork)) return true; - if (res < 0) { - ALOGW("Failed reading work fd: %s", strerror(errno)); - } else { - ALOGW("Truncated reading work fd: %d", res); - } - return false; + if (res < 0) { + ALOGW("Failed reading work fd: %s", strerror(errno)); + } else { + ALOGW("Truncated reading work fd: %d", res); + } + return false; } /* * Native state for interacting with the GameActivity class. */ struct NativeCode : public GameActivity { - NativeCode() { - memset((GameActivity *)this, 0, sizeof(GameActivity)); - memset(&callbacks, 0, sizeof(callbacks)); - memset(&insetsState, 0, sizeof(insetsState)); - nativeWindow = NULL; - mainWorkRead = mainWorkWrite = -1; - gameTextInput = NULL; - softwareKeyboardVisible = false; - sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk"); - ALOGD("SDK version: %d", sdkVersion); - } - - ~NativeCode() { - if (callbacks.onDestroy != NULL) { - callbacks.onDestroy(this); - } - if (env != NULL) { - if (javaGameActivity != NULL) { - env->DeleteGlobalRef(javaGameActivity); - } - if (javaAssetManager != NULL) { - env->DeleteGlobalRef(javaAssetManager); - } + NativeCode() { + memset((GameActivity*)this, 0, sizeof(GameActivity)); + memset(&callbacks, 0, sizeof(callbacks)); + memset(&insetsState, 0, sizeof(insetsState)); + nativeWindow = NULL; + mainWorkRead = mainWorkWrite = -1; + gameTextInput = NULL; + softwareKeyboardVisible = false; + sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk"); + ALOGD("SDK version: %d", sdkVersion); } - GameTextInput_destroy(gameTextInput); - if (looper != NULL && mainWorkRead >= 0) { - ALooper_removeFd(looper, mainWorkRead); - } - ALooper_release(looper); - looper = NULL; - setSurface(NULL); - if (mainWorkRead >= 0) close(mainWorkRead); - if (mainWorkWrite >= 0) close(mainWorkWrite); - } + ~NativeCode() { + if (callbacks.onDestroy != NULL) { + callbacks.onDestroy(this); + } + if (env != NULL) { + if (javaGameActivity != NULL) { + env->DeleteGlobalRef(javaGameActivity); + } + if (javaAssetManager != NULL) { + env->DeleteGlobalRef(javaAssetManager); + } + } + GameTextInput_destroy(gameTextInput); + if (looper != NULL && mainWorkRead >= 0) { + ALooper_removeFd(looper, mainWorkRead); + } + ALooper_release(looper); + looper = NULL; - void setSurface(jobject _surface) { - if (nativeWindow != NULL) { - ANativeWindow_release(nativeWindow); + setSurface(NULL); + if (mainWorkRead >= 0) close(mainWorkRead); + if (mainWorkWrite >= 0) close(mainWorkWrite); } - if (_surface != NULL) { - nativeWindow = ANativeWindow_fromSurface(env, _surface); - } else { - nativeWindow = NULL; + + void setSurface(jobject _surface) { + if (nativeWindow != NULL) { + ANativeWindow_release(nativeWindow); + } + if (_surface != NULL) { + nativeWindow = ANativeWindow_fromSurface(env, _surface); + } else { + nativeWindow = NULL; + } } - } - GameActivityCallbacks callbacks; + GameActivityCallbacks callbacks; - std::string internalDataPathObj; - std::string externalDataPathObj; - std::string obbPathObj; + std::string internalDataPathObj; + std::string externalDataPathObj; + std::string obbPathObj; - ANativeWindow *nativeWindow; - int32_t lastWindowWidth; - int32_t lastWindowHeight; + ANativeWindow* nativeWindow; + int32_t lastWindowWidth; + int32_t lastWindowHeight; - // These are used to wake up the main thread to process work. - int mainWorkRead; - int mainWorkWrite; - ALooper *looper; + // These are used to wake up the main thread to process work. + int mainWorkRead; + int mainWorkWrite; + ALooper* looper; - // Need to hold on to a reference here in case the upper layers destroy our - // AssetManager. - jobject javaAssetManager; + // Need to hold on to a reference here in case the upper layers destroy our + // AssetManager. + jobject javaAssetManager; - GameTextInput *gameTextInput; - // Set by users in GameActivity_setTextInputState, then passed to - // GameTextInput. - OwnedGameTextInputState gameTextInputState; - std::mutex gameTextInputStateMutex; + GameTextInput* gameTextInput; + // Set by users in GameActivity_setTextInputState, then passed to + // GameTextInput. + OwnedGameTextInputState gameTextInputState; + std::mutex gameTextInputStateMutex; - ARect insetsState[GAMECOMMON_INSETS_TYPE_COUNT]; - bool softwareKeyboardVisible; + ARect insetsState[GAMECOMMON_INSETS_TYPE_COUNT]; + bool softwareKeyboardVisible; }; -static void readConfigurationValues(NativeCode *code, jobject javaConfig); +static void readConfigurationValues(NativeCode* code, jobject javaConfig); -extern "C" void GameActivity_finish(GameActivity *activity) { - NativeCode *code = static_cast(activity); - write_work(code->mainWorkWrite, CMD_FINISH, 0); +extern "C" void GameActivity_finish(GameActivity* activity) { + NativeCode* code = static_cast(activity); + write_work(code->mainWorkWrite, CMD_FINISH, 0); } -extern "C" void GameActivity_setWindowFlags(GameActivity *activity, - uint32_t values, uint32_t mask) { - NativeCode *code = static_cast(activity); - write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask); +extern "C" void GameActivity_setWindowFlags(GameActivity* activity, uint32_t values, + uint32_t mask) { + NativeCode* code = static_cast(activity); + write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask); } -extern "C" void GameActivity_showSoftInput(GameActivity *activity, - uint32_t flags) { - NativeCode *code = static_cast(activity); - write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags); +extern "C" void GameActivity_showSoftInput(GameActivity* activity, uint32_t flags) { + NativeCode* code = static_cast(activity); + write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags); } -extern "C" void GameActivity_restartInput(GameActivity *activity) { - NativeCode *code = static_cast(activity); - write_work(code->mainWorkWrite, CMD_RESTART_INPUT); +extern "C" void GameActivity_restartInput(GameActivity* activity) { + NativeCode* code = static_cast(activity); + write_work(code->mainWorkWrite, CMD_RESTART_INPUT); } -extern "C" void GameActivity_setTextInputState( - GameActivity *activity, const GameTextInputState *state) { - NativeCode *code = static_cast(activity); - std::lock_guard lock(code->gameTextInputStateMutex); - code->gameTextInputState = *state; - write_work(code->mainWorkWrite, CMD_SET_SOFT_INPUT_STATE); +extern "C" void GameActivity_setTextInputState(GameActivity* activity, + const GameTextInputState* state) { + NativeCode* code = static_cast(activity); + std::lock_guard lock(code->gameTextInputStateMutex); + code->gameTextInputState = *state; + write_work(code->mainWorkWrite, CMD_SET_SOFT_INPUT_STATE); } -extern "C" void GameActivity_getTextInputState( - GameActivity *activity, GameTextInputGetStateCallback callback, - void *context) { - NativeCode *code = static_cast(activity); - return GameTextInput_getState(code->gameTextInput, callback, context); +extern "C" void GameActivity_getTextInputState(GameActivity* activity, + GameTextInputGetStateCallback callback, + void* context) { + NativeCode* code = static_cast(activity); + return GameTextInput_getState(code->gameTextInput, callback, context); } -extern "C" void GameActivity_hideSoftInput(GameActivity *activity, - uint32_t flags) { - NativeCode *code = static_cast(activity); - write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags); +extern "C" void GameActivity_hideSoftInput(GameActivity* activity, uint32_t flags) { + NativeCode* code = static_cast(activity); + write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags); } -extern "C" void GameActivity_getWindowInsets(GameActivity *activity, - GameCommonInsetsType type, - ARect *insets) { - if (type < 0 || type >= GAMECOMMON_INSETS_TYPE_COUNT) return; - NativeCode *code = static_cast(activity); - *insets = code->insetsState[type]; +extern "C" void GameActivity_getWindowInsets(GameActivity* activity, GameCommonInsetsType type, + ARect* insets) { + if (type < 0 || type >= GAMECOMMON_INSETS_TYPE_COUNT) return; + NativeCode* code = static_cast(activity); + *insets = code->insetsState[type]; } -extern "C" bool GameActivity_isSoftwareKeyboardVisible(GameActivity *activity) { - NativeCode *code = static_cast(activity); - return code->softwareKeyboardVisible; +extern "C" bool GameActivity_isSoftwareKeyboardVisible(GameActivity* activity) { + NativeCode* code = static_cast(activity); + return code->softwareKeyboardVisible; } -extern "C" GameTextInput *GameActivity_getTextInput( - const GameActivity *activity) { - const NativeCode *code = static_cast(activity); - return code->gameTextInput; +extern "C" GameTextInput* GameActivity_getTextInput(const GameActivity* activity) { + const NativeCode* code = static_cast(activity); + return code->gameTextInput; } /* * Log the JNI exception, if any. */ -static void checkAndClearException(JNIEnv *env, const char *methodName) { - if (env->ExceptionCheck()) { - ALOGE("Exception while running %s", methodName); - env->ExceptionDescribe(); - env->ExceptionClear(); - } +static void checkAndClearException(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + ALOGE("Exception while running %s", methodName); + env->ExceptionDescribe(); + env->ExceptionClear(); + } } /* * Callback for handling native events on the application's main thread. */ -static int mainWorkCallback(int fd, int events, void *data) { - ALOGD("************** mainWorkCallback *********"); - NativeCode *code = (NativeCode *)data; - if ((events & POLLIN) == 0) { - return 1; - } +static int mainWorkCallback(int fd, int events, void* data) { + ALOGD("************** mainWorkCallback *********"); + NativeCode* code = (NativeCode*)data; + if ((events & POLLIN) == 0) { + return 1; + } + + ActivityWork work; + if (!read_work(code->mainWorkRead, &work)) { + return 1; + } + LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd); + switch (work.cmd) { + case CMD_FINISH: { + code->env->CallVoidMethod(code->javaGameActivity, gGameActivityClassInfo.finish); + checkAndClearException(code->env, "finish"); + } break; + case CMD_SET_WINDOW_FLAGS: { + code->env->CallVoidMethod(code->javaGameActivity, gGameActivityClassInfo.setWindowFlags, + static_cast(work.arg1), static_cast(work.arg2)); + checkAndClearException(code->env, "setWindowFlags"); + } break; + case CMD_SHOW_SOFT_INPUT: { + GameTextInput_showIme(code->gameTextInput, work.arg1); + } break; + case CMD_SET_SOFT_INPUT_STATE: { + std::lock_guard lock(code->gameTextInputStateMutex); + GameTextInput_setState(code->gameTextInput, &code->gameTextInputState.inner); + checkAndClearException(code->env, "setTextInputState"); + } break; + case CMD_HIDE_SOFT_INPUT: { + GameTextInput_hideIme(code->gameTextInput, work.arg1); + } break; + case CMD_SET_IME_EDITOR_INFO: { + code->env->CallVoidMethod(code->javaGameActivity, + gGameActivityClassInfo.setImeEditorInfoFields, + static_cast(work.arg1), static_cast(work.arg2), + static_cast(work.arg3)); + checkAndClearException(code->env, "setImeEditorInfo"); + } break; + case CMD_RESTART_INPUT: { + GameTextInput_restartInput(code->gameTextInput); + } break; + default: + ALOGW("Unknown work command: %d", work.cmd); + break; + } - ActivityWork work; - if (!read_work(code->mainWorkRead, &work)) { return 1; - } - LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd); - switch (work.cmd) { - case CMD_FINISH: { - code->env->CallVoidMethod(code->javaGameActivity, - gGameActivityClassInfo.finish); - checkAndClearException(code->env, "finish"); - } break; - case CMD_SET_WINDOW_FLAGS: { - code->env->CallVoidMethod( - code->javaGameActivity, gGameActivityClassInfo.setWindowFlags, - static_cast(work.arg1), static_cast(work.arg2)); - checkAndClearException(code->env, "setWindowFlags"); - } break; - case CMD_SHOW_SOFT_INPUT: { - GameTextInput_showIme(code->gameTextInput, work.arg1); - } break; - case CMD_SET_SOFT_INPUT_STATE: { - std::lock_guard lock(code->gameTextInputStateMutex); - GameTextInput_setState(code->gameTextInput, - &code->gameTextInputState.inner); - checkAndClearException(code->env, "setTextInputState"); - } break; - case CMD_HIDE_SOFT_INPUT: { - GameTextInput_hideIme(code->gameTextInput, work.arg1); - } break; - case CMD_SET_IME_EDITOR_INFO: { - code->env->CallVoidMethod( - code->javaGameActivity, gGameActivityClassInfo.setImeEditorInfoFields, - static_cast(work.arg1), static_cast(work.arg2), - static_cast(work.arg3)); - checkAndClearException(code->env, "setImeEditorInfo"); - } break; - case CMD_RESTART_INPUT: { - GameTextInput_restartInput(code->gameTextInput); - } break; - default: - ALOGW("Unknown work command: %d", work.cmd); - break; - } - - return 1; } // ------------------------------------------------------------------------ static thread_local std::string g_error_msg; -static jlong initializeNativeCode_native( - JNIEnv *env, jobject javaGameActivity, jstring internalDataDir, - jstring obbDir, jstring externalDataDir, jobject jAssetMgr, - jbyteArray savedState, jobject javaConfig) { - LOG_TRACE("initializeNativeCode_native"); - NativeCode *code = NULL; +static jlong initializeNativeCode_native(JNIEnv* env, jobject javaGameActivity, + jstring internalDataDir, jstring obbDir, + jstring externalDataDir, jobject jAssetMgr, + jbyteArray savedState, jobject javaConfig) { + LOG_TRACE("initializeNativeCode_native"); + NativeCode* code = NULL; + + code = new NativeCode(); + + code->looper = ALooper_forThread(); + if (code->looper == nullptr) { + g_error_msg = "Unable to retrieve native ALooper"; + ALOGW("%s", g_error_msg.c_str()); + delete code; + return 0; + } + ALooper_acquire(code->looper); - code = new NativeCode(); + int msgpipe[2]; + if (pipe(msgpipe)) { + g_error_msg = "could not create pipe: "; + g_error_msg += strerror(errno); - code->looper = ALooper_forThread(); - if (code->looper == nullptr) { - g_error_msg = "Unable to retrieve native ALooper"; - ALOGW("%s", g_error_msg.c_str()); - delete code; - return 0; - } - ALooper_acquire(code->looper); + ALOGW("%s", g_error_msg.c_str()); + delete code; + return 0; + } + code->mainWorkRead = msgpipe[0]; + code->mainWorkWrite = msgpipe[1]; + int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK); + SLOGW_IF(result != 0, + "Could not make main work read pipe " + "non-blocking: %s", + strerror(errno)); + result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); + SLOGW_IF(result != 0, + "Could not make main work write pipe " + "non-blocking: %s", + strerror(errno)); + ALooper_addFd(code->looper, code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); + + code->GameActivity::callbacks = &code->callbacks; + if (env->GetJavaVM(&code->vm) < 0) { + ALOGW("GameActivity GetJavaVM failed"); + delete code; + return 0; + } + code->env = env; + code->javaGameActivity = env->NewGlobalRef(javaGameActivity); + + const char* dirStr = internalDataDir ? env->GetStringUTFChars(internalDataDir, NULL) : ""; + code->internalDataPathObj = dirStr; + code->internalDataPath = code->internalDataPathObj.c_str(); + if (internalDataDir) env->ReleaseStringUTFChars(internalDataDir, dirStr); + + dirStr = externalDataDir ? env->GetStringUTFChars(externalDataDir, NULL) : ""; + code->externalDataPathObj = dirStr; + code->externalDataPath = code->externalDataPathObj.c_str(); + if (externalDataDir) env->ReleaseStringUTFChars(externalDataDir, dirStr); + + code->javaAssetManager = env->NewGlobalRef(jAssetMgr); + code->assetManager = AAssetManager_fromJava(env, jAssetMgr); + + dirStr = obbDir ? env->GetStringUTFChars(obbDir, NULL) : ""; + code->obbPathObj = dirStr; + code->obbPath = code->obbPathObj.c_str(); + if (obbDir) env->ReleaseStringUTFChars(obbDir, dirStr); + + jbyte* rawSavedState = NULL; + jsize rawSavedSize = 0; + if (savedState != NULL) { + rawSavedState = env->GetByteArrayElements(savedState, NULL); + rawSavedSize = env->GetArrayLength(savedState); + } - int msgpipe[2]; - if (pipe(msgpipe)) { - g_error_msg = "could not create pipe: "; - g_error_msg += strerror(errno); + // read configuration for the first time + readConfigurationValues(code, javaConfig); - ALOGW("%s", g_error_msg.c_str()); - delete code; - return 0; - } - code->mainWorkRead = msgpipe[0]; - code->mainWorkWrite = msgpipe[1]; - int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK); - SLOGW_IF(result != 0, - "Could not make main work read pipe " - "non-blocking: %s", - strerror(errno)); - result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); - SLOGW_IF(result != 0, - "Could not make main work write pipe " - "non-blocking: %s", - strerror(errno)); - ALooper_addFd(code->looper, code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, - mainWorkCallback, code); - - code->GameActivity::callbacks = &code->callbacks; - if (env->GetJavaVM(&code->vm) < 0) { - ALOGW("GameActivity GetJavaVM failed"); - delete code; - return 0; - } - code->env = env; - code->javaGameActivity = env->NewGlobalRef(javaGameActivity); - - const char *dirStr = - internalDataDir ? env->GetStringUTFChars(internalDataDir, NULL) : ""; - code->internalDataPathObj = dirStr; - code->internalDataPath = code->internalDataPathObj.c_str(); - if (internalDataDir) env->ReleaseStringUTFChars(internalDataDir, dirStr); - - dirStr = externalDataDir ? env->GetStringUTFChars(externalDataDir, NULL) : ""; - code->externalDataPathObj = dirStr; - code->externalDataPath = code->externalDataPathObj.c_str(); - if (externalDataDir) env->ReleaseStringUTFChars(externalDataDir, dirStr); - - code->javaAssetManager = env->NewGlobalRef(jAssetMgr); - code->assetManager = AAssetManager_fromJava(env, jAssetMgr); - - dirStr = obbDir ? env->GetStringUTFChars(obbDir, NULL) : ""; - code->obbPathObj = dirStr; - code->obbPath = code->obbPathObj.c_str(); - if (obbDir) env->ReleaseStringUTFChars(obbDir, dirStr); - - jbyte *rawSavedState = NULL; - jsize rawSavedSize = 0; - if (savedState != NULL) { - rawSavedState = env->GetByteArrayElements(savedState, NULL); - rawSavedSize = env->GetArrayLength(savedState); - } - - // read configuration for the first time - readConfigurationValues(code, javaConfig); - - GameActivity_onCreate(code, rawSavedState, rawSavedSize); - - code->gameTextInput = GameTextInput_init(env, 0); - GameTextInput_setEventCallback(code->gameTextInput, - reinterpret_cast( - code->callbacks.onTextInputEvent), - code); - - if (rawSavedState != NULL) { - env->ReleaseByteArrayElements(savedState, rawSavedState, 0); - } - - return reinterpret_cast(code); -} - -static jstring getDlError_native(JNIEnv *env, jobject javaGameActivity) { - jstring result = env->NewStringUTF(g_error_msg.c_str()); - g_error_msg.clear(); - return result; -} - -static void terminateNativeCode_native(JNIEnv *env, jobject javaGameActivity, - jlong handle) { - LOG_TRACE("terminateNativeCode_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - delete code; - } -} - -static void onStart_native(JNIEnv *env, jobject javaGameActivity, - jlong handle) { - ALOGV("onStart_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onStart != NULL) { - code->callbacks.onStart(code); + GameActivity_onCreate(code, rawSavedState, rawSavedSize); + + code->gameTextInput = GameTextInput_init(env, 0); + GameTextInput_setEventCallback(code->gameTextInput, + reinterpret_cast( + code->callbacks.onTextInputEvent), + code); + + if (rawSavedState != NULL) { + env->ReleaseByteArrayElements(savedState, rawSavedState, 0); } - } + + return reinterpret_cast(code); +} + +static jstring getDlError_native(JNIEnv* env, jobject javaGameActivity) { + jstring result = env->NewStringUTF(g_error_msg.c_str()); + g_error_msg.clear(); + return result; } -static void onResume_native(JNIEnv *env, jobject javaGameActivity, - jlong handle) { - LOG_TRACE("onResume_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onResume != NULL) { - code->callbacks.onResume(code); +static void terminateNativeCode_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("terminateNativeCode_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + delete code; + } +} + +static void onStart_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + ALOGV("onStart_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStart != NULL) { + code->callbacks.onStart(code); + } + } +} + +static void onResume_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("onResume_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onResume != NULL) { + code->callbacks.onResume(code); + } } - } } struct SaveInstanceLocals { - JNIEnv *env; - jbyteArray array; + JNIEnv* env; + jbyteArray array; }; -static jbyteArray onSaveInstanceState_native(JNIEnv *env, - jobject javaGameActivity, - jlong handle) { - LOG_TRACE("onSaveInstanceState_native"); - - SaveInstanceLocals locals{ - env, NULL}; // Passed through the user's state prep function. - - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onSaveInstanceState != NULL) { - code->callbacks.onSaveInstanceState( - code, - [](const char *bytes, int len, void *context) { - auto locals = static_cast(context); - if (len > 0) { - locals->array = locals->env->NewByteArray(len); - if (locals->array != NULL) { - locals->env->SetByteArrayRegion(locals->array, 0, len, - (const jbyte *)bytes); - } - } - }, - &locals); +static jbyteArray onSaveInstanceState_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("onSaveInstanceState_native"); + + SaveInstanceLocals locals{env, NULL}; // Passed through the user's state prep function. + + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onSaveInstanceState != NULL) { + code->callbacks.onSaveInstanceState( + code, + [](const char* bytes, int len, void* context) { + auto locals = static_cast(context); + if (len > 0) { + locals->array = locals->env->NewByteArray(len); + if (locals->array != NULL) { + locals->env->SetByteArrayRegion(locals->array, 0, len, + (const jbyte*)bytes); + } + } + }, + &locals); + } } - } - return locals.array; + return locals.array; } -static void onPause_native(JNIEnv *env, jobject javaGameActivity, - jlong handle) { - LOG_TRACE("onPause_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onPause != NULL) { - code->callbacks.onPause(code); +static void onPause_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("onPause_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onPause != NULL) { + code->callbacks.onPause(code); + } } - } } -static void onStop_native(JNIEnv *env, jobject javaGameActivity, jlong handle) { - LOG_TRACE("onStop_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onStop != NULL) { - code->callbacks.onStop(code); - } - } -} - -static std::string getStringField(JNIEnv *env, jobject obj, jmethodID method) { - jstring str = (jstring)env->CallObjectMethod(obj, method); - const char *chars = env->GetStringUTFChars(str, NULL); - std::string res(chars); - env->ReleaseStringUTFChars(str, chars); - checkAndClearException(env, "getStringField"); - return res; -} - -static void readConfigurationValues(NativeCode *code, jobject javaConfig) { - const std::lock_guard lock(gConfigMutex); - - if (gConfigurationClassInfo.colorMode != NULL) { - gConfiguration.colorMode = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.colorMode); - } - - gConfiguration.densityDpi = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.densityDpi); - gConfiguration.fontScale = - code->env->GetFloatField(javaConfig, gConfigurationClassInfo.fontScale); - - if (gConfigurationClassInfo.fontWeightAdjustment != NULL) { - gConfiguration.fontWeightAdjustment = code->env->GetIntField( - javaConfig, gConfigurationClassInfo.fontWeightAdjustment); - } - - gConfiguration.hardKeyboardHidden = code->env->GetIntField( - javaConfig, gConfigurationClassInfo.hardKeyboardHidden); - gConfiguration.keyboard = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.keyboard); - gConfiguration.keyboardHidden = code->env->GetIntField( - javaConfig, gConfigurationClassInfo.keyboardHidden); - gConfiguration.mcc = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.mcc); - gConfiguration.mnc = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.mnc); - gConfiguration.navigation = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.navigation); - gConfiguration.navigationHidden = code->env->GetIntField( - javaConfig, gConfigurationClassInfo.navigationHidden); - gConfiguration.orientation = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.orientation); - gConfiguration.screenHeightDp = code->env->GetIntField( - javaConfig, gConfigurationClassInfo.screenHeightDp); - gConfiguration.screenLayout = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.screenLayout); - gConfiguration.screenWidthDp = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.screenWidthDp); - gConfiguration.smallestScreenWidthDp = code->env->GetIntField( - javaConfig, gConfigurationClassInfo.smallestScreenWidthDp); - gConfiguration.touchscreen = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.touchscreen); - gConfiguration.uiMode = - code->env->GetIntField(javaConfig, gConfigurationClassInfo.uiMode); - - checkAndClearException(code->env, "Configuration.get"); - - jobject locales = code->env->CallObjectMethod( - javaConfig, gConfigurationClassInfo.getLocales); - checkAndClearException(code->env, "getLocales"); - - int localesCount = - code->env->CallIntMethod(locales, gLocaleListClassInfo.size); - checkAndClearException(code->env, "size"); - gConfiguration.locales.resize(localesCount); - - // extract the data for every locale - for (int i = 0; i < localesCount; ++i) { - Locale &locale = gConfiguration.locales[i]; - - // get locale object from the array - jobject jniLocale = - code->env->CallObjectMethod(locales, gLocaleListClassInfo.get, i); - checkAndClearException(code->env, "GetObjectArrayElement"); - - // get data strings for this locale - locale.language = - getStringField(code->env, jniLocale, gLocaleClassInfo.getLanguage); - locale.script = - getStringField(code->env, jniLocale, gLocaleClassInfo.getScript); - locale.country = - getStringField(code->env, jniLocale, gLocaleClassInfo.getCountry); - locale.variant = - getStringField(code->env, jniLocale, gLocaleClassInfo.getVariant); - } -} - -static void onConfigurationChanged_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jobject javaNewConfig) { - LOG_TRACE("onConfigurationChanged_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - readConfigurationValues(code, javaNewConfig); - - if (code->callbacks.onConfigurationChanged != NULL) { - code->callbacks.onConfigurationChanged(code); +static void onStop_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("onStop_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStop != NULL) { + code->callbacks.onStop(code); + } } - } } -static void onTrimMemory_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jint level) { - LOG_TRACE("onTrimMemory_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onTrimMemory != NULL) { - code->callbacks.onTrimMemory(code, level); - } - } +static std::string getStringField(JNIEnv* env, jobject obj, jmethodID method) { + jstring str = (jstring)env->CallObjectMethod(obj, method); + const char* chars = env->GetStringUTFChars(str, NULL); + std::string res(chars); + env->ReleaseStringUTFChars(str, chars); + checkAndClearException(env, "getStringField"); + return res; } -static void onWindowFocusChanged_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jboolean focused) { - LOG_TRACE("onWindowFocusChanged_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onWindowFocusChanged != NULL) { - code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0); +static void readConfigurationValues(NativeCode* code, jobject javaConfig) { + const std::lock_guard lock(gConfigMutex); + + if (gConfigurationClassInfo.colorMode != NULL) { + gConfiguration.colorMode = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.colorMode); + } + + gConfiguration.densityDpi = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.densityDpi); + gConfiguration.fontScale = + code->env->GetFloatField(javaConfig, gConfigurationClassInfo.fontScale); + + if (gConfigurationClassInfo.fontWeightAdjustment != NULL) { + gConfiguration.fontWeightAdjustment = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.fontWeightAdjustment); + } + + gConfiguration.hardKeyboardHidden = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.hardKeyboardHidden); + gConfiguration.keyboard = code->env->GetIntField(javaConfig, gConfigurationClassInfo.keyboard); + gConfiguration.keyboardHidden = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.keyboardHidden); + gConfiguration.mcc = code->env->GetIntField(javaConfig, gConfigurationClassInfo.mcc); + gConfiguration.mnc = code->env->GetIntField(javaConfig, gConfigurationClassInfo.mnc); + gConfiguration.navigation = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.navigation); + gConfiguration.navigationHidden = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.navigationHidden); + gConfiguration.orientation = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.orientation); + gConfiguration.screenHeightDp = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.screenHeightDp); + gConfiguration.screenLayout = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.screenLayout); + gConfiguration.screenWidthDp = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.screenWidthDp); + gConfiguration.smallestScreenWidthDp = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.smallestScreenWidthDp); + gConfiguration.touchscreen = + code->env->GetIntField(javaConfig, gConfigurationClassInfo.touchscreen); + gConfiguration.uiMode = code->env->GetIntField(javaConfig, gConfigurationClassInfo.uiMode); + + checkAndClearException(code->env, "Configuration.get"); + + jobject locales = code->env->CallObjectMethod(javaConfig, gConfigurationClassInfo.getLocales); + checkAndClearException(code->env, "getLocales"); + + int localesCount = code->env->CallIntMethod(locales, gLocaleListClassInfo.size); + checkAndClearException(code->env, "size"); + gConfiguration.locales.resize(localesCount); + + // extract the data for every locale + for (int i = 0; i < localesCount; ++i) { + Locale& locale = gConfiguration.locales[i]; + + // get locale object from the array + jobject jniLocale = code->env->CallObjectMethod(locales, gLocaleListClassInfo.get, i); + checkAndClearException(code->env, "GetObjectArrayElement"); + + // get data strings for this locale + locale.language = getStringField(code->env, jniLocale, gLocaleClassInfo.getLanguage); + locale.script = getStringField(code->env, jniLocale, gLocaleClassInfo.getScript); + locale.country = getStringField(code->env, jniLocale, gLocaleClassInfo.getCountry); + locale.variant = getStringField(code->env, jniLocale, gLocaleClassInfo.getVariant); } - } } -static void onSurfaceCreated_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jobject surface) { - ALOGV("onSurfaceCreated_native"); - LOG_TRACE("onSurfaceCreated_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - code->setSurface(surface); +static void onConfigurationChanged_native(JNIEnv* env, jobject javaGameActivity, jlong handle, + jobject javaNewConfig) { + LOG_TRACE("onConfigurationChanged_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + readConfigurationValues(code, javaNewConfig); - if (code->nativeWindow != NULL && - code->callbacks.onNativeWindowCreated != NULL) { - code->callbacks.onNativeWindowCreated(code, code->nativeWindow); + if (code->callbacks.onConfigurationChanged != NULL) { + code->callbacks.onConfigurationChanged(code); + } } - } -} - -static void onSurfaceChanged_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jobject surface, jint format, - jint width, jint height) { - LOG_TRACE("onSurfaceChanged_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - ANativeWindow *oldNativeWindow = code->nativeWindow; - // Fix for window being destroyed behind the scenes on older Android - // versions. - if (oldNativeWindow != NULL) { - ANativeWindow_acquire(oldNativeWindow); +} + +static void onTrimMemory_native(JNIEnv* env, jobject javaGameActivity, jlong handle, jint level) { + LOG_TRACE("onTrimMemory_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onTrimMemory != NULL) { + code->callbacks.onTrimMemory(code, level); + } } - code->setSurface(surface); - if (oldNativeWindow != code->nativeWindow) { - if (oldNativeWindow != NULL && - code->callbacks.onNativeWindowDestroyed != NULL) { - code->callbacks.onNativeWindowDestroyed(code, oldNativeWindow); - } - if (code->nativeWindow != NULL) { - if (code->callbacks.onNativeWindowCreated != NULL) { - code->callbacks.onNativeWindowCreated(code, code->nativeWindow); +} + +static void onWindowFocusChanged_native(JNIEnv* env, jobject javaGameActivity, jlong handle, + jboolean focused) { + LOG_TRACE("onWindowFocusChanged_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onWindowFocusChanged != NULL) { + code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0); } + } +} - code->lastWindowWidth = ANativeWindow_getWidth(code->nativeWindow); - code->lastWindowHeight = ANativeWindow_getHeight(code->nativeWindow); - } - } else { - // Maybe it was resized? - int32_t newWidth = ANativeWindow_getWidth(code->nativeWindow); - int32_t newHeight = ANativeWindow_getHeight(code->nativeWindow); - - if (newWidth != code->lastWindowWidth || - newHeight != code->lastWindowHeight) { - code->lastWindowWidth = newWidth; - code->lastWindowHeight = newHeight; - - if (code->callbacks.onNativeWindowResized != NULL) { - code->callbacks.onNativeWindowResized(code, code->nativeWindow, - newWidth, newHeight); +static void onSurfaceCreated_native(JNIEnv* env, jobject javaGameActivity, jlong handle, + jobject surface) { + ALOGV("onSurfaceCreated_native"); + LOG_TRACE("onSurfaceCreated_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + code->setSurface(surface); + + if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) { + code->callbacks.onNativeWindowCreated(code, code->nativeWindow); } - } } - // Release the window we acquired earlier. - if (oldNativeWindow != NULL) { - ANativeWindow_release(oldNativeWindow); +} + +static void onSurfaceChanged_native(JNIEnv* env, jobject javaGameActivity, jlong handle, + jobject surface, jint format, jint width, jint height) { + LOG_TRACE("onSurfaceChanged_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + ANativeWindow* oldNativeWindow = code->nativeWindow; + // Fix for window being destroyed behind the scenes on older Android + // versions. + if (oldNativeWindow != NULL) { + ANativeWindow_acquire(oldNativeWindow); + } + code->setSurface(surface); + if (oldNativeWindow != code->nativeWindow) { + if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { + code->callbacks.onNativeWindowDestroyed(code, oldNativeWindow); + } + if (code->nativeWindow != NULL) { + if (code->callbacks.onNativeWindowCreated != NULL) { + code->callbacks.onNativeWindowCreated(code, code->nativeWindow); + } + + code->lastWindowWidth = ANativeWindow_getWidth(code->nativeWindow); + code->lastWindowHeight = ANativeWindow_getHeight(code->nativeWindow); + } + } else { + // Maybe it was resized? + int32_t newWidth = ANativeWindow_getWidth(code->nativeWindow); + int32_t newHeight = ANativeWindow_getHeight(code->nativeWindow); + + if (newWidth != code->lastWindowWidth || newHeight != code->lastWindowHeight) { + code->lastWindowWidth = newWidth; + code->lastWindowHeight = newHeight; + + if (code->callbacks.onNativeWindowResized != NULL) { + code->callbacks.onNativeWindowResized(code, code->nativeWindow, newWidth, + newHeight); + } + } + } + // Release the window we acquired earlier. + if (oldNativeWindow != NULL) { + ANativeWindow_release(oldNativeWindow); + } } - } } -static void onSurfaceRedrawNeeded_native(JNIEnv *env, jobject javaGameActivity, - jlong handle) { - LOG_TRACE("onSurfaceRedrawNeeded_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->nativeWindow != NULL && - code->callbacks.onNativeWindowRedrawNeeded != NULL) { - code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow); +static void onSurfaceRedrawNeeded_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("onSurfaceRedrawNeeded_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) { + code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow); + } } - } } -static void onSurfaceDestroyed_native(JNIEnv *env, jobject javaGameActivity, - jlong handle) { - LOG_TRACE("onSurfaceDestroyed_native"); - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - if (code->nativeWindow != NULL && - code->callbacks.onNativeWindowDestroyed != NULL) { - code->callbacks.onNativeWindowDestroyed(code, code->nativeWindow); +static void onSurfaceDestroyed_native(JNIEnv* env, jobject javaGameActivity, jlong handle) { + LOG_TRACE("onSurfaceDestroyed_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { + code->callbacks.onNativeWindowDestroyed(code, code->nativeWindow); + } + code->setSurface(NULL); } - code->setSurface(NULL); - } } -extern "C" void GameActivity_setImeEditorInfo( - GameActivity *activity, GameTextInputType inputType, - GameTextInputActionType actionId, GameTextInputImeOptions imeOptions) { - NativeCode *code = static_cast(activity); - write_work(code->mainWorkWrite, CMD_SET_IME_EDITOR_INFO, inputType, actionId, - imeOptions); +extern "C" void GameActivity_setImeEditorInfo(GameActivity* activity, GameTextInputType inputType, + GameTextInputActionType actionId, + GameTextInputImeOptions imeOptions) { + NativeCode* code = static_cast(activity); + write_work(code->mainWorkWrite, CMD_SET_IME_EDITOR_INFO, inputType, actionId, imeOptions); } -extern "C" int GameActivity_getColorMode(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.colorMode; +extern "C" int GameActivity_getColorMode(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.colorMode; } -extern "C" int GameActivity_getDensityDpi(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.densityDpi; +extern "C" int GameActivity_getDensityDpi(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.densityDpi; } -extern "C" float GameActivity_getFontScale(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.fontScale; +extern "C" float GameActivity_getFontScale(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.fontScale; } -extern "C" int GameActivity_getFontWeightAdjustment(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.fontWeightAdjustment; +extern "C" int GameActivity_getFontWeightAdjustment(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.fontWeightAdjustment; } -extern "C" int GameActivity_getHardKeyboardHidden(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.hardKeyboardHidden; +extern "C" int GameActivity_getHardKeyboardHidden(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.hardKeyboardHidden; } -extern "C" int GameActivity_getKeyboard(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.keyboard; +extern "C" int GameActivity_getKeyboard(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.keyboard; } -extern "C" int GameActivity_getKeyboardHidden(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.keyboardHidden; +extern "C" int GameActivity_getKeyboardHidden(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.keyboardHidden; } -extern "C" int GameActivity_getLocalesCount(GameActivity *activity) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.locales.size(); +extern "C" int GameActivity_getLocalesCount(GameActivity* activity) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.locales.size(); } -extern "C" int GameActivity_getMcc(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.mcc; +extern "C" int GameActivity_getMcc(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.mcc; } -extern "C" int GameActivity_getMnc(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.mnc; +extern "C" int GameActivity_getMnc(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.mnc; } -extern "C" int GameActivity_getNavigation(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.navigation; +extern "C" int GameActivity_getNavigation(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.navigation; } -extern "C" int GameActivity_getNavigationHidden(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.navigationHidden; +extern "C" int GameActivity_getNavigationHidden(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.navigationHidden; } -extern "C" int GameActivity_getOrientation(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.orientation; +extern "C" int GameActivity_getOrientation(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.orientation; } -extern "C" int GameActivity_getScreenHeightDp(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.screenHeightDp; +extern "C" int GameActivity_getScreenHeightDp(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.screenHeightDp; } -extern "C" int GameActivity_getScreenLayout(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.screenLayout; +extern "C" int GameActivity_getScreenLayout(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.screenLayout; } -extern "C" int GameActivity_getScreenWidthDp(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.screenWidthDp; +extern "C" int GameActivity_getScreenWidthDp(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.screenWidthDp; } -extern "C" int GameActivity_getSmallestScreenWidthDp(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.smallestScreenWidthDp; +extern "C" int GameActivity_getSmallestScreenWidthDp(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.smallestScreenWidthDp; } -extern "C" int GameActivity_getTouchscreen(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.touchscreen; +extern "C" int GameActivity_getTouchscreen(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.touchscreen; } -extern "C" int GameActivity_getUIMode(GameActivity *) { - const std::lock_guard lock(gConfigMutex); - return gConfiguration.uiMode; +extern "C" int GameActivity_getUIMode(GameActivity*) { + const std::lock_guard lock(gConfigMutex); + return gConfiguration.uiMode; } -static int copyStringIfFits(char *dst, size_t dst_size, const std::string &s) { - if (dst_size <= s.size()) { - return ENOBUFS; - } +static int copyStringIfFits(char* dst, size_t dst_size, const std::string& s) { + if (dst_size <= s.size()) { + return ENOBUFS; + } - strcpy(dst, s.c_str()); - return 0; + strcpy(dst, s.c_str()); + return 0; } -extern "C" int GameActivity_getLocaleLanguage(char *dst, size_t dst_size, - GameActivity *activity, +extern "C" int GameActivity_getLocaleLanguage(char* dst, size_t dst_size, GameActivity* activity, size_t localeIdx) { - const std::lock_guard lock(gConfigMutex); + const std::lock_guard lock(gConfigMutex); - if (localeIdx >= gConfiguration.locales.size()) { - return EINVAL; - } + if (localeIdx >= gConfiguration.locales.size()) { + return EINVAL; + } - return copyStringIfFits(dst, dst_size, - gConfiguration.locales[localeIdx].language); + return copyStringIfFits(dst, dst_size, gConfiguration.locales[localeIdx].language); } -extern "C" int GameActivity_getLocaleScript(char *dst, size_t dst_size, - GameActivity *activity, +extern "C" int GameActivity_getLocaleScript(char* dst, size_t dst_size, GameActivity* activity, size_t localeIdx) { - const std::lock_guard lock(gConfigMutex); + const std::lock_guard lock(gConfigMutex); - if (localeIdx >= gConfiguration.locales.size()) { - return EINVAL; - } + if (localeIdx >= gConfiguration.locales.size()) { + return EINVAL; + } - return copyStringIfFits(dst, dst_size, - gConfiguration.locales[localeIdx].script); + return copyStringIfFits(dst, dst_size, gConfiguration.locales[localeIdx].script); } -extern "C" int GameActivity_getLocaleCountry(char *dst, size_t dst_size, - GameActivity *activity, +extern "C" int GameActivity_getLocaleCountry(char* dst, size_t dst_size, GameActivity* activity, size_t localeIdx) { - const std::lock_guard lock(gConfigMutex); + const std::lock_guard lock(gConfigMutex); - if (localeIdx >= gConfiguration.locales.size()) { - return EINVAL; - } + if (localeIdx >= gConfiguration.locales.size()) { + return EINVAL; + } - return copyStringIfFits(dst, dst_size, - gConfiguration.locales[localeIdx].country); + return copyStringIfFits(dst, dst_size, gConfiguration.locales[localeIdx].country); } -extern "C" int GameActivity_getLocaleVariant(char *dst, size_t dst_size, - GameActivity *activity, +extern "C" int GameActivity_getLocaleVariant(char* dst, size_t dst_size, GameActivity* activity, size_t localeIdx) { - const std::lock_guard lock(gConfigMutex); + const std::lock_guard lock(gConfigMutex); - if (localeIdx >= gConfiguration.locales.size()) { - return EINVAL; - } + if (localeIdx >= gConfiguration.locales.size()) { + return EINVAL; + } - return copyStringIfFits(dst, dst_size, - gConfiguration.locales[localeIdx].variant); + return copyStringIfFits(dst, dst_size, gConfiguration.locales[localeIdx].variant); } -static bool onTouchEvent_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jobject motionEvent, - int pointerCount, int historySize, int deviceId, - int source, int action, int64_t eventTime, - int64_t downTime, int flags, int metaState, - int actionButton, int buttonState, - int classification, int edgeFlags, +static bool onTouchEvent_native(JNIEnv* env, jobject javaGameActivity, jlong handle, + jobject motionEvent, int pointerCount, int historySize, + int deviceId, int source, int action, int64_t eventTime, + int64_t downTime, int flags, int metaState, int actionButton, + int buttonState, int classification, int edgeFlags, float precisionX, float precisionY) { - if (handle == 0) return false; - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onTouchEvent == nullptr) return false; + if (handle == 0) return false; + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onTouchEvent == nullptr) return false; - static GameActivityMotionEvent c_event; + static GameActivityMotionEvent c_event; - c_event.deviceId = deviceId; - c_event.source = source; - c_event.action = action; + c_event.deviceId = deviceId; + c_event.source = source; + c_event.action = action; - c_event.eventTime = eventTime; - c_event.downTime = downTime; + c_event.eventTime = eventTime; + c_event.downTime = downTime; - c_event.flags = flags; - c_event.metaState = metaState; + c_event.flags = flags; + c_event.metaState = metaState; - c_event.actionButton = actionButton; - c_event.buttonState = buttonState; - c_event.classification = classification; - c_event.edgeFlags = edgeFlags; + c_event.actionButton = actionButton; + c_event.buttonState = buttonState; + c_event.classification = classification; + c_event.edgeFlags = edgeFlags; - c_event.precisionX = precisionX; - c_event.precisionY = precisionY; + c_event.precisionX = precisionX; + c_event.precisionY = precisionY; - GameActivityMotionEvent_fromJava(env, motionEvent, &c_event, pointerCount, - historySize); - return code->callbacks.onTouchEvent(code, &c_event); + GameActivityMotionEvent_fromJava(env, motionEvent, &c_event, pointerCount, historySize); + return code->callbacks.onTouchEvent(code, &c_event); } -static bool onKeyUp_native(JNIEnv *env, jobject javaGameActivity, jlong handle, - jobject keyEvent) { - if (handle == 0) return false; - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onKeyUp == nullptr) return false; +static bool onKeyUp_native(JNIEnv* env, jobject javaGameActivity, jlong handle, jobject keyEvent) { + if (handle == 0) return false; + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onKeyUp == nullptr) return false; - static GameActivityKeyEvent c_event; - GameActivityKeyEvent_fromJava(env, keyEvent, &c_event); - return code->callbacks.onKeyUp(code, &c_event); + static GameActivityKeyEvent c_event; + GameActivityKeyEvent_fromJava(env, keyEvent, &c_event); + return code->callbacks.onKeyUp(code, &c_event); } -static bool onKeyDown_native(JNIEnv *env, jobject javaGameActivity, - jlong handle, jobject keyEvent) { - if (handle == 0) return false; - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onKeyDown == nullptr) return false; +static bool onKeyDown_native(JNIEnv* env, jobject javaGameActivity, jlong handle, + jobject keyEvent) { + if (handle == 0) return false; + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onKeyDown == nullptr) return false; - static GameActivityKeyEvent c_event; - GameActivityKeyEvent_fromJava(env, keyEvent, &c_event); - return code->callbacks.onKeyDown(code, &c_event); + static GameActivityKeyEvent c_event; + GameActivityKeyEvent_fromJava(env, keyEvent, &c_event); + return code->callbacks.onKeyDown(code, &c_event); } -static void onTextInput_native(JNIEnv *env, jobject activity, jlong handle, +static void onTextInput_native(JNIEnv* env, jobject activity, jlong handle, jobject textInputEvent) { - if (handle == 0) return; - NativeCode *code = (NativeCode *)handle; - GameTextInput_processEvent(code->gameTextInput, textInputEvent); -} - -static void onWindowInsetsChanged_native(JNIEnv *env, jobject activity, - jlong handle) { - if (handle == 0) return; - NativeCode *code = (NativeCode *)handle; - if (code->callbacks.onWindowInsetsChanged == nullptr) return; - for (int type = 0; type < GAMECOMMON_INSETS_TYPE_COUNT; ++type) { - jobject jinsets; - // Note that waterfall insets are handled differently on the Java side. - if (type == GAMECOMMON_INSETS_TYPE_WATERFALL) { - jinsets = env->CallObjectMethod( - code->javaGameActivity, gGameActivityClassInfo.getWaterfallInsets); - } else { - jint jtype = env->CallStaticIntMethod( - gWindowInsetsCompatTypeClassInfo.clazz, - gWindowInsetsCompatTypeClassInfo.methods[type]); - jinsets = - env->CallObjectMethod(code->javaGameActivity, - gGameActivityClassInfo.getWindowInsets, jtype); - } - ARect &insets = code->insetsState[type]; - if (jinsets == nullptr) { - insets.left = 0; - insets.right = 0; - insets.top = 0; - insets.bottom = 0; - } else { - insets.left = env->GetIntField(jinsets, gInsetsClassInfo.left); - insets.right = env->GetIntField(jinsets, gInsetsClassInfo.right); - insets.top = env->GetIntField(jinsets, gInsetsClassInfo.top); - insets.bottom = env->GetIntField(jinsets, gInsetsClassInfo.bottom); + if (handle == 0) return; + NativeCode* code = (NativeCode*)handle; + GameTextInput_processEvent(code->gameTextInput, textInputEvent); +} + +static void onWindowInsetsChanged_native(JNIEnv* env, jobject activity, jlong handle) { + if (handle == 0) return; + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onWindowInsetsChanged == nullptr) return; + for (int type = 0; type < GAMECOMMON_INSETS_TYPE_COUNT; ++type) { + jobject jinsets; + // Note that waterfall insets are handled differently on the Java side. + if (type == GAMECOMMON_INSETS_TYPE_WATERFALL) { + jinsets = env->CallObjectMethod(code->javaGameActivity, + gGameActivityClassInfo.getWaterfallInsets); + } else { + jint jtype = env->CallStaticIntMethod(gWindowInsetsCompatTypeClassInfo.clazz, + gWindowInsetsCompatTypeClassInfo.methods[type]); + jinsets = env->CallObjectMethod(code->javaGameActivity, + gGameActivityClassInfo.getWindowInsets, jtype); + } + ARect& insets = code->insetsState[type]; + if (jinsets == nullptr) { + insets.left = 0; + insets.right = 0; + insets.top = 0; + insets.bottom = 0; + } else { + insets.left = env->GetIntField(jinsets, gInsetsClassInfo.left); + insets.right = env->GetIntField(jinsets, gInsetsClassInfo.right); + insets.top = env->GetIntField(jinsets, gInsetsClassInfo.top); + insets.bottom = env->GetIntField(jinsets, gInsetsClassInfo.bottom); + } } - } - GameTextInput_processImeInsets( - code->gameTextInput, &code->insetsState[GAMECOMMON_INSETS_TYPE_IME]); - code->callbacks.onWindowInsetsChanged(code); -} - -static void setInputConnection_native(JNIEnv *env, jobject activity, - jlong handle, jobject inputConnection) { - NativeCode *code = (NativeCode *)handle; - GameTextInput_setInputConnection(code->gameTextInput, inputConnection); -} - -static void onContentRectChangedNative_native(JNIEnv *env, jobject activity, - jlong handle, jint x, jint y, - jint w, jint h) { - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - - if (code->callbacks.onContentRectChanged != nullptr) { - ARect rect; - rect.left = x; - rect.top = y; - rect.right = x + w; - rect.bottom = y + h; - code->callbacks.onContentRectChanged(code, &rect); + GameTextInput_processImeInsets(code->gameTextInput, + &code->insetsState[GAMECOMMON_INSETS_TYPE_IME]); + code->callbacks.onWindowInsetsChanged(code); +} + +static void setInputConnection_native(JNIEnv* env, jobject activity, jlong handle, + jobject inputConnection) { + NativeCode* code = (NativeCode*)handle; + GameTextInput_setInputConnection(code->gameTextInput, inputConnection); +} + +static void onContentRectChangedNative_native(JNIEnv* env, jobject activity, jlong handle, jint x, + jint y, jint w, jint h) { + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + + if (code->callbacks.onContentRectChanged != nullptr) { + ARect rect; + rect.left = x; + rect.top = y; + rect.right = x + w; + rect.bottom = y + h; + code->callbacks.onContentRectChanged(code, &rect); + } } - } } -static void onSoftwareKeyboardVisibilityChangedNative_native(JNIEnv *env, - jobject activity, - jlong handle, - bool visible) { - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; - code->softwareKeyboardVisible = visible; +static void onSoftwareKeyboardVisibilityChangedNative_native(JNIEnv* env, jobject activity, + jlong handle, bool visible) { + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + code->softwareKeyboardVisible = visible; - if (code->callbacks.onSoftwareKeyboardVisibilityChanged != nullptr) { - code->callbacks.onSoftwareKeyboardVisibilityChanged(code, visible); + if (code->callbacks.onSoftwareKeyboardVisibilityChanged != nullptr) { + code->callbacks.onSoftwareKeyboardVisibilityChanged(code, visible); + } } - } } -static void onEditorActionNative_native(JNIEnv *env, jobject activity, - jlong handle, int action) { - if (handle != 0) { - NativeCode *code = (NativeCode *)handle; +static void onEditorActionNative_native(JNIEnv* env, jobject activity, jlong handle, int action) { + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; - if (code->callbacks.onEditorAction != nullptr) { - code->callbacks.onEditorAction(code, action); + if (code->callbacks.onEditorAction != nullptr) { + code->callbacks.onEditorAction(code, action); + } } - } } static const JNINativeMethod g_methods[] = { - {"initializeNativeCode", - "(Ljava/lang/String;Ljava/lang/String;" - "Ljava/lang/String;Landroid/content/res/AssetManager;" - "[BLandroid/content/res/Configuration;)J", - (void *)initializeNativeCode_native}, - {"getDlError", "()Ljava/lang/String;", (void *)getDlError_native}, - {"terminateNativeCode", "(J)V", (void *)terminateNativeCode_native}, - {"onStartNative", "(J)V", (void *)onStart_native}, - {"onResumeNative", "(J)V", (void *)onResume_native}, - {"onSaveInstanceStateNative", "(J)[B", (void *)onSaveInstanceState_native}, - {"onPauseNative", "(J)V", (void *)onPause_native}, - {"onStopNative", "(J)V", (void *)onStop_native}, - {"onConfigurationChangedNative", "(JLandroid/content/res/Configuration;)V", - (void *)onConfigurationChanged_native}, - {"onTrimMemoryNative", "(JI)V", (void *)onTrimMemory_native}, - {"onWindowFocusChangedNative", "(JZ)V", - (void *)onWindowFocusChanged_native}, - {"onSurfaceCreatedNative", "(JLandroid/view/Surface;)V", - (void *)onSurfaceCreated_native}, - {"onSurfaceChangedNative", "(JLandroid/view/Surface;III)V", - (void *)onSurfaceChanged_native}, - {"onSurfaceRedrawNeededNative", "(JLandroid/view/Surface;)V", - (void *)onSurfaceRedrawNeeded_native}, - {"onSurfaceDestroyedNative", "(J)V", (void *)onSurfaceDestroyed_native}, - {"onTouchEventNative", "(JLandroid/view/MotionEvent;IIIIIJJIIIIIIFF)Z", - (void *)onTouchEvent_native}, - {"onKeyDownNative", "(JLandroid/view/KeyEvent;)Z", - (void *)onKeyDown_native}, - {"onKeyUpNative", "(JLandroid/view/KeyEvent;)Z", (void *)onKeyUp_native}, - {"onTextInputEventNative", - "(JLcom/google/androidgamesdk/gametextinput/State;)V", - (void *)onTextInput_native}, - {"onWindowInsetsChangedNative", "(J)V", - (void *)onWindowInsetsChanged_native}, - {"setInputConnectionNative", - "(JLcom/google/androidgamesdk/gametextinput/InputConnection;)V", - (void *)setInputConnection_native}, - {"onContentRectChangedNative", "(JIIII)V", - (void *)onContentRectChangedNative_native}, - {"onSoftwareKeyboardVisibilityChangedNative", "(JZ)V", - (void *)onSoftwareKeyboardVisibilityChangedNative_native}, - {"onEditorActionNative", "(JI)V", (void *)onEditorActionNative_native}, + {"initializeNativeCode", + "(Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Landroid/content/res/AssetManager;" + "[BLandroid/content/res/Configuration;)J", + (void*)initializeNativeCode_native}, + {"getDlError", "()Ljava/lang/String;", (void*)getDlError_native}, + {"terminateNativeCode", "(J)V", (void*)terminateNativeCode_native}, + {"onStartNative", "(J)V", (void*)onStart_native}, + {"onResumeNative", "(J)V", (void*)onResume_native}, + {"onSaveInstanceStateNative", "(J)[B", (void*)onSaveInstanceState_native}, + {"onPauseNative", "(J)V", (void*)onPause_native}, + {"onStopNative", "(J)V", (void*)onStop_native}, + {"onConfigurationChangedNative", "(JLandroid/content/res/Configuration;)V", + (void*)onConfigurationChanged_native}, + {"onTrimMemoryNative", "(JI)V", (void*)onTrimMemory_native}, + {"onWindowFocusChangedNative", "(JZ)V", (void*)onWindowFocusChanged_native}, + {"onSurfaceCreatedNative", "(JLandroid/view/Surface;)V", (void*)onSurfaceCreated_native}, + {"onSurfaceChangedNative", "(JLandroid/view/Surface;III)V", (void*)onSurfaceChanged_native}, + {"onSurfaceRedrawNeededNative", "(JLandroid/view/Surface;)V", + (void*)onSurfaceRedrawNeeded_native}, + {"onSurfaceDestroyedNative", "(J)V", (void*)onSurfaceDestroyed_native}, + {"onTouchEventNative", "(JLandroid/view/MotionEvent;IIIIIJJIIIIIIFF)Z", + (void*)onTouchEvent_native}, + {"onKeyDownNative", "(JLandroid/view/KeyEvent;)Z", (void*)onKeyDown_native}, + {"onKeyUpNative", "(JLandroid/view/KeyEvent;)Z", (void*)onKeyUp_native}, + {"onTextInputEventNative", "(JLcom/google/androidgamesdk/gametextinput/State;)V", + (void*)onTextInput_native}, + {"onWindowInsetsChangedNative", "(J)V", (void*)onWindowInsetsChanged_native}, + {"setInputConnectionNative", + "(JLcom/google/androidgamesdk/gametextinput/InputConnection;)V", + (void*)setInputConnection_native}, + {"onContentRectChangedNative", "(JIIII)V", (void*)onContentRectChangedNative_native}, + {"onSoftwareKeyboardVisibilityChangedNative", "(JZ)V", + (void*)onSoftwareKeyboardVisibilityChangedNative_native}, + {"onEditorActionNative", "(JI)V", (void*)onEditorActionNative_native}, }; -static const char *const kGameActivityPathName = - "com/google/androidgamesdk/GameActivity"; +static const char* const kGameActivityPathName = "com/google/androidgamesdk/GameActivity"; -static const char *const kInsetsPathName = "androidx/core/graphics/Insets"; -static const char *const kConfigurationPathName = - "android/content/res/Configuration"; -static const char *const kWindowInsetsCompatTypePathName = - "androidx/core/view/WindowInsetsCompat$Type"; -static const char *const kLocaleListPathName = "android/os/LocaleList"; -static const char *const kLocalePathName = "java/util/Locale"; +static const char* const kInsetsPathName = "androidx/core/graphics/Insets"; +static const char* const kConfigurationPathName = "android/content/res/Configuration"; +static const char* const kWindowInsetsCompatTypePathName = + "androidx/core/view/WindowInsetsCompat$Type"; +static const char* const kLocaleListPathName = "android/os/LocaleList"; +static const char* const kLocalePathName = "java/util/Locale"; -#define FIND_CLASS(var, className) \ - var = env->FindClass(className); \ - LOG_FATAL_IF(!var, "Unable to find class %s", className); +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(!var, "Unable to find class %s", className); -#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ - var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ - LOG_FATAL_IF(!var, "Unable to find method %s", methodName); +#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ + var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ + LOG_FATAL_IF(!var, "Unable to find method %s", methodName); #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ - var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \ - LOG_FATAL_IF(!var, "Unable to find static method %s", methodName); - -#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ - var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ - LOG_FATAL_IF(!var, "Unable to find field %s", fieldName); - -static int jniRegisterNativeMethods(JNIEnv *env, const char *className, - const JNINativeMethod *methods, - int numMethods) { - ALOGV("Registering %s's %d native methods...", className, numMethods); - jclass clazz = env->FindClass(className); - LOG_FATAL_IF(clazz == nullptr, - "Native registration unable to find class '%s'; aborting...", - className); - int result = env->RegisterNatives(clazz, methods, numMethods); - env->DeleteLocalRef(clazz); - if (result == 0) { - return 0; - } - - // Failure to register natives is fatal. Try to report the corresponding - // exception, otherwise abort with generic failure message. - jthrowable thrown = env->ExceptionOccurred(); - if (thrown != NULL) { - env->ExceptionDescribe(); - env->DeleteLocalRef(thrown); - } - LOG_FATAL("RegisterNatives failed for '%s'; aborting...", className); -} - -extern "C" int GameActivity_register(JNIEnv *env) { - ALOGD("GameActivity_register"); - jclass activity_class; - FIND_CLASS(activity_class, kGameActivityPathName); - GET_METHOD_ID(gGameActivityClassInfo.finish, activity_class, "finish", "()V"); - GET_METHOD_ID(gGameActivityClassInfo.setWindowFlags, activity_class, - "setWindowFlags", "(II)V"); - GET_METHOD_ID(gGameActivityClassInfo.getWindowInsets, activity_class, - "getWindowInsets", "(I)Landroidx/core/graphics/Insets;"); - GET_METHOD_ID(gGameActivityClassInfo.getWaterfallInsets, activity_class, - "getWaterfallInsets", "()Landroidx/core/graphics/Insets;"); - GET_METHOD_ID(gGameActivityClassInfo.setImeEditorInfoFields, activity_class, - "setImeEditorInfoFields", "(III)V"); - - jclass insets_class; - FIND_CLASS(insets_class, kInsetsPathName); - GET_FIELD_ID(gInsetsClassInfo.left, insets_class, "left", "I"); - GET_FIELD_ID(gInsetsClassInfo.right, insets_class, "right", "I"); - GET_FIELD_ID(gInsetsClassInfo.top, insets_class, "top", "I"); - GET_FIELD_ID(gInsetsClassInfo.bottom, insets_class, "bottom", "I"); - - jclass configuration_class; - FIND_CLASS(configuration_class, kConfigurationPathName); - - if (android_get_device_api_level() >= 26) { - GET_FIELD_ID(gConfigurationClassInfo.colorMode, configuration_class, - "colorMode", "I"); - } - - GET_FIELD_ID(gConfigurationClassInfo.densityDpi, configuration_class, - "densityDpi", "I"); - GET_FIELD_ID(gConfigurationClassInfo.fontScale, configuration_class, - "fontScale", "F"); - - if (android_get_device_api_level() >= 31) { - GET_FIELD_ID(gConfigurationClassInfo.fontWeightAdjustment, - configuration_class, "fontWeightAdjustment", "I"); - } - - GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, configuration_class, - "hardKeyboardHidden", "I"); - GET_FIELD_ID(gConfigurationClassInfo.keyboard, configuration_class, - "keyboard", "I"); - GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, configuration_class, - "keyboardHidden", "I"); - GET_FIELD_ID(gConfigurationClassInfo.mcc, configuration_class, "mcc", "I"); - GET_FIELD_ID(gConfigurationClassInfo.mnc, configuration_class, "mnc", "I"); - GET_FIELD_ID(gConfigurationClassInfo.navigation, configuration_class, - "navigation", "I"); - GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, configuration_class, - "navigationHidden", "I"); - GET_FIELD_ID(gConfigurationClassInfo.orientation, configuration_class, - "orientation", "I"); - GET_FIELD_ID(gConfigurationClassInfo.screenHeightDp, configuration_class, - "screenHeightDp", "I"); - GET_FIELD_ID(gConfigurationClassInfo.screenLayout, configuration_class, - "screenLayout", "I"); - GET_FIELD_ID(gConfigurationClassInfo.screenWidthDp, configuration_class, - "screenWidthDp", "I"); - GET_FIELD_ID(gConfigurationClassInfo.smallestScreenWidthDp, - configuration_class, "smallestScreenWidthDp", "I"); - GET_FIELD_ID(gConfigurationClassInfo.touchscreen, configuration_class, - "touchscreen", "I"); - GET_FIELD_ID(gConfigurationClassInfo.uiMode, configuration_class, "uiMode", - "I"); - - GET_METHOD_ID(gConfigurationClassInfo.getLocales, configuration_class, - "getLocales", "()Landroid/os/LocaleList;"); - - jclass localeListClass; - FIND_CLASS(localeListClass, kLocaleListPathName); - GET_METHOD_ID(gLocaleListClassInfo.size, localeListClass, "size", "()I"); - GET_METHOD_ID(gLocaleListClassInfo.get, localeListClass, "get", - "(I)Ljava/util/Locale;"); - - jclass localeClass; - FIND_CLASS(localeClass, kLocalePathName); - GET_METHOD_ID(gLocaleClassInfo.getLanguage, localeClass, "getLanguage", - "()Ljava/lang/String;"); - GET_METHOD_ID(gLocaleClassInfo.getScript, localeClass, "getScript", - "()Ljava/lang/String;"); - GET_METHOD_ID(gLocaleClassInfo.getCountry, localeClass, "getCountry", - "()Ljava/lang/String;"); - GET_METHOD_ID(gLocaleClassInfo.getVariant, localeClass, "getVariant", - "()Ljava/lang/String;"); - - jclass windowInsetsCompatType_class; - FIND_CLASS(windowInsetsCompatType_class, kWindowInsetsCompatTypePathName); - gWindowInsetsCompatTypeClassInfo.clazz = - (jclass)env->NewGlobalRef(windowInsetsCompatType_class); - // These names must match, in order, the GameCommonInsetsType enum fields - // Note that waterfall is handled differently by the insets API, so we - // exclude it here. - const char *methodNames[GAMECOMMON_INSETS_TYPE_WATERFALL] = { - "captionBar", - "displayCutout", - "ime", - "mandatorySystemGestures", - "navigationBars", - "statusBars", - "systemBars", - "systemGestures", - "tappableElement"}; - for (int i = 0; i < GAMECOMMON_INSETS_TYPE_WATERFALL; ++i) { - GET_STATIC_METHOD_ID(gWindowInsetsCompatTypeClassInfo.methods[i], - windowInsetsCompatType_class, methodNames[i], "()I"); - } - - GameActivityEventsInit(env); - - return jniRegisterNativeMethods(env, kGameActivityPathName, g_methods, - NELEM(g_methods)); + var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \ + LOG_FATAL_IF(!var, "Unable to find static method %s", methodName); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(!var, "Unable to find field %s", fieldName); + +static int jniRegisterNativeMethods(JNIEnv* env, const char* className, + const JNINativeMethod* methods, int numMethods) { + ALOGV("Registering %s's %d native methods...", className, numMethods); + jclass clazz = env->FindClass(className); + LOG_FATAL_IF(clazz == nullptr, "Native registration unable to find class '%s'; aborting...", + className); + int result = env->RegisterNatives(clazz, methods, numMethods); + env->DeleteLocalRef(clazz); + if (result == 0) { + return 0; + } + + // Failure to register natives is fatal. Try to report the corresponding + // exception, otherwise abort with generic failure message. + jthrowable thrown = env->ExceptionOccurred(); + if (thrown != NULL) { + env->ExceptionDescribe(); + env->DeleteLocalRef(thrown); + } + LOG_FATAL("RegisterNatives failed for '%s'; aborting...", className); +} + +extern "C" int GameActivity_register(JNIEnv* env) { + if (g_methodsRegistered.exchange(true)) { + // Already registered, do nothing. + return JNI_OK; + } + + ALOGD("GameActivity_register"); + jclass activity_class; + FIND_CLASS(activity_class, kGameActivityPathName); + GET_METHOD_ID(gGameActivityClassInfo.finish, activity_class, "finish", "()V"); + GET_METHOD_ID(gGameActivityClassInfo.setWindowFlags, activity_class, "setWindowFlags", "(II)V"); + GET_METHOD_ID(gGameActivityClassInfo.getWindowInsets, activity_class, "getWindowInsets", + "(I)Landroidx/core/graphics/Insets;"); + GET_METHOD_ID(gGameActivityClassInfo.getWaterfallInsets, activity_class, "getWaterfallInsets", + "()Landroidx/core/graphics/Insets;"); + GET_METHOD_ID(gGameActivityClassInfo.setImeEditorInfoFields, activity_class, + "setImeEditorInfoFields", "(III)V"); + + jclass insets_class; + FIND_CLASS(insets_class, kInsetsPathName); + GET_FIELD_ID(gInsetsClassInfo.left, insets_class, "left", "I"); + GET_FIELD_ID(gInsetsClassInfo.right, insets_class, "right", "I"); + GET_FIELD_ID(gInsetsClassInfo.top, insets_class, "top", "I"); + GET_FIELD_ID(gInsetsClassInfo.bottom, insets_class, "bottom", "I"); + + jclass configuration_class; + FIND_CLASS(configuration_class, kConfigurationPathName); + + if (android_get_device_api_level() >= 26) { + GET_FIELD_ID(gConfigurationClassInfo.colorMode, configuration_class, "colorMode", "I"); + } + + GET_FIELD_ID(gConfigurationClassInfo.densityDpi, configuration_class, "densityDpi", "I"); + GET_FIELD_ID(gConfigurationClassInfo.fontScale, configuration_class, "fontScale", "F"); + + if (android_get_device_api_level() >= 31) { + GET_FIELD_ID(gConfigurationClassInfo.fontWeightAdjustment, configuration_class, + "fontWeightAdjustment", "I"); + } + + GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, configuration_class, + "hardKeyboardHidden", "I"); + GET_FIELD_ID(gConfigurationClassInfo.keyboard, configuration_class, "keyboard", "I"); + GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, configuration_class, "keyboardHidden", + "I"); + GET_FIELD_ID(gConfigurationClassInfo.mcc, configuration_class, "mcc", "I"); + GET_FIELD_ID(gConfigurationClassInfo.mnc, configuration_class, "mnc", "I"); + GET_FIELD_ID(gConfigurationClassInfo.navigation, configuration_class, "navigation", "I"); + GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, configuration_class, "navigationHidden", + "I"); + GET_FIELD_ID(gConfigurationClassInfo.orientation, configuration_class, "orientation", "I"); + GET_FIELD_ID(gConfigurationClassInfo.screenHeightDp, configuration_class, "screenHeightDp", + "I"); + GET_FIELD_ID(gConfigurationClassInfo.screenLayout, configuration_class, "screenLayout", "I"); + GET_FIELD_ID(gConfigurationClassInfo.screenWidthDp, configuration_class, "screenWidthDp", "I"); + GET_FIELD_ID(gConfigurationClassInfo.smallestScreenWidthDp, configuration_class, + "smallestScreenWidthDp", "I"); + GET_FIELD_ID(gConfigurationClassInfo.touchscreen, configuration_class, "touchscreen", "I"); + GET_FIELD_ID(gConfigurationClassInfo.uiMode, configuration_class, "uiMode", "I"); + + GET_METHOD_ID(gConfigurationClassInfo.getLocales, configuration_class, "getLocales", + "()Landroid/os/LocaleList;"); + + jclass localeListClass; + FIND_CLASS(localeListClass, kLocaleListPathName); + GET_METHOD_ID(gLocaleListClassInfo.size, localeListClass, "size", "()I"); + GET_METHOD_ID(gLocaleListClassInfo.get, localeListClass, "get", "(I)Ljava/util/Locale;"); + + jclass localeClass; + FIND_CLASS(localeClass, kLocalePathName); + GET_METHOD_ID(gLocaleClassInfo.getLanguage, localeClass, "getLanguage", "()Ljava/lang/String;"); + GET_METHOD_ID(gLocaleClassInfo.getScript, localeClass, "getScript", "()Ljava/lang/String;"); + GET_METHOD_ID(gLocaleClassInfo.getCountry, localeClass, "getCountry", "()Ljava/lang/String;"); + GET_METHOD_ID(gLocaleClassInfo.getVariant, localeClass, "getVariant", "()Ljava/lang/String;"); + + jclass windowInsetsCompatType_class; + FIND_CLASS(windowInsetsCompatType_class, kWindowInsetsCompatTypePathName); + gWindowInsetsCompatTypeClassInfo.clazz = + (jclass)env->NewGlobalRef(windowInsetsCompatType_class); + // These names must match, in order, the GameCommonInsetsType enum fields + // Note that waterfall is handled differently by the insets API, so we + // exclude it here. + const char* methodNames[GAMECOMMON_INSETS_TYPE_WATERFALL] = + {"captionBar", "displayCutout", "ime", "mandatorySystemGestures", + "navigationBars", "statusBars", "systemBars", "systemGestures", + "tappableElement"}; + for (int i = 0; i < GAMECOMMON_INSETS_TYPE_WATERFALL; ++i) { + GET_STATIC_METHOD_ID(gWindowInsetsCompatTypeClassInfo.methods[i], + windowInsetsCompatType_class, methodNames[i], "()I"); + } + + GameActivityEventsInit(env); + + return jniRegisterNativeMethods(env, kGameActivityPathName, g_methods, NELEM(g_methods)); } // XXX: This symbol is renamed with a _C suffix and then re-exported from @@ -1388,12 +1304,22 @@ extern "C" int GameActivity_register(JNIEnv *env) { // extern "C" JNIEXPORT jlong JNICALL Java_com_google_androidgamesdk_GameActivity_initializeNativeCode_C( - JNIEnv *env, jobject javaGameActivity, jstring internalDataDir, - jstring obbDir, jstring externalDataDir, jobject jAssetMgr, - jbyteArray savedState, jobject javaConfig) { - GameActivity_register(env); - jlong nativeCode = initializeNativeCode_native( - env, javaGameActivity, internalDataDir, obbDir, externalDataDir, - jAssetMgr, savedState, javaConfig); - return nativeCode; + JNIEnv* env, jobject javaGameActivity, jstring internalDataDir, jstring obbDir, + jstring externalDataDir, jobject jAssetMgr, jbyteArray savedState, jobject javaConfig) { + GameActivity_register(env); + jlong nativeCode = + initializeNativeCode_native(env, javaGameActivity, internalDataDir, obbDir, + externalDataDir, jAssetMgr, savedState, javaConfig); + return nativeCode; +} + +extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) __attribute__((weak)); + +extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } + int result = GameActivity_register(env); + return (result == 0) ? JNI_VERSION_1_6 : -1; } diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents.cpp b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents.cpp index 5e238c6c..f88a64e2 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents.cpp +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents.cpp @@ -24,312 +24,281 @@ #include "system_utils.h" static bool enabledAxes[GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT] = { - /* AMOTION_EVENT_AXIS_X */ true, - /* AMOTION_EVENT_AXIS_Y */ true, - // Disable all other axes by default (they can be enabled using - // `GameActivityPointerAxes_enableAxis`). - false}; + /* AMOTION_EVENT_AXIS_X */ true, + /* AMOTION_EVENT_AXIS_Y */ true, + // Disable all other axes by default (they can be enabled using + // `GameActivityPointerAxes_enableAxis`). + false}; extern "C" void GameActivityPointerAxes_enableAxis(int32_t axis) { - if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { - return; - } + if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { + return; + } - enabledAxes[axis] = true; + enabledAxes[axis] = true; } -float GameActivityPointerAxes_getAxisValue( - const GameActivityPointerAxes *pointerInfo, int32_t axis) { - if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { - return 0; - } +float GameActivityPointerAxes_getAxisValue(const GameActivityPointerAxes* pointerInfo, + int32_t axis) { + if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { + return 0; + } - if (!enabledAxes[axis]) { - ALOGW("Axis %d must be enabled before it can be accessed.", axis); - return 0; - } + if (!enabledAxes[axis]) { + ALOGW("Axis %d must be enabled before it can be accessed.", axis); + return 0; + } - return pointerInfo->axisValues[axis]; + return pointerInfo->axisValues[axis]; } extern "C" void GameActivityPointerAxes_disableAxis(int32_t axis) { - if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { - return; - } + if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { + return; + } - enabledAxes[axis] = false; + enabledAxes[axis] = false; } -float GameActivityMotionEvent_getHistoricalAxisValue( - const GameActivityMotionEvent *event, int axis, int pointerIndex, - int historyPos) { - if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { - ALOGE("Invalid axis %d", axis); - return -1; - } - if (pointerIndex < 0 || pointerIndex >= event->pointerCount) { - ALOGE("Invalid pointer index %d", pointerIndex); - return -1; - } - if (historyPos < 0 || historyPos >= event->historySize) { - ALOGE("Invalid history index %d", historyPos); - return -1; - } - if (!enabledAxes[axis]) { - ALOGW("Axis %d must be enabled before it can be accessed.", axis); - return 0; - } - - int pointerOffset = pointerIndex * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; - int historyValuesOffset = - historyPos * event->pointerCount * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; - return event - ->historicalAxisValues[historyValuesOffset + pointerOffset + axis]; +float GameActivityMotionEvent_getHistoricalAxisValue(const GameActivityMotionEvent* event, int axis, + int pointerIndex, int historyPos) { + if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) { + ALOGE("Invalid axis %d", axis); + return -1; + } + if (pointerIndex < 0 || pointerIndex >= event->pointerCount) { + ALOGE("Invalid pointer index %d", pointerIndex); + return -1; + } + if (historyPos < 0 || historyPos >= event->historySize) { + ALOGE("Invalid history index %d", historyPos); + return -1; + } + if (!enabledAxes[axis]) { + ALOGW("Axis %d must be enabled before it can be accessed.", axis); + return 0; + } + + int pointerOffset = pointerIndex * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; + int historyValuesOffset = + historyPos * event->pointerCount * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; + return event->historicalAxisValues[historyValuesOffset + pointerOffset + axis]; } static struct { - jmethodID getDeviceId; - jmethodID getSource; - jmethodID getAction; + jmethodID getDeviceId; + jmethodID getSource; + jmethodID getAction; - jmethodID getEventTime; - jmethodID getDownTime; + jmethodID getEventTime; + jmethodID getDownTime; - jmethodID getFlags; - jmethodID getMetaState; + jmethodID getFlags; + jmethodID getMetaState; - jmethodID getActionButton; - jmethodID getButtonState; - jmethodID getClassification; - jmethodID getEdgeFlags; + jmethodID getActionButton; + jmethodID getButtonState; + jmethodID getClassification; + jmethodID getEdgeFlags; - jmethodID getHistorySize; - jmethodID getHistoricalEventTime; + jmethodID getHistorySize; + jmethodID getHistoricalEventTime; - jmethodID getPointerCount; - jmethodID getPointerId; + jmethodID getPointerCount; + jmethodID getPointerId; - jmethodID getToolType; + jmethodID getToolType; - jmethodID getRawX; - jmethodID getRawY; - jmethodID getXPrecision; - jmethodID getYPrecision; - jmethodID getAxisValue; + jmethodID getRawX; + jmethodID getRawY; + jmethodID getXPrecision; + jmethodID getYPrecision; + jmethodID getAxisValue; - jmethodID getHistoricalAxisValue; + jmethodID getHistoricalAxisValue; } gMotionEventClassInfo; -extern "C" void GameActivityMotionEvent_destroy( - GameActivityMotionEvent *c_event) { - delete c_event->historicalAxisValues; - delete c_event->historicalEventTimesMillis; - delete c_event->historicalEventTimesNanos; +extern "C" void GameActivityMotionEvent_destroy(GameActivityMotionEvent* c_event) { + delete c_event->historicalAxisValues; + delete c_event->historicalEventTimesMillis; + delete c_event->historicalEventTimesNanos; } -static void initMotionEvents(JNIEnv *env) { - int sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk"); - gMotionEventClassInfo = {0}; - jclass motionEventClass = env->FindClass("android/view/MotionEvent"); - gMotionEventClassInfo.getDeviceId = - env->GetMethodID(motionEventClass, "getDeviceId", "()I"); - gMotionEventClassInfo.getSource = - env->GetMethodID(motionEventClass, "getSource", "()I"); - gMotionEventClassInfo.getAction = - env->GetMethodID(motionEventClass, "getAction", "()I"); - gMotionEventClassInfo.getEventTime = - env->GetMethodID(motionEventClass, "getEventTime", "()J"); - gMotionEventClassInfo.getDownTime = - env->GetMethodID(motionEventClass, "getDownTime", "()J"); - gMotionEventClassInfo.getFlags = - env->GetMethodID(motionEventClass, "getFlags", "()I"); - gMotionEventClassInfo.getMetaState = - env->GetMethodID(motionEventClass, "getMetaState", "()I"); - if (sdkVersion >= 23) { - gMotionEventClassInfo.getActionButton = - env->GetMethodID(motionEventClass, "getActionButton", "()I"); - } - if (sdkVersion >= 14) { - gMotionEventClassInfo.getButtonState = - env->GetMethodID(motionEventClass, "getButtonState", "()I"); - } - if (sdkVersion >= 29) { - gMotionEventClassInfo.getClassification = - env->GetMethodID(motionEventClass, "getClassification", "()I"); - } - gMotionEventClassInfo.getEdgeFlags = - env->GetMethodID(motionEventClass, "getEdgeFlags", "()I"); - - gMotionEventClassInfo.getHistorySize = - env->GetMethodID(motionEventClass, "getHistorySize", "()I"); - gMotionEventClassInfo.getHistoricalEventTime = - env->GetMethodID(motionEventClass, "getHistoricalEventTime", "(I)J"); - - gMotionEventClassInfo.getPointerCount = - env->GetMethodID(motionEventClass, "getPointerCount", "()I"); - gMotionEventClassInfo.getPointerId = - env->GetMethodID(motionEventClass, "getPointerId", "(I)I"); - gMotionEventClassInfo.getToolType = - env->GetMethodID(motionEventClass, "getToolType", "(I)I"); - if (sdkVersion >= 29) { - gMotionEventClassInfo.getRawX = - env->GetMethodID(motionEventClass, "getRawX", "(I)F"); - gMotionEventClassInfo.getRawY = - env->GetMethodID(motionEventClass, "getRawY", "(I)F"); - } - gMotionEventClassInfo.getXPrecision = - env->GetMethodID(motionEventClass, "getXPrecision", "()F"); - gMotionEventClassInfo.getYPrecision = - env->GetMethodID(motionEventClass, "getYPrecision", "()F"); - gMotionEventClassInfo.getAxisValue = - env->GetMethodID(motionEventClass, "getAxisValue", "(II)F"); - - gMotionEventClassInfo.getHistoricalAxisValue = - env->GetMethodID(motionEventClass, "getHistoricalAxisValue", "(III)F"); +static void initMotionEvents(JNIEnv* env) { + int sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk"); + gMotionEventClassInfo = {0}; + jclass motionEventClass = env->FindClass("android/view/MotionEvent"); + gMotionEventClassInfo.getDeviceId = env->GetMethodID(motionEventClass, "getDeviceId", "()I"); + gMotionEventClassInfo.getSource = env->GetMethodID(motionEventClass, "getSource", "()I"); + gMotionEventClassInfo.getAction = env->GetMethodID(motionEventClass, "getAction", "()I"); + gMotionEventClassInfo.getEventTime = env->GetMethodID(motionEventClass, "getEventTime", "()J"); + gMotionEventClassInfo.getDownTime = env->GetMethodID(motionEventClass, "getDownTime", "()J"); + gMotionEventClassInfo.getFlags = env->GetMethodID(motionEventClass, "getFlags", "()I"); + gMotionEventClassInfo.getMetaState = env->GetMethodID(motionEventClass, "getMetaState", "()I"); + if (sdkVersion >= 23) { + gMotionEventClassInfo.getActionButton = + env->GetMethodID(motionEventClass, "getActionButton", "()I"); + } + if (sdkVersion >= 14) { + gMotionEventClassInfo.getButtonState = + env->GetMethodID(motionEventClass, "getButtonState", "()I"); + } + if (sdkVersion >= 29) { + gMotionEventClassInfo.getClassification = + env->GetMethodID(motionEventClass, "getClassification", "()I"); + } + gMotionEventClassInfo.getEdgeFlags = env->GetMethodID(motionEventClass, "getEdgeFlags", "()I"); + + gMotionEventClassInfo.getHistorySize = + env->GetMethodID(motionEventClass, "getHistorySize", "()I"); + gMotionEventClassInfo.getHistoricalEventTime = + env->GetMethodID(motionEventClass, "getHistoricalEventTime", "(I)J"); + + gMotionEventClassInfo.getPointerCount = + env->GetMethodID(motionEventClass, "getPointerCount", "()I"); + gMotionEventClassInfo.getPointerId = env->GetMethodID(motionEventClass, "getPointerId", "(I)I"); + gMotionEventClassInfo.getToolType = env->GetMethodID(motionEventClass, "getToolType", "(I)I"); + if (sdkVersion >= 29) { + gMotionEventClassInfo.getRawX = env->GetMethodID(motionEventClass, "getRawX", "(I)F"); + gMotionEventClassInfo.getRawY = env->GetMethodID(motionEventClass, "getRawY", "(I)F"); + } + gMotionEventClassInfo.getXPrecision = + env->GetMethodID(motionEventClass, "getXPrecision", "()F"); + gMotionEventClassInfo.getYPrecision = + env->GetMethodID(motionEventClass, "getYPrecision", "()F"); + gMotionEventClassInfo.getAxisValue = + env->GetMethodID(motionEventClass, "getAxisValue", "(II)F"); + + gMotionEventClassInfo.getHistoricalAxisValue = + env->GetMethodID(motionEventClass, "getHistoricalAxisValue", "(III)F"); } -extern "C" void GameActivityMotionEvent_fromJava( - JNIEnv *env, jobject motionEvent, GameActivityMotionEvent *out_event, - int pointerCount, int historySize) { - pointerCount = - std::min(pointerCount, GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT); - out_event->pointerCount = pointerCount; - for (int i = 0; i < pointerCount; ++i) { - out_event->pointers[i] = { - /*id=*/env->CallIntMethod(motionEvent, - gMotionEventClassInfo.getPointerId, i), - /*toolType=*/ - env->CallIntMethod(motionEvent, gMotionEventClassInfo.getToolType, i), - /*axisValues=*/{0}, - /*rawX=*/gMotionEventClassInfo.getRawX - ? env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getRawX, - i) - : 0, - /*rawY=*/gMotionEventClassInfo.getRawY - ? env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getRawY, - i) - : 0, - }; - - for (int axisIndex = 0; axisIndex < GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; - ++axisIndex) { - if (enabledAxes[axisIndex]) { - out_event->pointers[i].axisValues[axisIndex] = env->CallFloatMethod( - motionEvent, gMotionEventClassInfo.getAxisValue, axisIndex, i); - } - } - } - - out_event->historySize = historySize; - out_event->historicalAxisValues = - new float[historySize * pointerCount * - GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT]; - out_event->historicalEventTimesMillis = new int64_t[historySize]; - out_event->historicalEventTimesNanos = new int64_t[historySize]; - - for (int historyIndex = 0; historyIndex < historySize; historyIndex++) { - out_event->historicalEventTimesMillis[historyIndex] = env->CallLongMethod( - motionEvent, gMotionEventClassInfo.getHistoricalEventTime, - historyIndex); - out_event->historicalEventTimesNanos[historyIndex] = - out_event->historicalEventTimesMillis[historyIndex] * 1000000; +extern "C" void GameActivityMotionEvent_fromJava(JNIEnv* env, jobject motionEvent, + GameActivityMotionEvent* out_event, + int pointerCount, int historySize) { + pointerCount = std::min(pointerCount, GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT); + out_event->pointerCount = pointerCount; for (int i = 0; i < pointerCount; ++i) { - int pointerOffset = i * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; - int historyAxisOffset = - historyIndex * pointerCount * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; - float *axisValues = - &out_event->historicalAxisValues[historyAxisOffset + pointerOffset]; - for (int axisIndex = 0; axisIndex < GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; - ++axisIndex) { - if (enabledAxes[axisIndex]) { - axisValues[axisIndex] = env->CallFloatMethod( - motionEvent, gMotionEventClassInfo.getHistoricalAxisValue, - axisIndex, i, historyIndex); + out_event->pointers[i] = { + /*id=*/env->CallIntMethod(motionEvent, gMotionEventClassInfo.getPointerId, i), + /*toolType=*/ + env->CallIntMethod(motionEvent, gMotionEventClassInfo.getToolType, i), + /*axisValues=*/{0}, + /*rawX=*/gMotionEventClassInfo.getRawX + ? env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getRawX, i) + : 0, + /*rawY=*/gMotionEventClassInfo.getRawY + ? env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getRawY, i) + : 0, + }; + + for (int axisIndex = 0; axisIndex < GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; ++axisIndex) { + if (enabledAxes[axisIndex]) { + out_event->pointers[i].axisValues[axisIndex] = + env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getAxisValue, + axisIndex, i); + } + } + } + + out_event->historySize = historySize; + out_event->historicalAxisValues = + new float[historySize * pointerCount * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT]; + out_event->historicalEventTimesMillis = new int64_t[historySize]; + out_event->historicalEventTimesNanos = new int64_t[historySize]; + + for (int historyIndex = 0; historyIndex < historySize; historyIndex++) { + out_event->historicalEventTimesMillis[historyIndex] = + env->CallLongMethod(motionEvent, gMotionEventClassInfo.getHistoricalEventTime, + historyIndex); + out_event->historicalEventTimesNanos[historyIndex] = + out_event->historicalEventTimesMillis[historyIndex] * 1000000; + for (int i = 0; i < pointerCount; ++i) { + int pointerOffset = i * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; + int historyAxisOffset = + historyIndex * pointerCount * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; + float* axisValues = &out_event->historicalAxisValues[historyAxisOffset + pointerOffset]; + for (int axisIndex = 0; axisIndex < GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; + ++axisIndex) { + if (enabledAxes[axisIndex]) { + axisValues[axisIndex] = + env->CallFloatMethod(motionEvent, + gMotionEventClassInfo.getHistoricalAxisValue, + axisIndex, i, historyIndex); + } + } } - } } - } } static struct { - jmethodID getDeviceId; - jmethodID getSource; - jmethodID getAction; + jmethodID getDeviceId; + jmethodID getSource; + jmethodID getAction; - jmethodID getEventTime; - jmethodID getDownTime; + jmethodID getEventTime; + jmethodID getDownTime; - jmethodID getFlags; - jmethodID getMetaState; + jmethodID getFlags; + jmethodID getMetaState; - jmethodID getModifiers; - jmethodID getRepeatCount; - jmethodID getKeyCode; - jmethodID getScanCode; - // jmethodID getUnicodeChar; + jmethodID getModifiers; + jmethodID getRepeatCount; + jmethodID getKeyCode; + jmethodID getScanCode; + // jmethodID getUnicodeChar; } gKeyEventClassInfo; -static void initKeyEvents(JNIEnv *env) { - int sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk"); - gKeyEventClassInfo = {0}; - jclass keyEventClass = env->FindClass("android/view/KeyEvent"); - gKeyEventClassInfo.getDeviceId = - env->GetMethodID(keyEventClass, "getDeviceId", "()I"); - gKeyEventClassInfo.getSource = - env->GetMethodID(keyEventClass, "getSource", "()I"); - gKeyEventClassInfo.getAction = - env->GetMethodID(keyEventClass, "getAction", "()I"); - gKeyEventClassInfo.getEventTime = - env->GetMethodID(keyEventClass, "getEventTime", "()J"); - gKeyEventClassInfo.getDownTime = - env->GetMethodID(keyEventClass, "getDownTime", "()J"); - gKeyEventClassInfo.getFlags = - env->GetMethodID(keyEventClass, "getFlags", "()I"); - gKeyEventClassInfo.getMetaState = - env->GetMethodID(keyEventClass, "getMetaState", "()I"); - if (sdkVersion >= 13) { - gKeyEventClassInfo.getModifiers = - env->GetMethodID(keyEventClass, "getModifiers", "()I"); - } - gKeyEventClassInfo.getRepeatCount = - env->GetMethodID(keyEventClass, "getRepeatCount", "()I"); - gKeyEventClassInfo.getKeyCode = - env->GetMethodID(keyEventClass, "getKeyCode", "()I"); - gKeyEventClassInfo.getScanCode = - env->GetMethodID(keyEventClass, "getScanCode", "()I"); - //gKeyEventClassInfo.getUnicodeChar = - //env->GetMethodID(keyEventClass, "getUnicodeChar", "()I"); +static void initKeyEvents(JNIEnv* env) { + int sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk"); + gKeyEventClassInfo = {0}; + jclass keyEventClass = env->FindClass("android/view/KeyEvent"); + gKeyEventClassInfo.getDeviceId = env->GetMethodID(keyEventClass, "getDeviceId", "()I"); + gKeyEventClassInfo.getSource = env->GetMethodID(keyEventClass, "getSource", "()I"); + gKeyEventClassInfo.getAction = env->GetMethodID(keyEventClass, "getAction", "()I"); + gKeyEventClassInfo.getEventTime = env->GetMethodID(keyEventClass, "getEventTime", "()J"); + gKeyEventClassInfo.getDownTime = env->GetMethodID(keyEventClass, "getDownTime", "()J"); + gKeyEventClassInfo.getFlags = env->GetMethodID(keyEventClass, "getFlags", "()I"); + gKeyEventClassInfo.getMetaState = env->GetMethodID(keyEventClass, "getMetaState", "()I"); + if (sdkVersion >= 13) { + gKeyEventClassInfo.getModifiers = env->GetMethodID(keyEventClass, "getModifiers", "()I"); + } + gKeyEventClassInfo.getRepeatCount = env->GetMethodID(keyEventClass, "getRepeatCount", "()I"); + gKeyEventClassInfo.getKeyCode = env->GetMethodID(keyEventClass, "getKeyCode", "()I"); + gKeyEventClassInfo.getScanCode = env->GetMethodID(keyEventClass, "getScanCode", "()I"); + // gKeyEventClassInfo.getUnicodeChar = + // env->GetMethodID(keyEventClass, "getUnicodeChar", "()I"); } -extern "C" void GameActivityKeyEvent_fromJava(JNIEnv *env, jobject keyEvent, - GameActivityKeyEvent *out_event) { - *out_event = { - /*deviceId=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getDeviceId), - /*source=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getSource), - /*action=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getAction), - // TODO: introduce a millisecondsToNanoseconds helper: - /*eventTime=*/ - env->CallLongMethod(keyEvent, gKeyEventClassInfo.getEventTime) * 1000000, - /*downTime=*/ - env->CallLongMethod(keyEvent, gKeyEventClassInfo.getDownTime) * 1000000, - /*flags=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getFlags), - /*metaState=*/ - env->CallIntMethod(keyEvent, gKeyEventClassInfo.getMetaState), - /*modifiers=*/gKeyEventClassInfo.getModifiers - ? env->CallIntMethod(keyEvent, gKeyEventClassInfo.getModifiers) - : 0, - /*repeatCount=*/ - env->CallIntMethod(keyEvent, gKeyEventClassInfo.getRepeatCount), - /*keyCode=*/ - env->CallIntMethod(keyEvent, gKeyEventClassInfo.getKeyCode), - /*scanCode=*/ - env->CallIntMethod(keyEvent, gKeyEventClassInfo.getScanCode) - /*unicodeChar=*/ - // env->CallIntMethod(keyEvent, gKeyEventClassInfo.getUnicodeChar) - }; +extern "C" void GameActivityKeyEvent_fromJava(JNIEnv* env, jobject keyEvent, + GameActivityKeyEvent* out_event) { + *out_event = { + /*deviceId=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getDeviceId), + /*source=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getSource), + /*action=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getAction), + // TODO: introduce a millisecondsToNanoseconds helper: + /*eventTime=*/ + env->CallLongMethod(keyEvent, gKeyEventClassInfo.getEventTime) * 1000000, + /*downTime=*/ + env->CallLongMethod(keyEvent, gKeyEventClassInfo.getDownTime) * 1000000, + /*flags=*/env->CallIntMethod(keyEvent, gKeyEventClassInfo.getFlags), + /*metaState=*/ + env->CallIntMethod(keyEvent, gKeyEventClassInfo.getMetaState), + /*modifiers=*/gKeyEventClassInfo.getModifiers + ? env->CallIntMethod(keyEvent, gKeyEventClassInfo.getModifiers) + : 0, + /*repeatCount=*/ + env->CallIntMethod(keyEvent, gKeyEventClassInfo.getRepeatCount), + /*keyCode=*/ + env->CallIntMethod(keyEvent, gKeyEventClassInfo.getKeyCode), + /*scanCode=*/ + env->CallIntMethod(keyEvent, gKeyEventClassInfo.getScanCode) + /*unicodeChar=*/ + // env->CallIntMethod(keyEvent, gKeyEventClassInfo.getUnicodeChar) + }; } -extern "C" void GameActivityEventsInit(JNIEnv *env) { - initMotionEvents(env); - initKeyEvents(env); +extern "C" void GameActivityEventsInit(JNIEnv* env) { + initMotionEvents(env); + initKeyEvents(env); } diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents_internal.h b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents_internal.h index 202be8b1..bcd0d537 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents_internal.h +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/GameActivityEvents_internal.h @@ -53,8 +53,8 @@ void GameActivityEventsInit(JNIEnv* env); * to avoid extra JNI calls. */ void GameActivityMotionEvent_fromJava(JNIEnv* env, jobject motionEvent, - GameActivityMotionEvent* out_event, - int pointerCount, int historySize); + GameActivityMotionEvent* out_event, int pointerCount, + int historySize); /** * \brief Convert a Java `KeyEvent` to a `GameActivityKeyEvent`. @@ -74,4 +74,4 @@ void GameActivityKeyEvent_fromJava(JNIEnv* env, jobject motionEvent, /** @} */ -#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_INTERNAL_H +#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_INTERNAL_H diff --git a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/native_app_glue/android_native_app_glue.c b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/native_app_glue/android_native_app_glue.c index 988287f5..27a68f4a 100644 --- a/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/native_app_glue/android_native_app_glue.c +++ b/android-activity/android-games-sdk/game-activity/prefab-src/modules/game-activity/src/game-activity/native_app_glue/android_native_app_glue.c @@ -27,217 +27,208 @@ #define NATIVE_APP_GLUE_MOTION_EVENTS_DEFAULT_BUF_SIZE 16 #define NATIVE_APP_GLUE_KEY_EVENTS_DEFAULT_BUF_SIZE 4 - -#define LOGI(...) \ - ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) -#define LOGE(...) \ - ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) -#define LOGW(...) \ - ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__)) -#define LOGW_ONCE(...) \ - do { \ - static bool alogw_once##__FILE__##__LINE__##__ = true; \ - if (alogw_once##__FILE__##__LINE__##__) { \ - alogw_once##__FILE__##__LINE__##__ = false; \ - LOGW(__VA_ARGS__); \ - } \ - } while (0) +#define NATIVE_APP_GLUE_CMD_WAIT_TIMEOUT_SECONDS 2 + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__)) +#define LOGW_ONCE(...) \ + do { \ + static bool alogw_once##__FILE__##__LINE__##__ = true; \ + if (alogw_once##__FILE__##__LINE__##__) { \ + alogw_once##__FILE__##__LINE__##__ = false; \ + LOGW(__VA_ARGS__); \ + } \ + } while (0) /* For debug builds, always enable the debug traces in this library */ #ifndef NDEBUG -#define LOGV(...) \ - ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) +#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) #else #define LOGV(...) ((void)0) #endif static void free_saved_state(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - if (android_app->savedState != NULL) { - free(android_app->savedState); - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - pthread_mutex_unlock(&android_app->mutex); + pthread_mutex_lock(&android_app->mutex); + if (android_app->savedState != NULL) { + free(android_app->savedState); + android_app->savedState = NULL; + android_app->savedStateSize = 0; + } + pthread_mutex_unlock(&android_app->mutex); } int8_t android_app_read_cmd(struct android_app* android_app) { - int8_t cmd; - if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) { - LOGE("No data on command pipe!"); - return -1; - } - if (cmd == APP_CMD_SAVE_STATE) free_saved_state(android_app); - return cmd; + int8_t cmd; + if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) { + LOGE("No data on command pipe!"); + return -1; + } + if (cmd == APP_CMD_SAVE_STATE) free_saved_state(android_app); + return cmd; } static void print_cur_config(struct android_app* android_app) { - char lang[2], country[2]; - AConfiguration_getLanguage(android_app->config, lang); - AConfiguration_getCountry(android_app->config, country); - - LOGV( - "Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " - "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " - "modetype=%d modenight=%d", - AConfiguration_getMcc(android_app->config), - AConfiguration_getMnc(android_app->config), lang[0], lang[1], country[0], - country[1], AConfiguration_getOrientation(android_app->config), - AConfiguration_getTouchscreen(android_app->config), - AConfiguration_getDensity(android_app->config), - AConfiguration_getKeyboard(android_app->config), - AConfiguration_getNavigation(android_app->config), - AConfiguration_getKeysHidden(android_app->config), - AConfiguration_getNavHidden(android_app->config), - AConfiguration_getSdkVersion(android_app->config), - AConfiguration_getScreenSize(android_app->config), - AConfiguration_getScreenLong(android_app->config), - AConfiguration_getUiModeType(android_app->config), - AConfiguration_getUiModeNight(android_app->config)); + char lang[2], country[2]; + AConfiguration_getLanguage(android_app->config, lang); + AConfiguration_getCountry(android_app->config, country); + + LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " + "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " + "modetype=%d modenight=%d", + AConfiguration_getMcc(android_app->config), AConfiguration_getMnc(android_app->config), + lang[0], lang[1], country[0], country[1], + AConfiguration_getOrientation(android_app->config), + AConfiguration_getTouchscreen(android_app->config), + AConfiguration_getDensity(android_app->config), + AConfiguration_getKeyboard(android_app->config), + AConfiguration_getNavigation(android_app->config), + AConfiguration_getKeysHidden(android_app->config), + AConfiguration_getNavHidden(android_app->config), + AConfiguration_getSdkVersion(android_app->config), + AConfiguration_getScreenSize(android_app->config), + AConfiguration_getScreenLong(android_app->config), + AConfiguration_getUiModeType(android_app->config), + AConfiguration_getUiModeNight(android_app->config)); } void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case UNUSED_APP_CMD_INPUT_CHANGED: - LOGV("UNUSED_APP_CMD_INPUT_CHANGED"); - // Do nothing. This can be used in the future to handle AInputQueue - // natively, like done in NativeActivity. - break; - - case APP_CMD_INIT_WINDOW: - LOGV("APP_CMD_INIT_WINDOW"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = android_app->pendingWindow; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_TERM_WINDOW: - LOGV("APP_CMD_TERM_WINDOW"); - pthread_cond_broadcast(&android_app->cond); - break; - - case APP_CMD_RESUME: - case APP_CMD_START: - case APP_CMD_PAUSE: - case APP_CMD_STOP: - LOGV("activityState=%d", cmd); - pthread_mutex_lock(&android_app->mutex); - android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_CONFIG_CHANGED: - LOGV("APP_CMD_CONFIG_CHANGED"); - AConfiguration_fromAssetManager(android_app->config, - android_app->activity->assetManager); - print_cur_config(android_app); - break; - - case APP_CMD_DESTROY: - LOGV("APP_CMD_DESTROY"); - android_app->destroyRequested = 1; - break; - } + switch (cmd) { + case UNUSED_APP_CMD_INPUT_CHANGED: + LOGV("UNUSED_APP_CMD_INPUT_CHANGED"); + // Do nothing. This can be used in the future to handle AInputQueue + // natively, like done in NativeActivity. + break; + + case APP_CMD_INIT_WINDOW: + LOGV("APP_CMD_INIT_WINDOW"); + pthread_mutex_lock(&android_app->mutex); + android_app->window = android_app->pendingWindow; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_TERM_WINDOW: + LOGV("APP_CMD_TERM_WINDOW"); + pthread_cond_broadcast(&android_app->cond); + break; + + case APP_CMD_RESUME: + case APP_CMD_START: + case APP_CMD_PAUSE: + case APP_CMD_STOP: + LOGV("activityState=%d", cmd); + pthread_mutex_lock(&android_app->mutex); + android_app->activityState = cmd; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_CONFIG_CHANGED: + LOGV("APP_CMD_CONFIG_CHANGED"); + AConfiguration_fromAssetManager(android_app->config, + android_app->activity->assetManager); + print_cur_config(android_app); + break; + + case APP_CMD_DESTROY: + LOGV("APP_CMD_DESTROY"); + android_app->destroyRequested = 1; + break; + } } void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case APP_CMD_TERM_WINDOW: - LOGV("APP_CMD_TERM_WINDOW"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = NULL; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_SAVE_STATE: - LOGV("APP_CMD_SAVE_STATE"); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_RESUME: - free_saved_state(android_app); - break; - } + switch (cmd) { + case APP_CMD_TERM_WINDOW: + LOGV("APP_CMD_TERM_WINDOW"); + pthread_mutex_lock(&android_app->mutex); + android_app->window = NULL; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_SAVE_STATE: + LOGV("APP_CMD_SAVE_STATE"); + pthread_mutex_lock(&android_app->mutex); + android_app->stateSaved = 1; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_RESUME: + free_saved_state(android_app); + break; + } } void app_dummy() {} static void android_app_destroy(struct android_app* android_app) { - LOGV("android_app_destroy!"); - free_saved_state(android_app); - pthread_mutex_lock(&android_app->mutex); + LOGV("android_app_destroy!"); + free_saved_state(android_app); + pthread_mutex_lock(&android_app->mutex); - AConfiguration_delete(android_app->config); - android_app->destroyed = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - // Can't touch android_app object after this. + AConfiguration_delete(android_app->config); + android_app->destroyed = 1; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + // Can't touch android_app object after this. } -static void process_cmd(struct android_app* app, - struct android_poll_source* source) { - int8_t cmd = android_app_read_cmd(app); - android_app_pre_exec_cmd(app, cmd); - if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); - android_app_post_exec_cmd(app, cmd); +static void process_cmd(struct android_app* app, struct android_poll_source* source) { + int8_t cmd = android_app_read_cmd(app); + android_app_pre_exec_cmd(app, cmd); + if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); + android_app_post_exec_cmd(app, cmd); } // This is run on a separate thread (i.e: not the main thread). static void* android_app_entry(void* param) { - struct android_app* android_app = (struct android_app*)param; - int input_buf_idx = 0; - - LOGV("android_app_entry called"); - android_app->config = AConfiguration_new(); - LOGV("android_app = %p", android_app); - LOGV("config = %p", android_app->config); - LOGV("activity = %p", android_app->activity); - LOGV("assetmanager = %p", android_app->activity->assetManager); - AConfiguration_fromAssetManager(android_app->config, - android_app->activity->assetManager); - - print_cur_config(android_app); - - /* initialize event buffers */ - for (input_buf_idx = 0; input_buf_idx < NATIVE_APP_GLUE_MAX_INPUT_BUFFERS; - input_buf_idx++) { - struct android_input_buffer* buf = - &android_app->inputBuffers[input_buf_idx]; - - buf->motionEventsBufferSize = - NATIVE_APP_GLUE_MOTION_EVENTS_DEFAULT_BUF_SIZE; - buf->motionEvents = (GameActivityMotionEvent*)malloc( - sizeof(GameActivityMotionEvent) * buf->motionEventsBufferSize); - - buf->keyEventsBufferSize = NATIVE_APP_GLUE_KEY_EVENTS_DEFAULT_BUF_SIZE; - buf->keyEvents = (GameActivityKeyEvent*)malloc( - sizeof(GameActivityKeyEvent) * buf->keyEventsBufferSize); - } + struct android_app* android_app = (struct android_app*)param; + int input_buf_idx = 0; + + LOGV("android_app_entry called"); + android_app->config = AConfiguration_new(); + LOGV("android_app = %p", android_app); + LOGV("config = %p", android_app->config); + LOGV("activity = %p", android_app->activity); + LOGV("assetmanager = %p", android_app->activity->assetManager); + AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); + + print_cur_config(android_app); + + /* initialize event buffers */ + for (input_buf_idx = 0; input_buf_idx < NATIVE_APP_GLUE_MAX_INPUT_BUFFERS; input_buf_idx++) { + struct android_input_buffer* buf = &android_app->inputBuffers[input_buf_idx]; + + buf->motionEventsBufferSize = NATIVE_APP_GLUE_MOTION_EVENTS_DEFAULT_BUF_SIZE; + buf->motionEvents = (GameActivityMotionEvent*)malloc(sizeof(GameActivityMotionEvent) * + buf->motionEventsBufferSize); + + buf->keyEventsBufferSize = NATIVE_APP_GLUE_KEY_EVENTS_DEFAULT_BUF_SIZE; + buf->keyEvents = (GameActivityKeyEvent*)malloc(sizeof(GameActivityKeyEvent) * + buf->keyEventsBufferSize); + } - android_app->cmdPollSource.id = LOOPER_ID_MAIN; - android_app->cmdPollSource.app = android_app; - android_app->cmdPollSource.process = process_cmd; + android_app->cmdPollSource.id = LOOPER_ID_MAIN; + android_app->cmdPollSource.app = android_app; + android_app->cmdPollSource.process = process_cmd; - ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, - ALOOPER_EVENT_INPUT, NULL, &android_app->cmdPollSource); - android_app->looper = looper; + ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, + &android_app->cmdPollSource); + android_app->looper = looper; - pthread_mutex_lock(&android_app->mutex); - android_app->running = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + pthread_mutex_lock(&android_app->mutex); + android_app->running = 1; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); - _rust_glue_entry(android_app); + _rust_glue_entry(android_app); - android_app_destroy(android_app); - return NULL; + android_app_destroy(android_app); + return NULL; } // Codes from https://developer.android.com/reference/android/view/KeyEvent @@ -250,13 +241,13 @@ static void* android_app_entry(void* param) { // Double-buffer the key event filter to avoid race condition. static bool default_key_filter(const GameActivityKeyEvent* event) { - // Ignore camera, volume, etc. buttons - return !(event->keyCode == KEY_EVENT_KEYCODE_VOLUME_DOWN || - event->keyCode == KEY_EVENT_KEYCODE_VOLUME_MUTE || - event->keyCode == KEY_EVENT_KEYCODE_VOLUME_UP || - event->keyCode == KEY_EVENT_KEYCODE_CAMERA || - event->keyCode == KEY_EVENT_KEYCODE_ZOOM_IN || - event->keyCode == KEY_EVENT_KEYCODE_ZOOM_OUT); + // Ignore camera, volume, etc. buttons + return !(event->keyCode == KEY_EVENT_KEYCODE_VOLUME_DOWN || + event->keyCode == KEY_EVENT_KEYCODE_VOLUME_MUTE || + event->keyCode == KEY_EVENT_KEYCODE_VOLUME_UP || + event->keyCode == KEY_EVENT_KEYCODE_CAMERA || + event->keyCode == KEY_EVENT_KEYCODE_ZOOM_IN || + event->keyCode == KEY_EVENT_KEYCODE_ZOOM_OUT); } // See @@ -264,526 +255,518 @@ static bool default_key_filter(const GameActivityKeyEvent* event) { #define SOURCE_TOUCHSCREEN 0x00001002 static bool default_motion_filter(const GameActivityMotionEvent* event) { - // Ignore any non-touch events. - return (event->source & SOURCE_TOUCHSCREEN) != 0; + // Ignore any non-touch events. + return (event->source & SOURCE_TOUCHSCREEN) != 0; } // -------------------------------------------------------------------- // Native activity interaction (called from main thread) // -------------------------------------------------------------------- -static struct android_app* android_app_create(GameActivity* activity, - void* savedState, +static struct android_app* android_app_create(GameActivity* activity, void* savedState, size_t savedStateSize) { - // struct android_app* android_app = calloc(1, sizeof(struct android_app)); - struct android_app* android_app = - (struct android_app*)malloc(sizeof(struct android_app)); - memset(android_app, 0, sizeof(struct android_app)); - android_app->activity = activity; - - pthread_mutex_init(&android_app->mutex, NULL); - pthread_cond_init(&android_app->cond, NULL); - - if (savedState != NULL) { - android_app->savedState = malloc(savedStateSize); - android_app->savedStateSize = savedStateSize; - memcpy(android_app->savedState, savedState, savedStateSize); - } - - android_app->mainLooper = ALooper_forThread(); - if (android_app->mainLooper == NULL) { - LOGE("Failed to get main looper"); - return NULL; - } - ALooper_acquire(android_app->mainLooper); - - int msgpipe[2]; - if (pipe(msgpipe)) { - LOGE("could not create pipe: %s", strerror(errno)); - return NULL; - } - android_app->msgread = msgpipe[0]; - android_app->msgwrite = msgpipe[1]; - - android_app->keyEventFilter = default_key_filter; - android_app->motionEventFilter = default_motion_filter; + // struct android_app* android_app = calloc(1, sizeof(struct android_app)); + struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); + memset(android_app, 0, sizeof(struct android_app)); + android_app->activity = activity; + + pthread_mutex_init(&android_app->mutex, NULL); + pthread_cond_init(&android_app->cond, NULL); + + if (savedState != NULL) { + android_app->savedState = malloc(savedStateSize); + android_app->savedStateSize = savedStateSize; + memcpy(android_app->savedState, savedState, savedStateSize); + } - LOGV("Launching android_app_entry in a thread"); - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&android_app->thread, &attr, android_app_entry, android_app); + android_app->mainLooper = ALooper_forThread(); + if (android_app->mainLooper == NULL) { + LOGE("Failed to get main looper"); + return NULL; + } + ALooper_acquire(android_app->mainLooper); - // Wait for thread to start. - pthread_mutex_lock(&android_app->mutex); - while (!android_app->running) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); + int msgpipe[2]; + if (pipe(msgpipe)) { + LOGE("could not create pipe: %s", strerror(errno)); + return NULL; + } + android_app->msgread = msgpipe[0]; + android_app->msgwrite = msgpipe[1]; + + android_app->keyEventFilter = default_key_filter; + android_app->motionEventFilter = default_motion_filter; + + LOGV("Launching android_app_entry in a thread"); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&android_app->thread, &attr, android_app_entry, android_app); + + // Wait for thread to start. + pthread_mutex_lock(&android_app->mutex); + while (!android_app->running) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); - return android_app; + return android_app; } -void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { - if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { - LOGE("Failure writing android_app cmd: %s", strerror(errno)); - } +bool android_app_write_cmd(struct android_app* android_app, int8_t cmd) { + if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { + LOGE("Failure writing android_app cmd: %s", strerror(errno)); + return false; + } + return true; } -static void android_app_set_window(struct android_app* android_app, - ANativeWindow* window) { - LOGV("android_app_set_window called"); - pthread_mutex_lock(&android_app->mutex); +static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { + LOGV("android_app_set_window called"); + pthread_mutex_lock(&android_app->mutex); - // NB: we have to consider that the native thread could have already - // (gracefully) exit (setting android_app->destroyed) and so we need - // to be careful to avoid a deadlock waiting for a thread that's - // already exit. - if (android_app->destroyed) { + // NB: we have to consider that the native thread could have already + // (gracefully) exit (setting android_app->destroyed) and so we need + // to be careful to avoid a deadlock waiting for a thread that's + // already exit. + if (android_app->destroyed) { + pthread_mutex_unlock(&android_app->mutex); + return; + } + if (android_app->pendingWindow != NULL) { + android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); + } + android_app->pendingWindow = window; + if (window != NULL) { + android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); + } + while (android_app->window != android_app->pendingWindow) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); +} + +static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { + pthread_mutex_lock(&android_app->mutex); + // NB: we have to consider that the native thread could have already + // (gracefully) exit (setting android_app->destroyed) and so we need + // to be careful to avoid a deadlock waiting for a thread that's + // already exit. + if (android_app->destroyed) { + pthread_mutex_unlock(&android_app->mutex); + return; + } + if (android_app_write_cmd(android_app, cmd)) { + struct timespec timeout; + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += NATIVE_APP_GLUE_CMD_WAIT_TIMEOUT_SECONDS; + + int wait_result = 0; + while (android_app->activityState != cmd) { + wait_result = pthread_cond_timedwait(&android_app->cond, &android_app->mutex, &timeout); + if (wait_result == ETIMEDOUT) { + LOGE("android_app_set_activity_state timed out waiting for cmd %d", cmd); + break; + } + } + } pthread_mutex_unlock(&android_app->mutex); - return; - } - if (android_app->pendingWindow != NULL) { - android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); - } - android_app->pendingWindow = window; - if (window != NULL) { - android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); - } - while (android_app->window != android_app->pendingWindow) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_activity_state(struct android_app* android_app, - int8_t cmd) { - pthread_mutex_lock(&android_app->mutex); - - // NB: we have to consider that the native thread could have already - // (gracefully) exit (setting android_app->destroyed) and so we need - // to be careful to avoid a deadlock waiting for a thread that's - // already exit. - if (!android_app->destroyed) { - android_app_write_cmd(android_app, cmd); - while (android_app->activityState != cmd) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - } - pthread_mutex_unlock(&android_app->mutex); } static void android_app_free(struct android_app* android_app) { - int input_buf_idx = 0; + int input_buf_idx = 0; - pthread_mutex_lock(&android_app->mutex); + pthread_mutex_lock(&android_app->mutex); - // It's possible that onDestroy is called after we have already 'destroyed' - // the app (via `android_app_destroy` due to `android_main` returning. - // - // In this case `->destroyed` will already be set (so we won't deadlock in - // the loop below) but we still need to close the messaging fds and finish - // freeing the android_app + // It's possible that onDestroy is called after we have already 'destroyed' + // the app (via `android_app_destroy` due to `android_main` returning. + // + // In this case `->destroyed` will already be set (so we won't deadlock in + // the loop below) but we still need to close the messaging fds and finish + // freeing the android_app - android_app_write_cmd(android_app, APP_CMD_DESTROY); - while (!android_app->destroyed) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); + android_app_write_cmd(android_app, APP_CMD_DESTROY); + while (!android_app->destroyed) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); - for (input_buf_idx = 0; input_buf_idx < NATIVE_APP_GLUE_MAX_INPUT_BUFFERS; - input_buf_idx++) { - struct android_input_buffer* buf = - &android_app->inputBuffers[input_buf_idx]; + for (input_buf_idx = 0; input_buf_idx < NATIVE_APP_GLUE_MAX_INPUT_BUFFERS; input_buf_idx++) { + struct android_input_buffer* buf = &android_app->inputBuffers[input_buf_idx]; - android_app_clear_motion_events(buf); - free(buf->motionEvents); - free(buf->keyEvents); - } + android_app_clear_motion_events(buf); + free(buf->motionEvents); + free(buf->keyEvents); + } - close(android_app->msgread); - close(android_app->msgwrite); + close(android_app->msgread); + close(android_app->msgwrite); - pthread_cond_destroy(&android_app->cond); - pthread_mutex_destroy(&android_app->mutex); + pthread_cond_destroy(&android_app->cond); + pthread_mutex_destroy(&android_app->mutex); - if (android_app->mainLooper != NULL) { - ALooper_release(android_app->mainLooper); - } + if (android_app->mainLooper != NULL) { + ALooper_release(android_app->mainLooper); + } - free(android_app); + free(android_app); } static inline struct android_app* ToApp(GameActivity* activity) { - return (struct android_app*)activity->instance; + return (struct android_app*)activity->instance; } static void onDestroy(GameActivity* activity) { - LOGV("Destroy: %p", activity); - android_app_free(ToApp(activity)); + LOGV("Destroy: %p", activity); + android_app_free(ToApp(activity)); } static void onStart(GameActivity* activity) { - LOGV("Start: %p", activity); - android_app_set_activity_state(ToApp(activity), APP_CMD_START); + LOGV("Start: %p", activity); + android_app_set_activity_state(ToApp(activity), APP_CMD_START); } static void onResume(GameActivity* activity) { - LOGV("Resume: %p", activity); - android_app_set_activity_state(ToApp(activity), APP_CMD_RESUME); + LOGV("Resume: %p", activity); + android_app_set_activity_state(ToApp(activity), APP_CMD_RESUME); } -static void onSaveInstanceState(GameActivity* activity, - SaveInstanceStateRecallback recallback, +static void onSaveInstanceState(GameActivity* activity, SaveInstanceStateRecallback recallback, void* context) { - LOGV("SaveInstanceState: %p", activity); - - struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); - - // NB: we have to consider that the native thread could have already - // (gracefully) exit (setting android_app->destroyed) and so we need - // to be careful to avoid a deadlock waiting for a thread that's - // already exit. - if (android_app->destroyed) { - pthread_mutex_unlock(&android_app->mutex); - return; - } + LOGV("SaveInstanceState: %p", activity); + + struct android_app* android_app = ToApp(activity); + pthread_mutex_lock(&android_app->mutex); + + // NB: we have to consider that the native thread could have already + // (gracefully) exit (setting android_app->destroyed) and so we need + // to be careful to avoid a deadlock waiting for a thread that's + // already exit. + if (android_app->destroyed) { + pthread_mutex_unlock(&android_app->mutex); + return; + } - android_app->stateSaved = 0; - android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); - while (!android_app->stateSaved) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } + android_app->stateSaved = 0; + android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); + while (!android_app->stateSaved) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } - if (android_app->savedState != NULL) { - // Tell the Java side about our state. - recallback((const char*)android_app->savedState, - android_app->savedStateSize, context); - // Now we can free it. - free(android_app->savedState); - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } + if (android_app->savedState != NULL) { + // Tell the Java side about our state. + recallback((const char*)android_app->savedState, android_app->savedStateSize, context); + // Now we can free it. + free(android_app->savedState); + android_app->savedState = NULL; + android_app->savedStateSize = 0; + } - pthread_mutex_unlock(&android_app->mutex); + pthread_mutex_unlock(&android_app->mutex); } static void onPause(GameActivity* activity) { - LOGV("Pause: %p", activity); - android_app_set_activity_state(ToApp(activity), APP_CMD_PAUSE); + LOGV("Pause: %p", activity); + android_app_set_activity_state(ToApp(activity), APP_CMD_PAUSE); } static void onStop(GameActivity* activity) { - LOGV("Stop: %p", activity); - android_app_set_activity_state(ToApp(activity), APP_CMD_STOP); + LOGV("Stop: %p", activity); + android_app_set_activity_state(ToApp(activity), APP_CMD_STOP); } static void onConfigurationChanged(GameActivity* activity) { - LOGV("ConfigurationChanged: %p", activity); - android_app_write_cmd(ToApp(activity), APP_CMD_CONFIG_CHANGED); + LOGV("ConfigurationChanged: %p", activity); + android_app_write_cmd(ToApp(activity), APP_CMD_CONFIG_CHANGED); } static void onTrimMemory(GameActivity* activity, int level) { - LOGV("TrimMemory: %p %d", activity, level); - android_app_write_cmd(ToApp(activity), APP_CMD_LOW_MEMORY); + LOGV("TrimMemory: %p %d", activity, level); + android_app_write_cmd(ToApp(activity), APP_CMD_LOW_MEMORY); } static void onWindowFocusChanged(GameActivity* activity, bool focused) { - LOGV("WindowFocusChanged: %p -- %d", activity, focused); - android_app_write_cmd(ToApp(activity), - focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); + LOGV("WindowFocusChanged: %p -- %d", activity, focused); + android_app_write_cmd(ToApp(activity), focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); } -static void onNativeWindowCreated(GameActivity* activity, - ANativeWindow* window) { - LOGV("NativeWindowCreated: %p -- %p", activity, window); - android_app_set_window(ToApp(activity), window); +static void onNativeWindowCreated(GameActivity* activity, ANativeWindow* window) { + LOGV("NativeWindowCreated: %p -- %p", activity, window); + android_app_set_window(ToApp(activity), window); } -static void onNativeWindowDestroyed(GameActivity* activity, - ANativeWindow* window) { - LOGV("NativeWindowDestroyed: %p -- %p", activity, window); - android_app_set_window(ToApp(activity), NULL); +static void onNativeWindowDestroyed(GameActivity* activity, ANativeWindow* window) { + LOGV("NativeWindowDestroyed: %p -- %p", activity, window); + android_app_set_window(ToApp(activity), NULL); } -static void onNativeWindowRedrawNeeded(GameActivity* activity, - ANativeWindow* window) { - LOGV("NativeWindowRedrawNeeded: %p -- %p", activity, window); - android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_REDRAW_NEEDED); +static void onNativeWindowRedrawNeeded(GameActivity* activity, ANativeWindow* window) { + LOGV("NativeWindowRedrawNeeded: %p -- %p", activity, window); + android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_REDRAW_NEEDED); } -static void onNativeWindowResized(GameActivity* activity, ANativeWindow* window, - int32_t width, int32_t height) { - LOGV("NativeWindowResized: %p -- %p ( %d x %d )", activity, window, width, - height); - android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_RESIZED); +static void onNativeWindowResized(GameActivity* activity, ANativeWindow* window, int32_t width, + int32_t height) { + LOGV("NativeWindowResized: %p -- %p ( %d x %d )", activity, window, width, height); + android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_RESIZED); } void android_app_set_motion_event_filter(struct android_app* app, android_motion_event_filter filter) { - pthread_mutex_lock(&app->mutex); - app->motionEventFilter = filter; - pthread_mutex_unlock(&app->mutex); + pthread_mutex_lock(&app->mutex); + app->motionEventFilter = filter; + pthread_mutex_unlock(&app->mutex); } bool android_app_input_available_wake_up(struct android_app* app) { - pthread_mutex_lock(&app->mutex); - bool available = app->inputAvailableWakeUp; - app->inputAvailableWakeUp = false; - pthread_mutex_unlock(&app->mutex); - return available; + pthread_mutex_lock(&app->mutex); + bool available = app->inputAvailableWakeUp; + app->inputAvailableWakeUp = false; + pthread_mutex_unlock(&app->mutex); + return available; } // NB: should be called with the android_app->mutex held already static void notifyInput(struct android_app* android_app) { - // Don't spam the mainloop with wake ups if we've already sent one - if (android_app->inputSwapPending) { - return; - } - - if (android_app->looper != NULL) { - // for the app thread to know why it received the wake() up - android_app->inputAvailableWakeUp = true; - android_app->inputSwapPending = true; - ALooper_wake(android_app->looper); - } -} - -static bool onTouchEvent(GameActivity* activity, - const GameActivityMotionEvent* event) { - struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); - - // NB: we have to consider that the native thread could have already - // (gracefully) exit (setting android_app->destroyed) and so we need - // to be careful to avoid a deadlock waiting for a thread that's - // already exit. - if (android_app->destroyed) { - pthread_mutex_unlock(&android_app->mutex); - return false; - } + // Don't spam the mainloop with wake ups if we've already sent one + if (android_app->inputSwapPending) { + return; + } - if (android_app->motionEventFilter != NULL && - !android_app->motionEventFilter(event)) { - pthread_mutex_unlock(&android_app->mutex); - return false; - } + if (android_app->looper != NULL) { + // for the app thread to know why it received the wake() up + android_app->inputAvailableWakeUp = true; + android_app->inputSwapPending = true; + ALooper_wake(android_app->looper); + } +} - struct android_input_buffer* inputBuffer = - &android_app->inputBuffers[android_app->currentInputBuffer]; +static bool onTouchEvent(GameActivity* activity, const GameActivityMotionEvent* event) { + struct android_app* android_app = ToApp(activity); + pthread_mutex_lock(&android_app->mutex); - // Add to the list of active motion events - if (inputBuffer->motionEventsCount >= inputBuffer->motionEventsBufferSize) { - inputBuffer->motionEventsBufferSize *= 2; - inputBuffer->motionEvents = (GameActivityMotionEvent*)realloc( - inputBuffer->motionEvents, - sizeof(GameActivityMotionEvent) * inputBuffer->motionEventsBufferSize); + // NB: we have to consider that the native thread could have already + // (gracefully) exit (setting android_app->destroyed) and so we need + // to be careful to avoid a deadlock waiting for a thread that's + // already exit. + if (android_app->destroyed) { + pthread_mutex_unlock(&android_app->mutex); + return false; + } - if (inputBuffer->motionEvents == NULL) { - LOGE("onTouchEvent: out of memory"); - abort(); + if (android_app->motionEventFilter != NULL && !android_app->motionEventFilter(event)) { + pthread_mutex_unlock(&android_app->mutex); + return false; } - } - int new_ix = inputBuffer->motionEventsCount; - memcpy(&inputBuffer->motionEvents[new_ix], event, - sizeof(GameActivityMotionEvent)); - ++inputBuffer->motionEventsCount; - notifyInput(android_app); + struct android_input_buffer* inputBuffer = + &android_app->inputBuffers[android_app->currentInputBuffer]; + + // Add to the list of active motion events + if (inputBuffer->motionEventsCount >= inputBuffer->motionEventsBufferSize) { + inputBuffer->motionEventsBufferSize *= 2; + inputBuffer->motionEvents = + (GameActivityMotionEvent*)realloc(inputBuffer->motionEvents, + sizeof(GameActivityMotionEvent) * + inputBuffer->motionEventsBufferSize); + + if (inputBuffer->motionEvents == NULL) { + LOGE("onTouchEvent: out of memory"); + abort(); + } + } + + int new_ix = inputBuffer->motionEventsCount; + memcpy(&inputBuffer->motionEvents[new_ix], event, sizeof(GameActivityMotionEvent)); + ++inputBuffer->motionEventsCount; + notifyInput(android_app); - //android_app_write_cmd(android_app, APP_CMD_TOUCH_EVENT); - pthread_mutex_unlock(&android_app->mutex); - return true; + // android_app_write_cmd(android_app, APP_CMD_TOUCH_EVENT); + pthread_mutex_unlock(&android_app->mutex); + return true; } -struct android_input_buffer* android_app_swap_input_buffers( - struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); +struct android_input_buffer* android_app_swap_input_buffers(struct android_app* android_app) { + pthread_mutex_lock(&android_app->mutex); - struct android_input_buffer* inputBuffer = - &android_app->inputBuffers[android_app->currentInputBuffer]; + struct android_input_buffer* inputBuffer = + &android_app->inputBuffers[android_app->currentInputBuffer]; - if (inputBuffer->motionEventsCount == 0 && inputBuffer->keyEventsCount == 0) { - inputBuffer = NULL; - } else { - android_app->currentInputBuffer = (android_app->currentInputBuffer + 1) % - NATIVE_APP_GLUE_MAX_INPUT_BUFFERS; - } + if (inputBuffer->motionEventsCount == 0 && inputBuffer->keyEventsCount == 0) { + inputBuffer = NULL; + } else { + android_app->currentInputBuffer = + (android_app->currentInputBuffer + 1) % NATIVE_APP_GLUE_MAX_INPUT_BUFFERS; + } - android_app->inputSwapPending = false; - android_app->inputAvailableWakeUp = false; + android_app->inputSwapPending = false; + android_app->inputAvailableWakeUp = false; - pthread_mutex_unlock(&android_app->mutex); + pthread_mutex_unlock(&android_app->mutex); - return inputBuffer; + return inputBuffer; } void android_app_clear_motion_events(struct android_input_buffer* inputBuffer) { - // We do not need to lock here if the inputBuffer has already been swapped - // as is handled by the game loop thread - while (inputBuffer->motionEventsCount > 0) { - GameActivityMotionEvent_destroy( - &inputBuffer->motionEvents[inputBuffer->motionEventsCount - 1]); + // We do not need to lock here if the inputBuffer has already been swapped + // as is handled by the game loop thread + while (inputBuffer->motionEventsCount > 0) { + GameActivityMotionEvent_destroy( + &inputBuffer->motionEvents[inputBuffer->motionEventsCount - 1]); - inputBuffer->motionEventsCount--; - } - assert(inputBuffer->motionEventsCount == 0); + inputBuffer->motionEventsCount--; + } + assert(inputBuffer->motionEventsCount == 0); } -void android_app_set_key_event_filter(struct android_app* app, - android_key_event_filter filter) { - pthread_mutex_lock(&app->mutex); - app->keyEventFilter = filter; - pthread_mutex_unlock(&app->mutex); +void android_app_set_key_event_filter(struct android_app* app, android_key_event_filter filter) { + pthread_mutex_lock(&app->mutex); + app->keyEventFilter = filter; + pthread_mutex_unlock(&app->mutex); } static bool onKey(GameActivity* activity, const GameActivityKeyEvent* event) { - struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); - - // NB: we have to consider that the native thread could have already - // (gracefully) exit (setting android_app->destroyed) and so we need - // to be careful to avoid a deadlock waiting for a thread that's - // already exit. - if (android_app->destroyed) { - pthread_mutex_unlock(&android_app->mutex); - return false; - } - - if (android_app->keyEventFilter != NULL && - !android_app->keyEventFilter(event)) { - pthread_mutex_unlock(&android_app->mutex); - return false; - } - - struct android_input_buffer* inputBuffer = - &android_app->inputBuffers[android_app->currentInputBuffer]; + struct android_app* android_app = ToApp(activity); + pthread_mutex_lock(&android_app->mutex); + + // NB: we have to consider that the native thread could have already + // (gracefully) exit (setting android_app->destroyed) and so we need + // to be careful to avoid a deadlock waiting for a thread that's + // already exit. + if (android_app->destroyed) { + pthread_mutex_unlock(&android_app->mutex); + return false; + } - // Add to the list of active key down events - if (inputBuffer->keyEventsCount >= inputBuffer->keyEventsBufferSize) { - inputBuffer->keyEventsBufferSize = inputBuffer->keyEventsBufferSize * 2; - inputBuffer->keyEvents = (GameActivityKeyEvent*)realloc( - inputBuffer->keyEvents, - sizeof(GameActivityKeyEvent) * inputBuffer->keyEventsBufferSize); + if (android_app->keyEventFilter != NULL && !android_app->keyEventFilter(event)) { + pthread_mutex_unlock(&android_app->mutex); + return false; + } - if (inputBuffer->keyEvents == NULL) { - LOGE("onKey: out of memory"); - abort(); + struct android_input_buffer* inputBuffer = + &android_app->inputBuffers[android_app->currentInputBuffer]; + + // Add to the list of active key down events + if (inputBuffer->keyEventsCount >= inputBuffer->keyEventsBufferSize) { + inputBuffer->keyEventsBufferSize = inputBuffer->keyEventsBufferSize * 2; + inputBuffer->keyEvents = + (GameActivityKeyEvent*)realloc(inputBuffer->keyEvents, + sizeof(GameActivityKeyEvent) * + inputBuffer->keyEventsBufferSize); + + if (inputBuffer->keyEvents == NULL) { + LOGE("onKey: out of memory"); + abort(); + } } - } - int new_ix = inputBuffer->keyEventsCount; - memcpy(&inputBuffer->keyEvents[new_ix], event, sizeof(GameActivityKeyEvent)); - ++inputBuffer->keyEventsCount; - notifyInput(android_app); + int new_ix = inputBuffer->keyEventsCount; + memcpy(&inputBuffer->keyEvents[new_ix], event, sizeof(GameActivityKeyEvent)); + ++inputBuffer->keyEventsCount; + notifyInput(android_app); - //android_app_write_cmd(android_app, APP_CMD_KEY_EVENT); - pthread_mutex_unlock(&android_app->mutex); - return true; + // android_app_write_cmd(android_app, APP_CMD_KEY_EVENT); + pthread_mutex_unlock(&android_app->mutex); + return true; } void android_app_clear_key_events(struct android_input_buffer* inputBuffer) { - inputBuffer->keyEventsCount = 0; + inputBuffer->keyEventsCount = 0; } -static void onTextInputEvent(GameActivity* activity, - const GameTextInputState* state) { - struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); - if (!android_app->destroyed) { - android_app->textInputState = 1; - notifyInput(android_app); - } - pthread_mutex_unlock(&android_app->mutex); +static void onTextInputEvent(GameActivity* activity, const GameTextInputState* state) { + struct android_app* android_app = ToApp(activity); + pthread_mutex_lock(&android_app->mutex); + if (!android_app->destroyed) { + android_app->textInputState = 1; + notifyInput(android_app); + } + pthread_mutex_unlock(&android_app->mutex); } static void onWindowInsetsChanged(GameActivity* activity) { - LOGV("WindowInsetsChanged: %p", activity); - android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_INSETS_CHANGED); + LOGV("WindowInsetsChanged: %p", activity); + android_app_write_cmd(ToApp(activity), APP_CMD_WINDOW_INSETS_CHANGED); } static void onContentRectChanged(GameActivity* activity, const ARect* rect) { - LOGV("ContentRectChanged: %p -- (%d %d) (%d %d)", activity, rect->left, - rect->top, rect->right, rect->bottom); + LOGV("ContentRectChanged: %p -- (%d %d) (%d %d)", activity, rect->left, rect->top, rect->right, + rect->bottom); - struct android_app* android_app = ToApp(activity); + struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); - android_app->contentRect = *rect; + pthread_mutex_lock(&android_app->mutex); + android_app->contentRect = *rect; - android_app_write_cmd(android_app, APP_CMD_CONTENT_RECT_CHANGED); - pthread_mutex_unlock(&android_app->mutex); + android_app_write_cmd(android_app, APP_CMD_CONTENT_RECT_CHANGED); + pthread_mutex_unlock(&android_app->mutex); } -static void onSoftwareKeyboardVisibilityChanged(GameActivity* activity, - bool visible) { - LOGV("SoftwareKeyboardVisibilityChanged: %p -- %d", activity, (int)visible); +static void onSoftwareKeyboardVisibilityChanged(GameActivity* activity, bool visible) { + LOGV("SoftwareKeyboardVisibilityChanged: %p -- %d", activity, (int)visible); - struct android_app* android_app = ToApp(activity); + struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); - android_app->softwareKeyboardVisible = visible; + pthread_mutex_lock(&android_app->mutex); + android_app->softwareKeyboardVisible = visible; - android_app_write_cmd(android_app, APP_CMD_SOFTWARE_KB_VIS_CHANGED); - pthread_mutex_unlock(&android_app->mutex); + android_app_write_cmd(android_app, APP_CMD_SOFTWARE_KB_VIS_CHANGED); + pthread_mutex_unlock(&android_app->mutex); } static bool onEditorAction(GameActivity* activity, int action) { - LOGV("EditorAction: %p -- %d", activity, action); + LOGV("EditorAction: %p -- %d", activity, action); - struct android_app* android_app = ToApp(activity); + struct android_app* android_app = ToApp(activity); - pthread_mutex_lock(&android_app->mutex); + pthread_mutex_lock(&android_app->mutex); - // XXX: this is a racy design that could lose InputConnection actions if the - // application doesn't manage to look at app->editorAction before another - // action is delivered. - if (android_app->pendingEditorAction) { - LOGW("Dropping editor action %d because previous action %d not yet " - "handled", - action, android_app->editorAction); - } - android_app->editorAction = action; - android_app->pendingEditorAction = true; - notifyInput(android_app); - // TODO: buffer IME text events and editor actions like other input events + // XXX: this is a racy design that could lose InputConnection actions if the + // application doesn't manage to look at app->editorAction before another + // action is delivered. + if (android_app->pendingEditorAction) { + LOGW("Dropping editor action %d because previous action %d not yet " + "handled", + action, android_app->editorAction); + } + android_app->editorAction = action; + android_app->pendingEditorAction = true; + notifyInput(android_app); + // TODO: buffer IME text events and editor actions like other input events - //android_app_write_cmd(android_app, APP_CMD_EDITOR_ACTION); - pthread_mutex_unlock(&android_app->mutex); - return true; + // android_app_write_cmd(android_app, APP_CMD_EDITOR_ACTION); + pthread_mutex_unlock(&android_app->mutex); + return true; } // XXX: This symbol is renamed with a _C suffix so we can implement // `GameActivity_onCreate` as a wrapper in Rust that does some additional setup // before calling this function, JNIEXPORT -void GameActivity_onCreate_C(GameActivity* activity, void* savedState, - size_t savedStateSize) { - LOGV("Creating: %p", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = onSaveInstanceState; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onTouchEvent = onTouchEvent; - activity->callbacks->onKeyDown = onKey; - activity->callbacks->onKeyUp = onKey; - activity->callbacks->onTextInputEvent = onTextInputEvent; - activity->callbacks->onConfigurationChanged = onConfigurationChanged; - activity->callbacks->onTrimMemory = onTrimMemory; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded; - activity->callbacks->onNativeWindowResized = onNativeWindowResized; - activity->callbacks->onWindowInsetsChanged = onWindowInsetsChanged; - activity->callbacks->onContentRectChanged = onContentRectChanged; - activity->callbacks->onSoftwareKeyboardVisibilityChanged = - onSoftwareKeyboardVisibilityChanged; - activity->callbacks->onEditorAction = onEditorAction; - LOGV("Callbacks set: %p", activity->callbacks); - - activity->instance = android_app_create(activity, savedState, savedStateSize); +void GameActivity_onCreate_C(GameActivity* activity, void* savedState, size_t savedStateSize) { + LOGV("Creating: %p", activity); + activity->callbacks->onDestroy = onDestroy; + activity->callbacks->onStart = onStart; + activity->callbacks->onResume = onResume; + activity->callbacks->onSaveInstanceState = onSaveInstanceState; + activity->callbacks->onPause = onPause; + activity->callbacks->onStop = onStop; + activity->callbacks->onTouchEvent = onTouchEvent; + activity->callbacks->onKeyDown = onKey; + activity->callbacks->onKeyUp = onKey; + activity->callbacks->onTextInputEvent = onTextInputEvent; + activity->callbacks->onConfigurationChanged = onConfigurationChanged; + activity->callbacks->onTrimMemory = onTrimMemory; + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; + activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded; + activity->callbacks->onNativeWindowResized = onNativeWindowResized; + activity->callbacks->onWindowInsetsChanged = onWindowInsetsChanged; + activity->callbacks->onContentRectChanged = onContentRectChanged; + activity->callbacks->onSoftwareKeyboardVisibilityChanged = onSoftwareKeyboardVisibilityChanged; + activity->callbacks->onEditorAction = onEditorAction; + LOGV("Callbacks set: %p", activity->callbacks); + + activity->instance = android_app_create(activity, savedState, savedStateSize); } diff --git a/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h b/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h index 28645446..e54bc22a 100644 --- a/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h +++ b/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/include/game-text-input/gametextinput.h @@ -32,13 +32,13 @@ extern "C" { #endif +#define GAMETEXTINPUT_VERSION_REVISION 7cd950d0022d01f1e7e2b470aba5a7b1abacdfaa #define GAMETEXTINPUT_MAJOR_VERSION 4 -#define GAMETEXTINPUT_MINOR_VERSION 0 +#define GAMETEXTINPUT_MINOR_VERSION 3 #define GAMETEXTINPUT_BUGFIX_VERSION 0 -#define GAMETEXTINPUT_PACKED_VERSION \ - ANDROID_GAMESDK_PACKED_VERSION(GAMETEXTINPUT_MAJOR_VERSION, \ - GAMETEXTINPUT_MINOR_VERSION, \ - GAMETEXTINPUT_BUGFIX_VERSION) +#define GAMETEXTINPUT_PACKED_VERSION \ + ANDROID_GAMESDK_PACKED_VERSION(GAMETEXTINPUT_MAJOR_VERSION, GAMETEXTINPUT_MINOR_VERSION, \ + GAMETEXTINPUT_BUGFIX_VERSION) /** * This struct holds a span within a region of text from start (inclusive) to @@ -46,10 +46,10 @@ extern "C" { * start==end. An undefined span is specified with start = end = SPAN_UNDEFINED. */ typedef struct GameTextInputSpan { - /** The start of the region (inclusive). */ - int32_t start; - /** The end of the region (exclusive). */ - int32_t end; + /** The start of the region (inclusive). */ + int32_t start; + /** The end of the region (exclusive). */ + int32_t end; } GameTextInputSpan; /** @@ -65,23 +65,23 @@ enum GameTextInputSpanFlag : int32_t { SPAN_UNDEFINED = -1 }; * GameTextInput_setState to read and modify the state that an IME is editing. */ typedef struct GameTextInputState { - /** - * Text owned by the state, as a modified UTF-8 string. Null-terminated. - * https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 - */ - const char *text_UTF8; - /** - * Length in bytes of text_UTF8, *not* including the null at end. - */ - int32_t text_length; - /** - * A selection defined on the text. - */ - GameTextInputSpan selection; - /** - * A composing region defined on the text. - */ - GameTextInputSpan composingRegion; + /** + * Text owned by the state, as a modified UTF-8 string. Null-terminated. + * https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 + */ + const char* text_UTF8; + /** + * Length in bytes of text_UTF8, *not* including the null at end. + */ + int32_t text_length; + /** + * A selection defined on the text. + */ + GameTextInputSpan selection; + /** + * A composing region defined on the text. + */ + GameTextInputSpan composingRegion; } GameTextInputState; /** @@ -90,8 +90,8 @@ typedef struct GameTextInputState { * @param state State, owned by the library, that will be valid for the duration * of the callback. */ -typedef void (*GameTextInputGetStateCallback)( - void *context, const struct GameTextInputState *state); +typedef void (*GameTextInputGetStateCallback)(void* context, + const struct GameTextInputState* state); /** * Opaque handle to the GameTextInput API. @@ -102,13 +102,14 @@ typedef struct GameTextInput GameTextInput; * Initialize the GameTextInput library. * If called twice without GameTextInput_destroy being called, the same pointer * will be returned and a warning will be issued. - * @param env A JNI env valid on the calling thread. + * @param env A JNI env valid on the calling thread. All other calls to the resulting GameTextInput + * object must be done on the same calling thread. * @param max_string_size The maximum length of a string that can be edited. If * zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated * at initialization. * @return A handle to the library. */ -GameTextInput *GameTextInput_init(JNIEnv *env, uint32_t max_string_size); +GameTextInput* GameTextInput_init(JNIEnv* env, uint32_t max_string_size); /** * When using GameTextInput, you need to create a gametextinput.InputConnection @@ -118,8 +119,7 @@ GameTextInput *GameTextInput_init(JNIEnv *env, uint32_t max_string_size); * @param input A valid GameTextInput library handle. * @param inputConnection A gametextinput.InputConnection object. */ -void GameTextInput_setInputConnection(GameTextInput *input, - jobject inputConnection); +void GameTextInput_setInputConnection(GameTextInput* input, jobject inputConnection); /** * Unless using GameActivity, it is required to call this function from your @@ -129,7 +129,7 @@ void GameTextInput_setInputConnection(GameTextInput *input, * @param input A valid GameTextInput library handle. * @param eventState A Java gametextinput.State object. */ -void GameTextInput_processEvent(GameTextInput *input, jobject eventState); +void GameTextInput_processEvent(GameTextInput* input, jobject eventState); /** * Free any resources owned by the GameTextInput library. @@ -137,19 +137,18 @@ void GameTextInput_processEvent(GameTextInput *input, jobject eventState); * called again. * @param input A valid GameTextInput library handle. */ -void GameTextInput_destroy(GameTextInput *input); +void GameTextInput_destroy(GameTextInput* input); /** * Flags to be passed to GameTextInput_showIme. */ enum ShowImeFlags : uint32_t { - SHOW_IME_UNDEFINED = 0, // Default value. - SHOW_IMPLICIT = - 1, // Indicates that the user has forced the input method open so it - // should not be closed until they explicitly do so. - SHOW_FORCED = 2 // Indicates that this is an implicit request to show the - // input window, not as the result of a direct request by - // the user. The window may not be shown in this case. + SHOW_IME_UNDEFINED = 0, // Default value. + SHOW_IMPLICIT = 1, // Indicates that the user has forced the input method open so it + // should not be closed until they explicitly do so. + SHOW_FORCED = 2 // Indicates that this is an implicit request to show the + // input window, not as the result of a direct request by + // the user. The window may not be shown in this case. }; /** @@ -158,19 +157,17 @@ enum ShowImeFlags : uint32_t { * @param flags Defined in ShowImeFlags above. For more information see: * https://developer.android.com/reference/android/view/inputmethod/InputMethodManager */ -void GameTextInput_showIme(GameTextInput *input, uint32_t flags); +void GameTextInput_showIme(GameTextInput* input, uint32_t flags); /** * Flags to be passed to GameTextInput_hideIme. */ enum HideImeFlags : uint32_t { - HIDE_IME_UNDEFINED = 0, // Default value. - HIDE_IMPLICIT_ONLY = - 1, // Indicates that the soft input window should only be hidden if it - // was not explicitly shown by the user. - HIDE_NOT_ALWAYS = - 2, // Indicates that the soft input window should normally be hidden, - // unless it was originally shown with SHOW_FORCED. + HIDE_IME_UNDEFINED = 0, // Default value. + HIDE_IMPLICIT_ONLY = 1, // Indicates that the soft input window should only be hidden if it + // was not explicitly shown by the user. + HIDE_NOT_ALWAYS = 2, // Indicates that the soft input window should normally be hidden, + // unless it was originally shown with SHOW_FORCED. }; /** @@ -179,13 +176,13 @@ enum HideImeFlags : uint32_t { * @param flags Defined in HideImeFlags above. For more information see: * https://developer.android.com/reference/android/view/inputmethod/InputMethodManager */ -void GameTextInput_hideIme(GameTextInput *input, uint32_t flags); +void GameTextInput_hideIme(GameTextInput* input, uint32_t flags); /** * Restarts the input method. Calls InputMethodManager.restartInput(). * @param input A valid GameTextInput library handle. */ -void GameTextInput_restartInput(GameTextInput *input); +void GameTextInput_restartInput(GameTextInput* input); /** * Call a callback with the current GameTextInput state, which may have been @@ -197,9 +194,8 @@ void GameTextInput_restartInput(GameTextInput *input); * @param callback A function that will be called with valid state. * @param context Context used by the callback. */ -void GameTextInput_getState(GameTextInput *input, - GameTextInputGetStateCallback callback, - void *context); +void GameTextInput_getState(GameTextInput* input, GameTextInputGetStateCallback callback, + void* context); /** * Set the current GameTextInput state. This state is reflected to any active @@ -208,8 +204,7 @@ void GameTextInput_getState(GameTextInput *input, * @param state The state to set. Ownership is maintained by the caller and must * remain valid for the duration of the call. */ -void GameTextInput_setState(GameTextInput *input, - const GameTextInputState *state); +void GameTextInput_setState(GameTextInput* input, const GameTextInputState* state); /** * Type of the callback needed by GameTextInput_setEventCallback that will be @@ -218,8 +213,7 @@ void GameTextInput_setState(GameTextInput *input, * @param current_state Current IME state, owned by the library and valid during * the callback. */ -typedef void (*GameTextInputEventCallback)( - void *context, const GameTextInputState *current_state); +typedef void (*GameTextInputEventCallback)(void* context, const GameTextInputState* current_state); /** * Optionally set a callback to be called whenever the IME state changes. @@ -232,9 +226,8 @@ typedef void (*GameTextInputEventCallback)( * the callback other than copying the state variable. Using any synchronization * primitives inside this callback may cause a deadlock. */ -void GameTextInput_setEventCallback(GameTextInput *input, - GameTextInputEventCallback callback, - void *context); +void GameTextInput_setEventCallback(GameTextInput* input, GameTextInputEventCallback callback, + void* context); /** * Type of the callback needed by GameTextInput_setImeInsetsCallback that will @@ -244,8 +237,7 @@ void GameTextInput_setEventCallback(GameTextInput *input, * @param current_insets Current IME insets, owned by the library and valid * during the callback. */ -typedef void (*GameTextInputImeInsetsCallback)(void *context, - const ARect *current_insets); +typedef void (*GameTextInputImeInsetsCallback)(void* context, const ARect* current_insets); /** * Optionally set a callback to be called whenever the IME insets change. @@ -255,16 +247,15 @@ typedef void (*GameTextInputImeInsetsCallback)(void *context, * @param callback Called by the library when the IME insets change. * @param context Context passed as first argument to the callback. */ -void GameTextInput_setImeInsetsCallback(GameTextInput *input, - GameTextInputImeInsetsCallback callback, - void *context); +void GameTextInput_setImeInsetsCallback(GameTextInput* input, + GameTextInputImeInsetsCallback callback, void* context); /** * Get the current window insets for the IME. * @param input A valid GameTextInput library handle. * @param insets Filled with the current insets by this function. */ -void GameTextInput_getImeInsets(const GameTextInput *input, ARect *insets); +void GameTextInput_getImeInsets(const GameTextInput* input, ARect* insets); /** * Unless using GameActivity, it is required to call this function from your @@ -274,7 +265,7 @@ void GameTextInput_getImeInsets(const GameTextInput *input, ARect *insets); * @param input A valid GameTextInput library handle. * @param eventState A Java gametextinput.State object. */ -void GameTextInput_processImeInsets(GameTextInput *input, const ARect *insets); +void GameTextInput_processImeInsets(GameTextInput* input, const ARect* insets); /** * Convert a GameTextInputState struct to a Java gametextinput.State object. @@ -284,8 +275,7 @@ void GameTextInput_processImeInsets(GameTextInput *input, const ARect *insets); * @return A Java object of class gametextinput.State. The caller is required to * delete this local reference. */ -jobject GameTextInputState_toJava(const GameTextInput *input, - const GameTextInputState *state); +jobject GameTextInputState_toJava(const GameTextInput* input, const GameTextInputState* state); /** * Convert from a Java gametextinput.State object into a C GameTextInputState @@ -296,9 +286,8 @@ jobject GameTextInputState_toJava(const GameTextInput *input, * of the call. * @param context Context passed to the callback. */ -void GameTextInputState_fromJava(const GameTextInput *input, jobject state, - GameTextInputGetStateCallback callback, - void *context); +void GameTextInputState_fromJava(const GameTextInput* input, jobject state, + GameTextInputGetStateCallback callback, void* context); /** * Definitions for inputType argument of GameActivity_setImeEditorInfo() @@ -350,354 +339,354 @@ void GameTextInputState_fromJava(const GameTextInput *input, jobject state, */ enum GameTextInputType : uint32_t { - /** - * Mask of bits that determine the overall class - * of text being given. Currently supported classes are: - * {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER}, - * {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}. - *

IME authors: If the class is not one you - * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation - * or flags.

- */ - TYPE_MASK_CLASS = 0x0000000f, - - /** - * Mask of bits that determine the variation of - * the base content class. - */ - TYPE_MASK_VARIATION = 0x00000ff0, - - /** - * Mask of bits that provide addition bit flags - * of options. - */ - TYPE_MASK_FLAGS = 0x00fff000, - - /** - * Special content type for when no explicit type has been specified. - * This should be interpreted to mean that the target input connection - * is not rich, it can not process and show things like candidate text nor - * retrieve the current text, so the input method will need to run in a - * limited "generate key events" mode, if it supports it. Note that some - * input methods may not support it, for example a voice-based input - * method will likely not be able to generate key events even if this - * flag is set. - */ - TYPE_NULL = 0x00000000, - - // ---------------------------------------------------------------------- - - /** - * Class for normal text. This class supports the following flags (only - * one of which should be set): - * {@link #TYPE_TEXT_FLAG_CAP_CHARACTERS}, - * {@link #TYPE_TEXT_FLAG_CAP_WORDS}, and. - * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. It also supports the - * following variations: - * {@link #TYPE_TEXT_VARIATION_NORMAL}, and - * {@link #TYPE_TEXT_VARIATION_URI}. If you do not recognize the - * variation, normal should be assumed. - */ - TYPE_CLASS_TEXT = 0x00000001, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides - * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and - * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. Of course, - * this only affects languages where there are upper-case and lower-case - * letters. - */ - TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of - * every word. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This - * value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_WORDS}. Of course, - * this only affects languages where there are upper-case and lower-case - * letters. - */ - TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of - * each sentence. This value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. For example - * in English it means to capitalize after a period and a space (note that - * other languages may have different characters for period, or not use - * spaces, or use different grammatical rules). Of course, this only affects - * languages where there are upper-case and lower-case letters. - */ - TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form - * text that should have auto-correction applied to it. Without this flag, - * the IME will not try to correct typos. You should always set this flag - * unless you really expect users to type non-words in this field, for - * example to choose a name for a character in a game. - * Contrast this with {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE} and - * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}: - * {@code TYPE_TEXT_FLAG_AUTO_CORRECT} means that the IME will try to - * auto-correct typos as the user is typing, but does not define whether - * the IME offers an interface to show suggestions. - */ - TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the text editor (which means - * the application) is performing auto-completion of the text being entered - * based on its own semantics, which it will present to the user as they type. - * This generally means that the input method should not be showing - * candidates itself, but can expect the editor to supply its own - * completions/candidates from - * {@link android.view.inputmethod.InputMethodSession#displayCompletions - * InputMethodSession.displayCompletions()} as a result of the editor calling - * {@link android.view.inputmethod.InputMethodManager#displayCompletions - * InputMethodManager.displayCompletions()}. - * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and - * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}: - * {@code TYPE_TEXT_FLAG_AUTO_COMPLETE} means the editor should show an - * interface for displaying suggestions, but instead of supplying its own - * it will rely on the Editor to pass completions/corrections. - */ - TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be - * entered into the field. If this flag is not set, the text field - * will be constrained to a single line. The IME may also choose not to - * display an enter key when this flag is not set, as there should be no - * need to create new lines. - */ - TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the regular text view associated - * with this should not be multi-line, but when a fullscreen input method - * is providing text it should use multiple lines if it can. - */ - TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: the input method does not need to - * display any dictionary-based candidates. This is useful for text views that - * do not contain words from the language and do not benefit from any - * dictionary-based completions or corrections. It overrides the - * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set. - * Please avoid using this unless you are certain this is what you want. - * Many input methods need suggestions to work well, for example the ones - * based on gesture typing. Consider clearing - * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} instead if you just do not - * want the IME to correct typos. - * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and - * {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE}: - * {@code TYPE_TEXT_FLAG_NO_SUGGESTIONS} means the IME does not need to - * show an interface to display suggestions. Most IMEs will also take this to - * mean they do not need to try to auto-correct what the user is typing. - */ - TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000, - - /** - * Flag for {@link #TYPE_CLASS_TEXT}: Let the IME know the text conversion - * suggestions are required by the application. Text conversion suggestion is - * for the transliteration languages which has pronunciation characters and - * target characters. When the user is typing the pronunciation charactes, the - * IME could provide the possible target characters to the user. When this - * flag is set, the IME should insert the text conversion suggestions through - * {@link Builder#setTextConversionSuggestions(List)} and - * the {@link TextAttribute} with initialized with the text conversion - * suggestions is provided by the IME to the application. To receive the - * additional information, the application needs to implement {@link - * InputConnection#setComposingText(CharSequence, int, TextAttribute)}, - * {@link InputConnection#setComposingRegion(int, int, TextAttribute)}, and - * {@link InputConnection#commitText(CharSequence, int, TextAttribute)}. - */ - TYPE_TEXT_FLAG_ENABLE_TEXT_CONVERSION_SUGGESTIONS = 0x00100000, - - // ---------------------------------------------------------------------- - - /** - * Default variation of {@link #TYPE_CLASS_TEXT}: plain old normal text. - */ - TYPE_TEXT_VARIATION_NORMAL = 0x00000000, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a URI. - */ - TYPE_TEXT_VARIATION_URI = 0x00000010, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering an e-mail address. - */ - TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering the subject line of - * an e-mail. - */ - TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a short, possibly informal - * message such as an instant message or a text message. - */ - TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x00000040, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of a long, - * possibly formal message such as the body of an e-mail. - */ - TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x00000050, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person. - */ - TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000060, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing address. - */ - TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000070, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a password. - */ - TYPE_TEXT_VARIATION_PASSWORD = 0x00000080, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering a password, which should - * be visible to the user. - */ - TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x00000090, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of a web form. - */ - TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x000000a0, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering text to filter contents - * of a list etc. - */ - TYPE_TEXT_VARIATION_FILTER = 0x000000b0, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic - * pronunciation, such as a phonetic name field in contacts. This is mostly - * useful for languages where one spelling may have several phonetic - * readings, like Japanese. - */ - TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering e-mail address inside - * of a web form. This was added in - * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target - * this API version or later to see this input type; if it doesn't, a request - * for this type will be seen as {@link #TYPE_TEXT_VARIATION_EMAIL_ADDRESS} - * when passed through {@link - * android.view.inputmethod.EditorInfo#makeCompatible(int) - * EditorInfo.makeCompatible(int)}. - */ - TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x000000d0, - - /** - * Variation of {@link #TYPE_CLASS_TEXT}: entering password inside - * of a web form. This was added in - * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target - * this API version or later to see this input type; if it doesn't, a request - * for this type will be seen as {@link #TYPE_TEXT_VARIATION_PASSWORD} - * when passed through {@link - * android.view.inputmethod.EditorInfo#makeCompatible(int) - * EditorInfo.makeCompatible(int)}. - */ - TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x000000e0, - - // ---------------------------------------------------------------------- - - /** - * Class for numeric text. This class supports the following flags: - * {@link #TYPE_NUMBER_FLAG_SIGNED} and - * {@link #TYPE_NUMBER_FLAG_DECIMAL}. It also supports the following - * variations: {@link #TYPE_NUMBER_VARIATION_NORMAL} and - * {@link #TYPE_NUMBER_VARIATION_PASSWORD}. - *

IME authors: If you do not recognize - * the variation, normal should be assumed.

- */ - TYPE_CLASS_NUMBER = 0x00000002, - - /** - * Flag of {@link #TYPE_CLASS_NUMBER}: the number is signed, allowing - * a positive or negative sign at the start. - */ - TYPE_NUMBER_FLAG_SIGNED = 0x00001000, - - /** - * Flag of {@link #TYPE_CLASS_NUMBER}: the number is decimal, allowing - * a decimal point to provide fractional values. - */ - TYPE_NUMBER_FLAG_DECIMAL = 0x00002000, - - // ---------------------------------------------------------------------- - - /** - * Default variation of {@link #TYPE_CLASS_NUMBER}: plain normal - * numeric text. This was added in - * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target - * this API version or later to see this input type; if it doesn't, a request - * for this type will be dropped when passed through - * {@link android.view.inputmethod.EditorInfo#makeCompatible(int) - * EditorInfo.makeCompatible(int)}. - */ - TYPE_NUMBER_VARIATION_NORMAL = 0x00000000, - - /** - * Variation of {@link #TYPE_CLASS_NUMBER}: entering a numeric password. - * This was added in {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An - * IME must target this API version or later to see this input type; if it - * doesn't, a request for this type will be dropped when passed - * through {@link android.view.inputmethod.EditorInfo#makeCompatible(int) - * EditorInfo.makeCompatible(int)}. - */ - TYPE_NUMBER_VARIATION_PASSWORD = 0x00000010, - - // ---------------------------------------------------------------------- - /** - * Class for a phone number. This class currently supports no variations - * or flags. - */ - TYPE_CLASS_PHONE = 0x00000003, - - // ---------------------------------------------------------------------- - - /** - * Class for dates and times. It supports the - * following variations: - * {@link #TYPE_DATETIME_VARIATION_NORMAL} - * {@link #TYPE_DATETIME_VARIATION_DATE}, and - * {@link #TYPE_DATETIME_VARIATION_TIME}. - */ - TYPE_CLASS_DATETIME = 0x00000004, - - /** - * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering - * both a date and time. - */ - TYPE_DATETIME_VARIATION_NORMAL = 0x00000000, - - /** - * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering - * only a date. - */ - TYPE_DATETIME_VARIATION_DATE = 0x00000010, - - /** - * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering - * only a time. - */ - TYPE_DATETIME_VARIATION_TIME = 0x00000020, + /** + * Mask of bits that determine the overall class + * of text being given. Currently supported classes are: + * {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER}, + * {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}. + *

IME authors: If the class is not one you + * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation + * or flags.

+ */ + TYPE_MASK_CLASS = 0x0000000f, + + /** + * Mask of bits that determine the variation of + * the base content class. + */ + TYPE_MASK_VARIATION = 0x00000ff0, + + /** + * Mask of bits that provide addition bit flags + * of options. + */ + TYPE_MASK_FLAGS = 0x00fff000, + + /** + * Special content type for when no explicit type has been specified. + * This should be interpreted to mean that the target input connection + * is not rich, it can not process and show things like candidate text nor + * retrieve the current text, so the input method will need to run in a + * limited "generate key events" mode, if it supports it. Note that some + * input methods may not support it, for example a voice-based input + * method will likely not be able to generate key events even if this + * flag is set. + */ + TYPE_NULL = 0x00000000, + + // ---------------------------------------------------------------------- + + /** + * Class for normal text. This class supports the following flags (only + * one of which should be set): + * {@link #TYPE_TEXT_FLAG_CAP_CHARACTERS}, + * {@link #TYPE_TEXT_FLAG_CAP_WORDS}, and. + * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. It also supports the + * following variations: + * {@link #TYPE_TEXT_VARIATION_NORMAL}, and + * {@link #TYPE_TEXT_VARIATION_URI}. If you do not recognize the + * variation, normal should be assumed. + */ + TYPE_CLASS_TEXT = 0x00000001, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides + * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and + * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is explicitly defined + * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. Of course, + * this only affects languages where there are upper-case and lower-case + * letters. + */ + TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of + * every word. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This + * value is explicitly defined + * to be the same as {@link TextUtils#CAP_MODE_WORDS}. Of course, + * this only affects languages where there are upper-case and lower-case + * letters. + */ + TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of + * each sentence. This value is explicitly defined + * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. For example + * in English it means to capitalize after a period and a space (note that + * other languages may have different characters for period, or not use + * spaces, or use different grammatical rules). Of course, this only affects + * languages where there are upper-case and lower-case letters. + */ + TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form + * text that should have auto-correction applied to it. Without this flag, + * the IME will not try to correct typos. You should always set this flag + * unless you really expect users to type non-words in this field, for + * example to choose a name for a character in a game. + * Contrast this with {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE} and + * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}: + * {@code TYPE_TEXT_FLAG_AUTO_CORRECT} means that the IME will try to + * auto-correct typos as the user is typing, but does not define whether + * the IME offers an interface to show suggestions. + */ + TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: the text editor (which means + * the application) is performing auto-completion of the text being entered + * based on its own semantics, which it will present to the user as they type. + * This generally means that the input method should not be showing + * candidates itself, but can expect the editor to supply its own + * completions/candidates from + * {@link android.view.inputmethod.InputMethodSession#displayCompletions + * InputMethodSession.displayCompletions()} as a result of the editor calling + * {@link android.view.inputmethod.InputMethodManager#displayCompletions + * InputMethodManager.displayCompletions()}. + * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and + * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}: + * {@code TYPE_TEXT_FLAG_AUTO_COMPLETE} means the editor should show an + * interface for displaying suggestions, but instead of supplying its own + * it will rely on the Editor to pass completions/corrections. + */ + TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be + * entered into the field. If this flag is not set, the text field + * will be constrained to a single line. The IME may also choose not to + * display an enter key when this flag is not set, as there should be no + * need to create new lines. + */ + TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: the regular text view associated + * with this should not be multi-line, but when a fullscreen input method + * is providing text it should use multiple lines if it can. + */ + TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: the input method does not need to + * display any dictionary-based candidates. This is useful for text views that + * do not contain words from the language and do not benefit from any + * dictionary-based completions or corrections. It overrides the + * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set. + * Please avoid using this unless you are certain this is what you want. + * Many input methods need suggestions to work well, for example the ones + * based on gesture typing. Consider clearing + * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} instead if you just do not + * want the IME to correct typos. + * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and + * {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE}: + * {@code TYPE_TEXT_FLAG_NO_SUGGESTIONS} means the IME does not need to + * show an interface to display suggestions. Most IMEs will also take this to + * mean they do not need to try to auto-correct what the user is typing. + */ + TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000, + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: Let the IME know the text conversion + * suggestions are required by the application. Text conversion suggestion is + * for the transliteration languages which has pronunciation characters and + * target characters. When the user is typing the pronunciation charactes, the + * IME could provide the possible target characters to the user. When this + * flag is set, the IME should insert the text conversion suggestions through + * {@link Builder#setTextConversionSuggestions(List)} and + * the {@link TextAttribute} with initialized with the text conversion + * suggestions is provided by the IME to the application. To receive the + * additional information, the application needs to implement {@link + * InputConnection#setComposingText(CharSequence, int, TextAttribute)}, + * {@link InputConnection#setComposingRegion(int, int, TextAttribute)}, and + * {@link InputConnection#commitText(CharSequence, int, TextAttribute)}. + */ + TYPE_TEXT_FLAG_ENABLE_TEXT_CONVERSION_SUGGESTIONS = 0x00100000, + + // ---------------------------------------------------------------------- + + /** + * Default variation of {@link #TYPE_CLASS_TEXT}: plain old normal text. + */ + TYPE_TEXT_VARIATION_NORMAL = 0x00000000, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a URI. + */ + TYPE_TEXT_VARIATION_URI = 0x00000010, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering an e-mail address. + */ + TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering the subject line of + * an e-mail. + */ + TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a short, possibly informal + * message such as an instant message or a text message. + */ + TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x00000040, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of a long, + * possibly formal message such as the body of an e-mail. + */ + TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x00000050, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person. + */ + TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000060, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing address. + */ + TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000070, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a password. + */ + TYPE_TEXT_VARIATION_PASSWORD = 0x00000080, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a password, which should + * be visible to the user. + */ + TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x00000090, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of a web form. + */ + TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x000000a0, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering text to filter contents + * of a list etc. + */ + TYPE_TEXT_VARIATION_FILTER = 0x000000b0, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic + * pronunciation, such as a phonetic name field in contacts. This is mostly + * useful for languages where one spelling may have several phonetic + * readings, like Japanese. + */ + TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering e-mail address inside + * of a web form. This was added in + * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target + * this API version or later to see this input type; if it doesn't, a request + * for this type will be seen as {@link #TYPE_TEXT_VARIATION_EMAIL_ADDRESS} + * when passed through {@link + * android.view.inputmethod.EditorInfo#makeCompatible(int) + * EditorInfo.makeCompatible(int)}. + */ + TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x000000d0, + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering password inside + * of a web form. This was added in + * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target + * this API version or later to see this input type; if it doesn't, a request + * for this type will be seen as {@link #TYPE_TEXT_VARIATION_PASSWORD} + * when passed through {@link + * android.view.inputmethod.EditorInfo#makeCompatible(int) + * EditorInfo.makeCompatible(int)}. + */ + TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x000000e0, + + // ---------------------------------------------------------------------- + + /** + * Class for numeric text. This class supports the following flags: + * {@link #TYPE_NUMBER_FLAG_SIGNED} and + * {@link #TYPE_NUMBER_FLAG_DECIMAL}. It also supports the following + * variations: {@link #TYPE_NUMBER_VARIATION_NORMAL} and + * {@link #TYPE_NUMBER_VARIATION_PASSWORD}. + *

IME authors: If you do not recognize + * the variation, normal should be assumed.

+ */ + TYPE_CLASS_NUMBER = 0x00000002, + + /** + * Flag of {@link #TYPE_CLASS_NUMBER}: the number is signed, allowing + * a positive or negative sign at the start. + */ + TYPE_NUMBER_FLAG_SIGNED = 0x00001000, + + /** + * Flag of {@link #TYPE_CLASS_NUMBER}: the number is decimal, allowing + * a decimal point to provide fractional values. + */ + TYPE_NUMBER_FLAG_DECIMAL = 0x00002000, + + // ---------------------------------------------------------------------- + + /** + * Default variation of {@link #TYPE_CLASS_NUMBER}: plain normal + * numeric text. This was added in + * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target + * this API version or later to see this input type; if it doesn't, a request + * for this type will be dropped when passed through + * {@link android.view.inputmethod.EditorInfo#makeCompatible(int) + * EditorInfo.makeCompatible(int)}. + */ + TYPE_NUMBER_VARIATION_NORMAL = 0x00000000, + + /** + * Variation of {@link #TYPE_CLASS_NUMBER}: entering a numeric password. + * This was added in {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An + * IME must target this API version or later to see this input type; if it + * doesn't, a request for this type will be dropped when passed + * through {@link android.view.inputmethod.EditorInfo#makeCompatible(int) + * EditorInfo.makeCompatible(int)}. + */ + TYPE_NUMBER_VARIATION_PASSWORD = 0x00000010, + + // ---------------------------------------------------------------------- + /** + * Class for a phone number. This class currently supports no variations + * or flags. + */ + TYPE_CLASS_PHONE = 0x00000003, + + // ---------------------------------------------------------------------- + + /** + * Class for dates and times. It supports the + * following variations: + * {@link #TYPE_DATETIME_VARIATION_NORMAL} + * {@link #TYPE_DATETIME_VARIATION_DATE}, and + * {@link #TYPE_DATETIME_VARIATION_TIME}. + */ + TYPE_CLASS_DATETIME = 0x00000004, + + /** + * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering + * both a date and time. + */ + TYPE_DATETIME_VARIATION_NORMAL = 0x00000000, + + /** + * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering + * only a date. + */ + TYPE_DATETIME_VARIATION_DATE = 0x00000010, + + /** + * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering + * only a time. + */ + TYPE_DATETIME_VARIATION_TIME = 0x00000020, }; /** @@ -727,199 +716,199 @@ enum GameTextInputType : uint32_t { */ enum GameTextInputActionType : uint32_t { - /** - * Set of bits in {@link #imeOptions} that provide alternative actions - * associated with the "enter" key. This both helps the IME provide - * better feedback about what the enter key will do, and also allows it - * to provide alternative mechanisms for providing that command. - */ - IME_MASK_ACTION = 0x000000ff, - - /** - * Bits of {@link #IME_MASK_ACTION}: no specific action has been - * associated with this editor, let the editor come up with its own if - * it can. - */ - IME_ACTION_UNSPECIFIED = 0x00000000, - - /** - * Bits of {@link #IME_MASK_ACTION}: there is no available action. - */ - IME_ACTION_NONE = 0x00000001, - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "go" - * operation to take the user to the target of the text they typed. - * Typically used, for example, when entering a URL. - */ - IME_ACTION_GO = 0x00000002, - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "search" - * operation, taking the user to the results of searching for the text - * they have typed (in whatever context is appropriate). - */ - IME_ACTION_SEARCH = 0x00000003, - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "send" - * operation, delivering the text to its target. This is typically used - * when composing a message in IM or SMS where sending is immediate. - */ - IME_ACTION_SEND = 0x00000004, - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "next" - * operation, taking the user to the next field that will accept text. - */ - IME_ACTION_NEXT = 0x00000005, - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "done" - * operation, typically meaning there is nothing more to input and the - * IME will be closed. - */ - IME_ACTION_DONE = 0x00000006, - - /** - * Bits of {@link #IME_MASK_ACTION}: like {@link #IME_ACTION_NEXT}, but - * for moving to the previous field. This will normally not be used to - * specify an action (since it precludes {@link #IME_ACTION_NEXT}), but - * can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}. - */ - IME_ACTION_PREVIOUS = 0x00000007, + /** + * Set of bits in {@link #imeOptions} that provide alternative actions + * associated with the "enter" key. This both helps the IME provide + * better feedback about what the enter key will do, and also allows it + * to provide alternative mechanisms for providing that command. + */ + IME_MASK_ACTION = 0x000000ff, + + /** + * Bits of {@link #IME_MASK_ACTION}: no specific action has been + * associated with this editor, let the editor come up with its own if + * it can. + */ + IME_ACTION_UNSPECIFIED = 0x00000000, + + /** + * Bits of {@link #IME_MASK_ACTION}: there is no available action. + */ + IME_ACTION_NONE = 0x00000001, + + /** + * Bits of {@link #IME_MASK_ACTION}: the action key performs a "go" + * operation to take the user to the target of the text they typed. + * Typically used, for example, when entering a URL. + */ + IME_ACTION_GO = 0x00000002, + + /** + * Bits of {@link #IME_MASK_ACTION}: the action key performs a "search" + * operation, taking the user to the results of searching for the text + * they have typed (in whatever context is appropriate). + */ + IME_ACTION_SEARCH = 0x00000003, + + /** + * Bits of {@link #IME_MASK_ACTION}: the action key performs a "send" + * operation, delivering the text to its target. This is typically used + * when composing a message in IM or SMS where sending is immediate. + */ + IME_ACTION_SEND = 0x00000004, + + /** + * Bits of {@link #IME_MASK_ACTION}: the action key performs a "next" + * operation, taking the user to the next field that will accept text. + */ + IME_ACTION_NEXT = 0x00000005, + + /** + * Bits of {@link #IME_MASK_ACTION}: the action key performs a "done" + * operation, typically meaning there is nothing more to input and the + * IME will be closed. + */ + IME_ACTION_DONE = 0x00000006, + + /** + * Bits of {@link #IME_MASK_ACTION}: like {@link #IME_ACTION_NEXT}, but + * for moving to the previous field. This will normally not be used to + * specify an action (since it precludes {@link #IME_ACTION_NEXT}), but + * can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}. + */ + IME_ACTION_PREVIOUS = 0x00000007, }; enum GameTextInputImeOptions : uint32_t { - /** - * Flag of {@link #imeOptions}: used to request that the IME should not update - * any personalized data such as typing history and personalized language - * model based on what the user typed on this text editing object. Typical - * use cases are:
  • When the application is in a special mode, where - * user's activities are expected to be not recorded in the application's - * history. Some web browsers and chat applications may have this kind of - * modes.
  • When storing typing history does not make much sense. - * Specifying this flag in typing games may help to avoid typing history from - * being filled up with words that the user is less likely to type in their - * daily life. Another example is that when the application already knows - * that the expected input is not a valid word (e.g. a promotion code that is - * not a valid word in any natural language).
  • - *
- * - *

Applications need to be aware that the flag is not a guarantee, and some - * IMEs may not respect it.

- */ - IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000, - - /** - * Flag of {@link #imeOptions}: used to request that the IME never go - * into fullscreen mode. - * By default, IMEs may go into full screen mode when they think - * it's appropriate, for example on small screens in landscape - * orientation where displaying a software keyboard may occlude - * such a large portion of the screen that the remaining part is - * too small to meaningfully display the application UI. - * If this flag is set, compliant IMEs will never go into full screen mode, - * and always leave some space to display the application UI. - * Applications need to be aware that the flag is not a guarantee, and - * some IMEs may ignore it. - */ - IME_FLAG_NO_FULLSCREEN = 0x2000000, - - /** - * Flag of {@link #imeOptions}: like {@link #IME_FLAG_NAVIGATE_NEXT}, but - * specifies there is something interesting that a backward navigation - * can focus on. If the user selects the IME's facility to backward - * navigate, this will show up in the application as an {@link - * #IME_ACTION_PREVIOUS} at {@link InputConnection#performEditorAction(int) - * InputConnection.performEditorAction(int)}. - */ - IME_FLAG_NAVIGATE_PREVIOUS = 0x4000000, - - /** - * Flag of {@link #imeOptions}: used to specify that there is something - * interesting that a forward navigation can focus on. This is like using - * {@link #IME_ACTION_NEXT}, except allows the IME to be multiline (with - * an enter key) as well as provide forward navigation. Note that some - * IMEs may not be able to do this, especially when running on a small - * screen where there is little space. In that case it does not need to - * present a UI for this option. Like {@link #IME_ACTION_NEXT}, if the - * user selects the IME's facility to forward navigate, this will show up - * in the application at {@link InputConnection#performEditorAction(int) - * InputConnection.performEditorAction(int)}. - */ - IME_FLAG_NAVIGATE_NEXT = 0x8000000, - - /** - * Flag of {@link #imeOptions}: used to specify that the IME does not need - * to show its extracted text UI. For input methods that may be fullscreen, - * often when in landscape mode, this allows them to be smaller and let part - * of the application be shown behind, through transparent UI parts in the - * fullscreen IME. The part of the UI visible to the user may not be - * responsive to touch because the IME will receive touch events, which may - * confuse the user; use {@link #IME_FLAG_NO_FULLSCREEN} instead for a better - * experience. Using this flag is discouraged and it may become deprecated in - * the future. Its meaning is unclear in some situations and it may not work - * appropriately on older versions of the platform. - */ - IME_FLAG_NO_EXTRACT_UI = 0x10000000, - - /** - * Flag of {@link #imeOptions}: used in conjunction with one of the actions - * masked by {@link #IME_MASK_ACTION}, this indicates that the action - * should not be available as an accessory button on the right of the - * extracted text when the input method is full-screen. Note that by setting - * this flag, there can be cases where the action is simply never available to - * the user. Setting this generally means that you think that in fullscreen - * mode, where there is little space to show the text, it's not worth taking - * some screen real estate to display the action and it should be used instead - * to show more text. - */ - IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000, - - /** - * Flag of {@link #imeOptions}: used in conjunction with one of the actions - * masked by {@link #IME_MASK_ACTION}. If this flag is not set, IMEs will - * normally replace the "enter" key with the action supplied. This flag - * indicates that the action should not be available in-line as a replacement - * for the "enter" key. Typically this is because the action has such a - * significant impact or is not recoverable enough that accidentally hitting - * it should be avoided, such as sending a message. Note that - * {@link android.widget.TextView} will automatically set this flag for you - * on multi-line text views. - */ - IME_FLAG_NO_ENTER_ACTION = 0x40000000, - - /** - * Flag of {@link #imeOptions}: used to request an IME that is capable of - * inputting ASCII characters. The intention of this flag is to ensure that - * the user can type Roman alphabet characters in a {@link - * android.widget.TextView}. It is typically used for an account ID or - * password input. A lot of the time, IMEs are already able to input ASCII - * even without being told so (such IMEs already respect this flag in a - * sense), but there are cases when this is not the default. For instance, - * users of languages using a different script like Arabic, Greek, Hebrew or - * Russian typically have a keyboard that can't input ASCII characters by - * default. Applications need to be aware that the flag is not a guarantee, - * and some IMEs may not respect it. However, it is strongly recommended for - * IME authors to respect this flag especially when their IME could end up - * with a state where only languages using non-ASCII are enabled. - */ - IME_FLAG_FORCE_ASCII = 0x80000000, - - /** - * Flag of {@link #internalImeOptions}: flag is set when app window containing - * this - * {@link EditorInfo} is using {@link Configuration#ORIENTATION_PORTRAIT} - * mode. - * @hide - */ - IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT = 0x00000001, - - /** - * Generic unspecified type for {@link #imeOptions}. - */ - IME_NULL = 0x00000000, + /** + * Flag of {@link #imeOptions}: used to request that the IME should not update + * any personalized data such as typing history and personalized language + * model based on what the user typed on this text editing object. Typical + * use cases are:
  • When the application is in a special mode, where + * user's activities are expected to be not recorded in the application's + * history. Some web browsers and chat applications may have this kind of + * modes.
  • When storing typing history does not make much sense. + * Specifying this flag in typing games may help to avoid typing history from + * being filled up with words that the user is less likely to type in their + * daily life. Another example is that when the application already knows + * that the expected input is not a valid word (e.g. a promotion code that is + * not a valid word in any natural language).
  • + *
+ * + *

Applications need to be aware that the flag is not a guarantee, and some + * IMEs may not respect it.

+ */ + IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000, + + /** + * Flag of {@link #imeOptions}: used to request that the IME never go + * into fullscreen mode. + * By default, IMEs may go into full screen mode when they think + * it's appropriate, for example on small screens in landscape + * orientation where displaying a software keyboard may occlude + * such a large portion of the screen that the remaining part is + * too small to meaningfully display the application UI. + * If this flag is set, compliant IMEs will never go into full screen mode, + * and always leave some space to display the application UI. + * Applications need to be aware that the flag is not a guarantee, and + * some IMEs may ignore it. + */ + IME_FLAG_NO_FULLSCREEN = 0x2000000, + + /** + * Flag of {@link #imeOptions}: like {@link #IME_FLAG_NAVIGATE_NEXT}, but + * specifies there is something interesting that a backward navigation + * can focus on. If the user selects the IME's facility to backward + * navigate, this will show up in the application as an {@link + * #IME_ACTION_PREVIOUS} at {@link InputConnection#performEditorAction(int) + * InputConnection.performEditorAction(int)}. + */ + IME_FLAG_NAVIGATE_PREVIOUS = 0x4000000, + + /** + * Flag of {@link #imeOptions}: used to specify that there is something + * interesting that a forward navigation can focus on. This is like using + * {@link #IME_ACTION_NEXT}, except allows the IME to be multiline (with + * an enter key) as well as provide forward navigation. Note that some + * IMEs may not be able to do this, especially when running on a small + * screen where there is little space. In that case it does not need to + * present a UI for this option. Like {@link #IME_ACTION_NEXT}, if the + * user selects the IME's facility to forward navigate, this will show up + * in the application at {@link InputConnection#performEditorAction(int) + * InputConnection.performEditorAction(int)}. + */ + IME_FLAG_NAVIGATE_NEXT = 0x8000000, + + /** + * Flag of {@link #imeOptions}: used to specify that the IME does not need + * to show its extracted text UI. For input methods that may be fullscreen, + * often when in landscape mode, this allows them to be smaller and let part + * of the application be shown behind, through transparent UI parts in the + * fullscreen IME. The part of the UI visible to the user may not be + * responsive to touch because the IME will receive touch events, which may + * confuse the user; use {@link #IME_FLAG_NO_FULLSCREEN} instead for a better + * experience. Using this flag is discouraged and it may become deprecated in + * the future. Its meaning is unclear in some situations and it may not work + * appropriately on older versions of the platform. + */ + IME_FLAG_NO_EXTRACT_UI = 0x10000000, + + /** + * Flag of {@link #imeOptions}: used in conjunction with one of the actions + * masked by {@link #IME_MASK_ACTION}, this indicates that the action + * should not be available as an accessory button on the right of the + * extracted text when the input method is full-screen. Note that by setting + * this flag, there can be cases where the action is simply never available to + * the user. Setting this generally means that you think that in fullscreen + * mode, where there is little space to show the text, it's not worth taking + * some screen real estate to display the action and it should be used instead + * to show more text. + */ + IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000, + + /** + * Flag of {@link #imeOptions}: used in conjunction with one of the actions + * masked by {@link #IME_MASK_ACTION}. If this flag is not set, IMEs will + * normally replace the "enter" key with the action supplied. This flag + * indicates that the action should not be available in-line as a replacement + * for the "enter" key. Typically this is because the action has such a + * significant impact or is not recoverable enough that accidentally hitting + * it should be avoided, such as sending a message. Note that + * {@link android.widget.TextView} will automatically set this flag for you + * on multi-line text views. + */ + IME_FLAG_NO_ENTER_ACTION = 0x40000000, + + /** + * Flag of {@link #imeOptions}: used to request an IME that is capable of + * inputting ASCII characters. The intention of this flag is to ensure that + * the user can type Roman alphabet characters in a {@link + * android.widget.TextView}. It is typically used for an account ID or + * password input. A lot of the time, IMEs are already able to input ASCII + * even without being told so (such IMEs already respect this flag in a + * sense), but there are cases when this is not the default. For instance, + * users of languages using a different script like Arabic, Greek, Hebrew or + * Russian typically have a keyboard that can't input ASCII characters by + * default. Applications need to be aware that the flag is not a guarantee, + * and some IMEs may not respect it. However, it is strongly recommended for + * IME authors to respect this flag especially when their IME could end up + * with a state where only languages using non-ASCII are enabled. + */ + IME_FLAG_FORCE_ASCII = 0x80000000, + + /** + * Flag of {@link #internalImeOptions}: flag is set when app window containing + * this + * {@link EditorInfo} is using {@link Configuration#ORIENTATION_PORTRAIT} + * mode. + * @hide + */ + IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT = 0x00000001, + + /** + * Generic unspecified type for {@link #imeOptions}. + */ + IME_NULL = 0x00000000, }; #ifdef __cplusplus diff --git a/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/src/game-text-input/gametextinput.cpp b/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/src/game-text-input/gametextinput.cpp index 70a59389..5db09800 100644 --- a/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/src/game-text-input/gametextinput.cpp +++ b/android-activity/android-games-sdk/game-text-input/prefab-src/modules/game-text-input/src/game-text-input/gametextinput.cpp @@ -31,65 +31,64 @@ static constexpr int32_t DEFAULT_MAX_STRING_SIZE = 1 << 16; // Cache of field ids in the Java GameTextInputState class struct StateClassInfo { - jfieldID text; - jfieldID selectionStart; - jfieldID selectionEnd; - jfieldID composingRegionStart; - jfieldID composingRegionEnd; + jfieldID text; + jfieldID selectionStart; + jfieldID selectionEnd; + jfieldID composingRegionStart; + jfieldID composingRegionEnd; }; // Main GameTextInput object. struct GameTextInput { - public: - GameTextInput(JNIEnv *env, uint32_t max_string_size); - ~GameTextInput(); - void setState(const GameTextInputState &state); - GameTextInputState getState() const { - std::lock_guard lock(currentStateMutex_); - return currentState_; - } - void setInputConnection(jobject inputConnection); - void processEvent(jobject textInputEvent); - void showIme(uint32_t flags); - void hideIme(uint32_t flags); - void restartInput(); - void setEventCallback(GameTextInputEventCallback callback, void *context); - jobject stateToJava(const GameTextInputState &state) const; - void stateFromJava(jobject textInputEvent, - GameTextInputGetStateCallback callback, - void *context) const; - void setImeInsetsCallback(GameTextInputImeInsetsCallback callback, - void *context); - void processImeInsets(const ARect *insets); - const ARect &getImeInsets() const { return currentInsets_; } - - private: - // Copy string and set other fields - void setStateInner(const GameTextInputState &state); - static void processCallback(void *context, const GameTextInputState *state); - JNIEnv *env_ = nullptr; - // Cached at initialization from - // com/google/androidgamesdk/gametextinput/State. - jclass stateJavaClass_ = nullptr; - // The latest text input update. - GameTextInputState currentState_ = {}; - // A mutex to protect currentState_. - mutable std::mutex currentStateMutex_; - // An instance of gametextinput.InputConnection. - jclass inputConnectionClass_ = nullptr; - jobject inputConnection_ = nullptr; - jmethodID inputConnectionSetStateMethod_; - jmethodID setSoftKeyboardActiveMethod_; - jmethodID restartInputMethod_; - void (*eventCallback_)(void *context, - const struct GameTextInputState *state) = nullptr; - void *eventCallbackContext_ = nullptr; - void (*insetsCallback_)(void *context, const struct ARect *insets) = nullptr; - ARect currentInsets_ = {}; - void *insetsCallbackContext_ = nullptr; - StateClassInfo stateClassInfo_ = {}; - // Constant-sized buffer used to store state text. - std::vector stateStringBuffer_; +public: + GameTextInput(JNIEnv* env, uint32_t max_string_size); + ~GameTextInput(); + void setState(const GameTextInputState& state); + GameTextInputState getState() const { + std::lock_guard lock(currentStateMutex_); + return currentState_; + } + void setInputConnection(jobject inputConnection); + void processEvent(jobject textInputEvent); + void showIme(uint32_t flags); + void hideIme(uint32_t flags); + void restartInput(); + void setEventCallback(GameTextInputEventCallback callback, void* context); + jobject stateToJava(const GameTextInputState& state) const; + void stateFromJava(jobject textInputEvent, GameTextInputGetStateCallback callback, + void* context) const; + void setImeInsetsCallback(GameTextInputImeInsetsCallback callback, void* context); + void processImeInsets(const ARect* insets); + const ARect& getImeInsets() const { + return currentInsets_; + } + +private: + // Copy string and set other fields + void setStateInner(const GameTextInputState& state); + static void processCallback(void* context, const GameTextInputState* state); + JNIEnv* env_ = nullptr; + // Cached at initialization from + // com/google/androidgamesdk/gametextinput/State. + jclass stateJavaClass_ = nullptr; + // The latest text input update. + GameTextInputState currentState_ = {}; + // A mutex to protect currentState_. + mutable std::mutex currentStateMutex_; + // An instance of gametextinput.InputConnection. + jclass inputConnectionClass_ = nullptr; + jobject inputConnection_ = nullptr; + jmethodID inputConnectionSetStateMethod_; + jmethodID setSoftKeyboardActiveMethod_; + jmethodID restartInputMethod_; + void (*eventCallback_)(void* context, const struct GameTextInputState* state) = nullptr; + void* eventCallbackContext_ = nullptr; + void (*insetsCallback_)(void* context, const struct ARect* insets) = nullptr; + ARect currentInsets_ = {}; + void* insetsCallbackContext_ = nullptr; + StateClassInfo stateClassInfo_ = {}; + // Constant-sized buffer used to store state text. + std::vector stateStringBuffer_; }; std::unique_ptr s_gameTextInput; @@ -101,286 +100,257 @@ extern "C" { /////////////////////////////////////////////////////////// // Convert to a Java structure. -jobject currentState_toJava(const GameTextInput *gameTextInput, - const GameTextInputState *state) { - if (state == nullptr) return NULL; - return gameTextInput->stateToJava(*state); +jobject currentState_toJava(const GameTextInput* gameTextInput, const GameTextInputState* state) { + if (state == nullptr) return NULL; + return gameTextInput->stateToJava(*state); } // Convert from Java structure. -void currentState_fromJava(const GameTextInput *gameTextInput, - jobject textInputEvent, - GameTextInputGetStateCallback callback, - void *context) { - gameTextInput->stateFromJava(textInputEvent, callback, context); +void currentState_fromJava(const GameTextInput* gameTextInput, jobject textInputEvent, + GameTextInputGetStateCallback callback, void* context) { + gameTextInput->stateFromJava(textInputEvent, callback, context); } /////////////////////////////////////////////////////////// /// GameTextInput C Functions /////////////////////////////////////////////////////////// -struct GameTextInput *GameTextInput_init(JNIEnv *env, - uint32_t max_string_size) { - if (s_gameTextInput.get() != nullptr) { - __android_log_print(ANDROID_LOG_WARN, LOG_TAG, - "Warning: called GameTextInput_init twice without " - "calling GameTextInput_destroy"); +struct GameTextInput* GameTextInput_init(JNIEnv* env, uint32_t max_string_size) { + if (s_gameTextInput.get() != nullptr) { + __android_log_print(ANDROID_LOG_WARN, LOG_TAG, + "Warning: called GameTextInput_init twice without " + "calling GameTextInput_destroy"); + return s_gameTextInput.get(); + } + // Don't use make_unique, for C++11 compatibility + s_gameTextInput = std::unique_ptr(new GameTextInput(env, max_string_size)); return s_gameTextInput.get(); - } - // Don't use make_unique, for C++11 compatibility - s_gameTextInput = - std::unique_ptr(new GameTextInput(env, max_string_size)); - return s_gameTextInput.get(); } -void GameTextInput_destroy(GameTextInput *input) { - if (input == nullptr || s_gameTextInput.get() == nullptr) return; - s_gameTextInput.reset(); +void GameTextInput_destroy(GameTextInput* input) { + if (input == nullptr || s_gameTextInput.get() == nullptr) return; + s_gameTextInput.reset(); } -void GameTextInput_setState(GameTextInput *input, - const GameTextInputState *state) { - if (state == nullptr) return; - input->setState(*state); +void GameTextInput_setState(GameTextInput* input, const GameTextInputState* state) { + if (state == nullptr) return; + input->setState(*state); } -void GameTextInput_getState(GameTextInput *input, - GameTextInputGetStateCallback callback, - void *context) { - GameTextInputState state = input->getState(); - callback(context, &state); +void GameTextInput_getState(GameTextInput* input, GameTextInputGetStateCallback callback, + void* context) { + GameTextInputState state = input->getState(); + callback(context, &state); } -void GameTextInput_setInputConnection(GameTextInput *input, - jobject inputConnection) { - input->setInputConnection(inputConnection); +void GameTextInput_setInputConnection(GameTextInput* input, jobject inputConnection) { + input->setInputConnection(inputConnection); } -void GameTextInput_processEvent(GameTextInput *input, jobject textInputEvent) { - input->processEvent(textInputEvent); +void GameTextInput_processEvent(GameTextInput* input, jobject textInputEvent) { + input->processEvent(textInputEvent); } -void GameTextInput_processImeInsets(GameTextInput *input, const ARect *insets) { - input->processImeInsets(insets); +void GameTextInput_processImeInsets(GameTextInput* input, const ARect* insets) { + input->processImeInsets(insets); } -void GameTextInput_showIme(struct GameTextInput *input, uint32_t flags) { - input->showIme(flags); +void GameTextInput_showIme(struct GameTextInput* input, uint32_t flags) { + input->showIme(flags); } -void GameTextInput_hideIme(struct GameTextInput *input, uint32_t flags) { - input->hideIme(flags); +void GameTextInput_hideIme(struct GameTextInput* input, uint32_t flags) { + input->hideIme(flags); } -void GameTextInput_restartInput(struct GameTextInput *input) { - input->restartInput(); +void GameTextInput_restartInput(struct GameTextInput* input) { + input->restartInput(); } -void GameTextInput_setEventCallback(struct GameTextInput *input, - GameTextInputEventCallback callback, - void *context) { - input->setEventCallback(callback, context); +void GameTextInput_setEventCallback(struct GameTextInput* input, + GameTextInputEventCallback callback, void* context) { + input->setEventCallback(callback, context); } -void GameTextInput_setImeInsetsCallback(struct GameTextInput *input, - GameTextInputImeInsetsCallback callback, - void *context) { - input->setImeInsetsCallback(callback, context); +void GameTextInput_setImeInsetsCallback(struct GameTextInput* input, + GameTextInputImeInsetsCallback callback, void* context) { + input->setImeInsetsCallback(callback, context); } -void GameTextInput_getImeInsets(const GameTextInput *input, ARect *insets) { - *insets = input->getImeInsets(); +void GameTextInput_getImeInsets(const GameTextInput* input, ARect* insets) { + *insets = input->getImeInsets(); } -} // extern "C" +} // extern "C" /////////////////////////////////////////////////////////// /// GameTextInput C++ class Implementation /////////////////////////////////////////////////////////// -GameTextInput::GameTextInput(JNIEnv *env, uint32_t max_string_size) - : env_(env), - stateStringBuffer_(max_string_size == 0 ? DEFAULT_MAX_STRING_SIZE - : max_string_size) { - stateJavaClass_ = (jclass)env_->NewGlobalRef( - env_->FindClass("com/google/androidgamesdk/gametextinput/State")); - inputConnectionClass_ = (jclass)env_->NewGlobalRef(env_->FindClass( - "com/google/androidgamesdk/gametextinput/InputConnection")); - inputConnectionSetStateMethod_ = - env_->GetMethodID(inputConnectionClass_, "setState", - "(Lcom/google/androidgamesdk/gametextinput/State;)V"); - setSoftKeyboardActiveMethod_ = env_->GetMethodID( - inputConnectionClass_, "setSoftKeyboardActive", "(ZI)V"); - restartInputMethod_ = - env_->GetMethodID(inputConnectionClass_, "restartInput", "()V"); - - stateClassInfo_.text = - env_->GetFieldID(stateJavaClass_, "text", "Ljava/lang/String;"); - stateClassInfo_.selectionStart = - env_->GetFieldID(stateJavaClass_, "selectionStart", "I"); - stateClassInfo_.selectionEnd = - env_->GetFieldID(stateJavaClass_, "selectionEnd", "I"); - stateClassInfo_.composingRegionStart = - env_->GetFieldID(stateJavaClass_, "composingRegionStart", "I"); - stateClassInfo_.composingRegionEnd = - env_->GetFieldID(stateJavaClass_, "composingRegionEnd", "I"); +GameTextInput::GameTextInput(JNIEnv* env, uint32_t max_string_size) + : env_(env), + stateStringBuffer_(max_string_size == 0 ? DEFAULT_MAX_STRING_SIZE : max_string_size) { + stateJavaClass_ = (jclass)env_->NewGlobalRef( + env_->FindClass("com/google/androidgamesdk/gametextinput/State")); + inputConnectionClass_ = (jclass)env_->NewGlobalRef( + env_->FindClass("com/google/androidgamesdk/gametextinput/InputConnection")); + inputConnectionSetStateMethod_ = + env_->GetMethodID(inputConnectionClass_, "setState", + "(Lcom/google/androidgamesdk/gametextinput/State;)V"); + setSoftKeyboardActiveMethod_ = + env_->GetMethodID(inputConnectionClass_, "setSoftKeyboardActive", "(ZI)V"); + restartInputMethod_ = env_->GetMethodID(inputConnectionClass_, "restartInput", "()V"); + + stateClassInfo_.text = env_->GetFieldID(stateJavaClass_, "text", "Ljava/lang/String;"); + stateClassInfo_.selectionStart = env_->GetFieldID(stateJavaClass_, "selectionStart", "I"); + stateClassInfo_.selectionEnd = env_->GetFieldID(stateJavaClass_, "selectionEnd", "I"); + stateClassInfo_.composingRegionStart = + env_->GetFieldID(stateJavaClass_, "composingRegionStart", "I"); + stateClassInfo_.composingRegionEnd = + env_->GetFieldID(stateJavaClass_, "composingRegionEnd", "I"); } GameTextInput::~GameTextInput() { - if (stateJavaClass_ != NULL) { - env_->DeleteGlobalRef(stateJavaClass_); - stateJavaClass_ = NULL; - } - if (inputConnectionClass_ != NULL) { - env_->DeleteGlobalRef(inputConnectionClass_); - inputConnectionClass_ = NULL; - } - if (inputConnection_ != NULL) { - env_->DeleteGlobalRef(inputConnection_); - inputConnection_ = NULL; - } + if (stateJavaClass_ != NULL) { + env_->DeleteGlobalRef(stateJavaClass_); + stateJavaClass_ = NULL; + } + if (inputConnectionClass_ != NULL) { + env_->DeleteGlobalRef(inputConnectionClass_); + inputConnectionClass_ = NULL; + } + if (inputConnection_ != NULL) { + env_->DeleteGlobalRef(inputConnection_); + inputConnection_ = NULL; + } } -void GameTextInput::setState(const GameTextInputState &state) { - if (inputConnection_ == nullptr) return; - jobject jstate = stateToJava(state); - env_->CallVoidMethod(inputConnection_, inputConnectionSetStateMethod_, - jstate); - env_->DeleteLocalRef(jstate); - setStateInner(state); +void GameTextInput::setState(const GameTextInputState& state) { + if (inputConnection_ == nullptr) return; + jobject jstate = stateToJava(state); + env_->CallVoidMethod(inputConnection_, inputConnectionSetStateMethod_, jstate); + env_->DeleteLocalRef(jstate); + setStateInner(state); } -void GameTextInput::setStateInner(const GameTextInputState &state) { - std::lock_guard lock(currentStateMutex_); - - // Check if we're setting using our own string (other parts may be - // different) - if (state.text_UTF8 == currentState_.text_UTF8) { - currentState_ = state; - return; - } - // Otherwise, copy across the string. - auto bytes_needed = - std::min(static_cast(state.text_length + 1), - static_cast(stateStringBuffer_.size())); - currentState_.text_UTF8 = stateStringBuffer_.data(); - std::copy(state.text_UTF8, state.text_UTF8 + bytes_needed - 1, - stateStringBuffer_.data()); - currentState_.text_length = state.text_length; - currentState_.selection = state.selection; - currentState_.composingRegion = state.composingRegion; - stateStringBuffer_[bytes_needed - 1] = 0; +void GameTextInput::setStateInner(const GameTextInputState& state) { + std::lock_guard lock(currentStateMutex_); + + // Check if we're setting using our own string (other parts may be + // different) + if (state.text_UTF8 == currentState_.text_UTF8) { + currentState_ = state; + return; + } + // Otherwise, copy across the string. + auto bytes_needed = std::min(static_cast(state.text_length + 1), + static_cast(stateStringBuffer_.size())); + currentState_.text_UTF8 = stateStringBuffer_.data(); + std::copy(state.text_UTF8, state.text_UTF8 + bytes_needed - 1, stateStringBuffer_.data()); + currentState_.text_length = state.text_length; + currentState_.selection = state.selection; + currentState_.composingRegion = state.composingRegion; + stateStringBuffer_[bytes_needed - 1] = 0; } void GameTextInput::setInputConnection(jobject inputConnection) { - if (inputConnection_ != NULL) { - env_->DeleteGlobalRef(inputConnection_); - } - inputConnection_ = env_->NewGlobalRef(inputConnection); + if (inputConnection_ != NULL) { + env_->DeleteGlobalRef(inputConnection_); + } + inputConnection_ = env_->NewGlobalRef(inputConnection); } -/*static*/ void GameTextInput::processCallback( - void *context, const GameTextInputState *state) { - auto thiz = static_cast(context); - if (state != nullptr) thiz->setStateInner(*state); +/*static*/ void GameTextInput::processCallback(void* context, const GameTextInputState* state) { + auto thiz = static_cast(context); + if (state != nullptr) thiz->setStateInner(*state); } void GameTextInput::processEvent(jobject textInputEvent) { - stateFromJava(textInputEvent, processCallback, this); - if (eventCallback_) { - std::lock_guard lock(currentStateMutex_); - eventCallback_(eventCallbackContext_, ¤tState_); - } + stateFromJava(textInputEvent, processCallback, this); + if (eventCallback_) { + std::lock_guard lock(currentStateMutex_); + eventCallback_(eventCallbackContext_, ¤tState_); + } } void GameTextInput::showIme(uint32_t flags) { - if (inputConnection_ == nullptr) return; - env_->CallVoidMethod(inputConnection_, setSoftKeyboardActiveMethod_, true, - static_cast(flags)); + if (inputConnection_ == nullptr) return; + env_->CallVoidMethod(inputConnection_, setSoftKeyboardActiveMethod_, true, + static_cast(flags)); } -void GameTextInput::setEventCallback(GameTextInputEventCallback callback, - void *context) { - eventCallback_ = callback; - eventCallbackContext_ = context; +void GameTextInput::setEventCallback(GameTextInputEventCallback callback, void* context) { + eventCallback_ = callback; + eventCallbackContext_ = context; } -void GameTextInput::setImeInsetsCallback( - GameTextInputImeInsetsCallback callback, void *context) { - insetsCallback_ = callback; - insetsCallbackContext_ = context; +void GameTextInput::setImeInsetsCallback(GameTextInputImeInsetsCallback callback, void* context) { + insetsCallback_ = callback; + insetsCallbackContext_ = context; } -void GameTextInput::processImeInsets(const ARect *insets) { - currentInsets_ = *insets; - if (insetsCallback_) { - insetsCallback_(insetsCallbackContext_, ¤tInsets_); - } +void GameTextInput::processImeInsets(const ARect* insets) { + currentInsets_ = *insets; + if (insetsCallback_) { + insetsCallback_(insetsCallbackContext_, ¤tInsets_); + } } void GameTextInput::hideIme(uint32_t flags) { - if (inputConnection_ == nullptr) return; - env_->CallVoidMethod(inputConnection_, setSoftKeyboardActiveMethod_, false, - static_cast(flags)); + if (inputConnection_ == nullptr) return; + env_->CallVoidMethod(inputConnection_, setSoftKeyboardActiveMethod_, false, + static_cast(flags)); } void GameTextInput::restartInput() { - if (inputConnection_ == nullptr) return; - env_->CallVoidMethod(inputConnection_, restartInputMethod_); + if (inputConnection_ == nullptr) return; + env_->CallVoidMethod(inputConnection_, restartInputMethod_); } -jobject GameTextInput::stateToJava(const GameTextInputState &state) const { - static jmethodID constructor = nullptr; - if (constructor == nullptr) { - constructor = env_->GetMethodID(stateJavaClass_, "", - "(Ljava/lang/String;IIII)V"); +jobject GameTextInput::stateToJava(const GameTextInputState& state) const { + static jmethodID constructor = nullptr; if (constructor == nullptr) { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, - "Can't find gametextinput.State constructor"); - return nullptr; + constructor = env_->GetMethodID(stateJavaClass_, "", "(Ljava/lang/String;IIII)V"); + if (constructor == nullptr) { + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, + "Can't find gametextinput.State constructor"); + return nullptr; + } + } + const char* text = state.text_UTF8; + if (text == nullptr) { + static char empty_string[] = ""; + text = empty_string; } - } - const char *text = state.text_UTF8; - if (text == nullptr) { - static char empty_string[] = ""; - text = empty_string; - } - // Note that this expects 'modified' UTF-8 which is not the same as UTF-8 - // https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 - jstring jtext = env_->NewStringUTF(text); - jobject jobj = - env_->NewObject(stateJavaClass_, constructor, jtext, - state.selection.start, state.selection.end, - state.composingRegion.start, state.composingRegion.end); - env_->DeleteLocalRef(jtext); - return jobj; + // Note that this expects 'modified' UTF-8 which is not the same as UTF-8 + // https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 + jstring jtext = env_->NewStringUTF(text); + jobject jobj = env_->NewObject(stateJavaClass_, constructor, jtext, state.selection.start, + state.selection.end, state.composingRegion.start, + state.composingRegion.end); + env_->DeleteLocalRef(jtext); + return jobj; } -void GameTextInput::stateFromJava(jobject textInputEvent, - GameTextInputGetStateCallback callback, - void *context) const { - jstring text = - (jstring)env_->GetObjectField(textInputEvent, stateClassInfo_.text); - // Note this is 'modified' UTF-8, not true UTF-8. It has no NULLs in it, - // except at the end. It's actually not specified whether the value returned - // by GetStringUTFChars includes a null at the end, but it *seems to* on - // Android. - const char *text_chars = env_->GetStringUTFChars(text, NULL); - int text_len = env_->GetStringUTFLength( - text); // Length in bytes, *not* including the null. - int selectionStart = - env_->GetIntField(textInputEvent, stateClassInfo_.selectionStart); - int selectionEnd = - env_->GetIntField(textInputEvent, stateClassInfo_.selectionEnd); - int composingRegionStart = - env_->GetIntField(textInputEvent, stateClassInfo_.composingRegionStart); - int composingRegionEnd = - env_->GetIntField(textInputEvent, stateClassInfo_.composingRegionEnd); - GameTextInputState state{text_chars, - text_len, - {selectionStart, selectionEnd}, - {composingRegionStart, composingRegionEnd}}; - callback(context, &state); - env_->ReleaseStringUTFChars(text, text_chars); - env_->DeleteLocalRef(text); +void GameTextInput::stateFromJava(jobject textInputEvent, GameTextInputGetStateCallback callback, + void* context) const { + jstring text = (jstring)env_->GetObjectField(textInputEvent, stateClassInfo_.text); + // Note this is 'modified' UTF-8, not true UTF-8. It has no NULLs in it, + // except at the end. It's actually not specified whether the value returned + // by GetStringUTFChars includes a null at the end, but it *seems to* on + // Android. + const char* text_chars = env_->GetStringUTFChars(text, NULL); + int text_len = env_->GetStringUTFLength(text); // Length in bytes, *not* including the null. + int selectionStart = env_->GetIntField(textInputEvent, stateClassInfo_.selectionStart); + int selectionEnd = env_->GetIntField(textInputEvent, stateClassInfo_.selectionEnd); + int composingRegionStart = + env_->GetIntField(textInputEvent, stateClassInfo_.composingRegionStart); + int composingRegionEnd = env_->GetIntField(textInputEvent, stateClassInfo_.composingRegionEnd); + GameTextInputState state{text_chars, + text_len, + {selectionStart, selectionEnd}, + {composingRegionStart, composingRegionEnd}}; + callback(context, &state); + env_->ReleaseStringUTFChars(text, text_chars); + env_->DeleteLocalRef(text); } diff --git a/android-activity/android-games-sdk/include/common/gamesdk_common.h b/android-activity/android-games-sdk/include/common/gamesdk_common.h index 25ce8139..806351f5 100644 --- a/android-activity/android-games-sdk/include/common/gamesdk_common.h +++ b/android-activity/android-games-sdk/include/common/gamesdk_common.h @@ -31,7 +31,7 @@ // There are separate versions for each GameSDK component that use this format: #define ANDROID_GAMESDK_PACKED_VERSION(MAJOR, MINOR, BUGFIX) \ - ((MAJOR << 16) | (MINOR << 8) | (BUGFIX)) + ((MAJOR << 16) | (MINOR << 8) | (BUGFIX)) // Accessors #define ANDROID_GAMESDK_MAJOR_VERSION(PACKED) ((PACKED) >> 16) #define ANDROID_GAMESDK_MINOR_VERSION(PACKED) (((PACKED) >> 8) & 0xff) @@ -39,4 +39,4 @@ #define AGDK_STRINGIFY(NUMBER) #NUMBER #define AGDK_STRING_VERSION(MAJOR, MINOR, BUGFIX) \ - AGDK_STRINGIFY(MAJOR) "." AGDK_STRINGIFY(MINOR) "." AGDK_STRINGIFY(BUGFIX) + AGDK_STRINGIFY(MAJOR) "." AGDK_STRINGIFY(MINOR) "." AGDK_STRINGIFY(BUGFIX) diff --git a/android-activity/android-games-sdk/src/common/system_utils.cpp b/android-activity/android-games-sdk/src/common/system_utils.cpp index efc5b743..2bd09ea8 100644 --- a/android-activity/android-games-sdk/src/common/system_utils.cpp +++ b/android-activity/android-games-sdk/src/common/system_utils.cpp @@ -23,15 +23,13 @@ namespace gamesdk { #if __ANDROID_API__ >= 26 -std::string getSystemPropViaCallback(const char* key, - const char* default_value = "") { +std::string getSystemPropViaCallback(const char* key, const char* default_value = "") { const prop_info* prop = __system_property_find(key); if (prop == nullptr) { return default_value; } std::string return_value; - auto thunk = [](void* cookie, const char* /*name*/, const char* value, - uint32_t /*serial*/) { + auto thunk = [](void* cookie, const char* /*name*/, const char* value, uint32_t /*serial*/) { if (value != nullptr) { std::string* r = static_cast(cookie); *r = value; @@ -41,9 +39,8 @@ std::string getSystemPropViaCallback(const char* key, return return_value; } #else -std::string getSystemPropViaGet(const char* key, - const char* default_value = "") { - char buffer[PROP_VALUE_MAX + 1] = ""; // +1 for terminator +std::string getSystemPropViaGet(const char* key, const char* default_value = "") { + char buffer[PROP_VALUE_MAX + 1] = ""; // +1 for terminator int bufferLen = __system_property_get(key, buffer); if (bufferLen > 0) return buffer; @@ -69,4 +66,4 @@ bool GetSystemPropAsBool(const char* key, bool default_value) { return GetSystemPropAsInt(key, default_value) != 0; } -} // namespace gamesdk \ No newline at end of file +} // namespace gamesdk \ No newline at end of file diff --git a/android-activity/android-games-sdk/src/common/system_utils.h b/android-activity/android-games-sdk/src/common/system_utils.h index 488374bc..ed3286fc 100644 --- a/android-activity/android-games-sdk/src/common/system_utils.h +++ b/android-activity/android-games-sdk/src/common/system_utils.h @@ -29,4 +29,4 @@ int GetSystemPropAsInt(const char* key, int default_value = 0); // Get the value of the given system property as a bool bool GetSystemPropAsBool(const char* key, bool default_value = false); -} // namespace gamesdk \ No newline at end of file +} // namespace gamesdk \ No newline at end of file diff --git a/android-activity/src/game_activity/ffi_aarch64.rs b/android-activity/src/game_activity/ffi_aarch64.rs index 323af260..50c2e939 100644 --- a/android-activity/src/game_activity/ffi_aarch64.rs +++ b/android-activity/src/game_activity/ffi_aarch64.rs @@ -293,10 +293,10 @@ pub const SCNxPTR: &[u8; 3] = b"lx\0"; pub const GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT: u32 = 48; pub const GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT: u32 = 8; pub const GAMETEXTINPUT_MAJOR_VERSION: u32 = 4; -pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 0; +pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 3; pub const GAMETEXTINPUT_BUGFIX_VERSION: u32 = 0; pub const GAMEACTIVITY_MAJOR_VERSION: u32 = 4; -pub const GAMEACTIVITY_MINOR_VERSION: u32 = 0; +pub const GAMEACTIVITY_MINOR_VERSION: u32 = 4; pub const GAMEACTIVITY_BUGFIX_VERSION: u32 = 0; pub const POLLIN: u32 = 1; pub const POLLPRI: u32 = 2; @@ -2364,7 +2364,7 @@ pub struct GameTextInput { _unused: [u8; 0], } unsafe extern "C" { - #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] + #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread. All other calls to the resulting GameTextInput\n object must be done on the same calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] pub fn GameTextInput_init(env: *mut JNIEnv, max_string_size: u32) -> *mut GameTextInput; } unsafe extern "C" { @@ -4829,7 +4829,7 @@ pub const NativeAppGlueAppCmd_APP_CMD_WINDOW_INSETS_CHANGED: NativeAppGlueAppCmd #[doc = " Commands passed from the application's main Java thread to the game's thread.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] pub type NativeAppGlueAppCmd = i8; unsafe extern "C" { - #[doc = " Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next\n app command message."] + #[doc = " Call when ALooper_pollOnce() returns LOOPER_ID_MAIN, reading the next\n app command message."] pub fn android_app_read_cmd(android_app: *mut android_app) -> i8; } unsafe extern "C" { @@ -4873,8 +4873,8 @@ unsafe extern "C" { ); } unsafe extern "C" { - #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] - pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8); + #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events.\n\n The function returns true if the write operation was successful."] + pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8) -> bool; } unsafe extern "C" { #[doc = " Determines if a looper wake up was due to new input becoming available"] diff --git a/android-activity/src/game_activity/ffi_arm.rs b/android-activity/src/game_activity/ffi_arm.rs index 79126740..1ee62e57 100644 --- a/android-activity/src/game_activity/ffi_arm.rs +++ b/android-activity/src/game_activity/ffi_arm.rs @@ -378,10 +378,10 @@ pub const SCNxMAX: &[u8; 3] = b"jx\0"; pub const GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT: u32 = 48; pub const GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT: u32 = 8; pub const GAMETEXTINPUT_MAJOR_VERSION: u32 = 4; -pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 0; +pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 3; pub const GAMETEXTINPUT_BUGFIX_VERSION: u32 = 0; pub const GAMEACTIVITY_MAJOR_VERSION: u32 = 4; -pub const GAMEACTIVITY_MINOR_VERSION: u32 = 0; +pub const GAMEACTIVITY_MINOR_VERSION: u32 = 4; pub const GAMEACTIVITY_BUGFIX_VERSION: u32 = 0; pub const POLLIN: u32 = 1; pub const POLLPRI: u32 = 2; @@ -2420,7 +2420,7 @@ pub struct GameTextInput { _unused: [u8; 0], } unsafe extern "C" { - #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] + #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread. All other calls to the resulting GameTextInput\n object must be done on the same calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] pub fn GameTextInput_init(env: *mut JNIEnv, max_string_size: u32) -> *mut GameTextInput; } unsafe extern "C" { @@ -5241,7 +5241,7 @@ pub const NativeAppGlueAppCmd_APP_CMD_WINDOW_INSETS_CHANGED: NativeAppGlueAppCmd #[doc = " Commands passed from the application's main Java thread to the game's thread.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] pub type NativeAppGlueAppCmd = i8; unsafe extern "C" { - #[doc = " Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next\n app command message."] + #[doc = " Call when ALooper_pollOnce() returns LOOPER_ID_MAIN, reading the next\n app command message."] pub fn android_app_read_cmd(android_app: *mut android_app) -> i8; } unsafe extern "C" { @@ -5285,8 +5285,8 @@ unsafe extern "C" { ); } unsafe extern "C" { - #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] - pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8); + #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events.\n\n The function returns true if the write operation was successful."] + pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8) -> bool; } unsafe extern "C" { #[doc = " Determines if a looper wake up was due to new input becoming available"] diff --git a/android-activity/src/game_activity/ffi_i686.rs b/android-activity/src/game_activity/ffi_i686.rs index 52ac4e4e..85b6d835 100644 --- a/android-activity/src/game_activity/ffi_i686.rs +++ b/android-activity/src/game_activity/ffi_i686.rs @@ -241,10 +241,10 @@ pub const SCNxMAX: &[u8; 3] = b"jx\0"; pub const GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT: u32 = 48; pub const GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT: u32 = 8; pub const GAMETEXTINPUT_MAJOR_VERSION: u32 = 4; -pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 0; +pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 3; pub const GAMETEXTINPUT_BUGFIX_VERSION: u32 = 0; pub const GAMEACTIVITY_MAJOR_VERSION: u32 = 4; -pub const GAMEACTIVITY_MINOR_VERSION: u32 = 0; +pub const GAMEACTIVITY_MINOR_VERSION: u32 = 4; pub const GAMEACTIVITY_BUGFIX_VERSION: u32 = 0; pub const POLLIN: u32 = 1; pub const POLLPRI: u32 = 2; @@ -2284,7 +2284,7 @@ pub struct GameTextInput { _unused: [u8; 0], } unsafe extern "C" { - #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] + #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread. All other calls to the resulting GameTextInput\n object must be done on the same calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] pub fn GameTextInput_init(env: *mut JNIEnv, max_string_size: u32) -> *mut GameTextInput; } unsafe extern "C" { @@ -5281,7 +5281,7 @@ pub const NativeAppGlueAppCmd_APP_CMD_WINDOW_INSETS_CHANGED: NativeAppGlueAppCmd #[doc = " Commands passed from the application's main Java thread to the game's thread.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] pub type NativeAppGlueAppCmd = i8; unsafe extern "C" { - #[doc = " Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next\n app command message."] + #[doc = " Call when ALooper_pollOnce() returns LOOPER_ID_MAIN, reading the next\n app command message."] pub fn android_app_read_cmd(android_app: *mut android_app) -> i8; } unsafe extern "C" { @@ -5325,8 +5325,8 @@ unsafe extern "C" { ); } unsafe extern "C" { - #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] - pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8); + #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events.\n\n The function returns true if the write operation was successful."] + pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8) -> bool; } unsafe extern "C" { #[doc = " Determines if a looper wake up was due to new input becoming available"] diff --git a/android-activity/src/game_activity/ffi_x86_64.rs b/android-activity/src/game_activity/ffi_x86_64.rs index 849863f9..ac793270 100644 --- a/android-activity/src/game_activity/ffi_x86_64.rs +++ b/android-activity/src/game_activity/ffi_x86_64.rs @@ -282,10 +282,10 @@ pub const SCNxPTR: &[u8; 3] = b"lx\0"; pub const GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT: u32 = 48; pub const GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT: u32 = 8; pub const GAMETEXTINPUT_MAJOR_VERSION: u32 = 4; -pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 0; +pub const GAMETEXTINPUT_MINOR_VERSION: u32 = 3; pub const GAMETEXTINPUT_BUGFIX_VERSION: u32 = 0; pub const GAMEACTIVITY_MAJOR_VERSION: u32 = 4; -pub const GAMEACTIVITY_MINOR_VERSION: u32 = 0; +pub const GAMEACTIVITY_MINOR_VERSION: u32 = 4; pub const GAMEACTIVITY_BUGFIX_VERSION: u32 = 0; pub const POLLIN: u32 = 1; pub const POLLPRI: u32 = 2; @@ -2325,7 +2325,7 @@ pub struct GameTextInput { _unused: [u8; 0], } unsafe extern "C" { - #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] + #[doc = " Initialize the GameTextInput library.\n If called twice without GameTextInput_destroy being called, the same pointer\n will be returned and a warning will be issued.\n @param env A JNI env valid on the calling thread. All other calls to the resulting GameTextInput\n object must be done on the same calling thread.\n @param max_string_size The maximum length of a string that can be edited. If\n zero, the maximum defaults to 65536 bytes. A buffer of this size is allocated\n at initialization.\n @return A handle to the library."] pub fn GameTextInput_init(env: *mut JNIEnv, max_string_size: u32) -> *mut GameTextInput; } unsafe extern "C" { @@ -5310,7 +5310,7 @@ pub const NativeAppGlueAppCmd_APP_CMD_WINDOW_INSETS_CHANGED: NativeAppGlueAppCmd #[doc = " Commands passed from the application's main Java thread to the game's thread.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] pub type NativeAppGlueAppCmd = i8; unsafe extern "C" { - #[doc = " Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next\n app command message."] + #[doc = " Call when ALooper_pollOnce() returns LOOPER_ID_MAIN, reading the next\n app command message."] pub fn android_app_read_cmd(android_app: *mut android_app) -> i8; } unsafe extern "C" { @@ -5354,8 +5354,8 @@ unsafe extern "C" { ); } unsafe extern "C" { - #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events."] - pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8); + #[doc = " You can send your custom events using the function below.\n\n Make sure your custom codes do not overlap with this library's ones.\n\n Values from 0 to 127 are reserved for this library; values from -128 to -1\n can be used for custom user's events.\n\n The function returns true if the write operation was successful."] + pub fn android_app_write_cmd(android_app: *mut android_app, cmd: i8) -> bool; } unsafe extern "C" { #[doc = " Determines if a looper wake up was due to new input becoming available"]