(&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"]