aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVamsidhar reddy Gaddam <gvamsi@google.com>2022-10-18 12:26:38 +0000
committerVamsidhar reddy Gaddam <gvamsi@google.com>2022-11-23 07:58:40 +0000
commit80bc09f4da61784fb467ffc96b4461b2f845d8c4 (patch)
tree567dec13b49c251d35fb101d4dfee5a367ef31a0
parent610c786b6f83caff3e35e833b9b805fa8e186760 (diff)
downloadgamesdk-80bc09f4da61784fb467ffc96b4461b2f845d8c4.tar.gz
Separate GameActivity events into module
Users implementing their own event handlers can now include a smaller header and implementation. Bug: 247549995 Test: Ran samples Change-Id: Ic2e0377872e2b8db3608e21ed0ac78ebbcf76851
-rw-r--r--game-activity/CMakeLists.txt1
-rw-r--r--game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.cpp460
-rw-r--r--game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h294
-rw-r--r--game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.cpp401
-rw-r--r--game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h336
-rw-r--r--game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h109
6 files changed, 850 insertions, 751 deletions
diff --git a/game-activity/CMakeLists.txt b/game-activity/CMakeLists.txt
index e947466b..c5051f29 100644
--- a/game-activity/CMakeLists.txt
+++ b/game-activity/CMakeLists.txt
@@ -23,6 +23,7 @@ set(GAMEACTIVITY_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/prefab-src/modules/game-ac
set(GAMEACTIVITY_SRCS
${GAMEACTIVITY_SRC_DIR}/game-activity/GameActivity.cpp
+ ${GAMEACTIVITY_SRC_DIR}/game-activity/GameActivityEvents.cpp
${GAMEACTIVITY_SRC_DIR}/game-activity/native_app_glue/android_native_app_glue.c
${GAMEACTIVITY_SRC_DIR}/game-text-input/gametextinput.cpp)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Os")
diff --git a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.cpp b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.cpp
index 678a5721..3c0e762a 100644
--- a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.cpp
+++ b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.cpp
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "GameActivity"
#include "GameActivity.h"
@@ -39,29 +38,9 @@
#include <mutex>
#include <string>
-// TODO(b/187147166): these functions were extracted from the Game SDK
-// (gamesdk/src/common/system_utils.h). system_utils.h/cpp should be used
-// instead.
-namespace {
-
-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;
- else
- return "";
-}
+#include "GameActivityLog.h"
-std::string GetSystemProp(const char *key, const char *default_value = "") {
- return getSystemPropViaGet(key, default_value);
-}
-
-int GetSystemPropAsInt(const char *key, int default_value = 0) {
- std::string prop = GetSystemProp(key);
- return prop == "" ? default_value : strtoll(prop.c_str(), nullptr, 10);
-}
+namespace {
struct OwnedGameTextInputState {
OwnedGameTextInputState &operator=(const GameTextInputState &rhs) {
@@ -76,93 +55,6 @@ struct OwnedGameTextInputState {
} // anonymous namespace
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);
-#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__);
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__);
-#ifdef NDEBUG
-#define ALOGV(...)
-#else
-#define ALOGV(...) \
- __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__);
-#endif
-
-/* Returns 2nd arg. Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(first, second, ...) second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...) , ##__VA_ARGS__
-
-#define android_printAssert(cond, tag, fmt...) \
- __android_log_assert(cond, tag, \
- __android_second(0, ##fmt, NULL) __android_rest(fmt))
-
-#define CONDITION(cond) (__builtin_expect((cond) != 0, 0))
-
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
- ((CONDITION(cond)) \
- ? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) \
- : (void)0)
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
- (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__)))
-#endif
-
-/*
- * Simplified macro to send a warning system log message using current LOG_TAG.
- */
-#ifndef SLOGW
-#define SLOGW(...) \
- ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ##__VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds. Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
-#endif
-
-#define LOG_TRACE(...)
-
#ifndef NELEM
#define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
#endif
@@ -865,58 +757,6 @@ static void onSurfaceDestroyed_native(JNIEnv *env, jobject javaGameActivity,
}
}
-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};
-
-extern "C" void GameActivityPointerAxes_enableAxis(int32_t axis) {
- if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) {
- return;
- }
-
- enabledAxes[axis] = true;
-}
-
-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;
- }
-
- return pointerInfo->axisValues[axis];
-}
-
-extern "C" void GameActivityPointerAxes_disableAxis(int32_t axis) {
- if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) {
- return;
- }
-
- 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) {
- return 0;
- }
-
- if (!enabledAxes[axis]) {
- ALOGW("Axis %d must be enabled before it can be accessed.", axis);
- return 0;
- }
-
- return event->historicalAxisValues[event->pointerCount * historyPos + axis];
-}
-
extern "C" void GameActivity_setImeEditorInfo(GameActivity *activity,
int inputType, int actionId,
int imeOptions) {
@@ -997,302 +837,6 @@ extern "C" int GameActivity_getUIMode(GameActivity *) {
return gConfiguration.uiMode;
}
-static struct {
- jmethodID getDeviceId;
- jmethodID getSource;
- jmethodID getAction;
-
- jmethodID getEventTime;
- jmethodID getDownTime;
-
- jmethodID getFlags;
- jmethodID getMetaState;
-
- jmethodID getActionButton;
- jmethodID getButtonState;
- jmethodID getClassification;
- jmethodID getEdgeFlags;
-
- jmethodID getHistorySize;
- jmethodID getHistoricalEventTime;
-
- jmethodID getPointerCount;
- jmethodID getPointerId;
-
- jmethodID getToolType;
-
- jmethodID getRawX;
- jmethodID getRawY;
- jmethodID getXPrecision;
- jmethodID getYPrecision;
- jmethodID getAxisValue;
-
- 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_fromJava(
- JNIEnv *env, jobject motionEvent, GameActivityMotionEvent *out_event) {
- static bool gMotionEventClassInfoInitialized = false;
- if (!gMotionEventClassInfoInitialized) {
- int sdkVersion = 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");
- gMotionEventClassInfoInitialized = true;
- }
-
- int pointerCount =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getPointerCount);
- 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);
- }
- }
- }
-
- int historySize =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getHistorySize);
- out_event->historySize = historySize;
- out_event->historicalAxisValues =
- new float[historySize * pointerCount *
- GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
- out_event->historicalEventTimesMillis = new long[historySize];
- out_event->historicalEventTimesNanos = new long[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);
- }
- }
- }
- }
-
- out_event->deviceId =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getDeviceId);
- out_event->source =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getSource);
- out_event->action =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getAction);
- out_event->eventTime =
- env->CallLongMethod(motionEvent, gMotionEventClassInfo.getEventTime) *
- 1000000;
- out_event->downTime =
- env->CallLongMethod(motionEvent, gMotionEventClassInfo.getDownTime) *
- 1000000;
- out_event->flags =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getFlags);
- out_event->metaState =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getMetaState);
- out_event->actionButton =
- gMotionEventClassInfo.getActionButton
- ? env->CallIntMethod(motionEvent,
- gMotionEventClassInfo.getActionButton)
- : 0;
- out_event->buttonState =
- gMotionEventClassInfo.getButtonState
- ? env->CallIntMethod(motionEvent,
- gMotionEventClassInfo.getButtonState)
- : 0;
- out_event->classification =
- gMotionEventClassInfo.getClassification
- ? env->CallIntMethod(motionEvent,
- gMotionEventClassInfo.getClassification)
- : 0;
- out_event->edgeFlags =
- env->CallIntMethod(motionEvent, gMotionEventClassInfo.getEdgeFlags);
- out_event->precisionX =
- env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getXPrecision);
- out_event->precisionY =
- env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getYPrecision);
-}
-
-static struct {
- jmethodID getDeviceId;
- jmethodID getSource;
- jmethodID getAction;
-
- jmethodID getEventTime;
- jmethodID getDownTime;
-
- jmethodID getFlags;
- jmethodID getMetaState;
-
- jmethodID getModifiers;
- jmethodID getRepeatCount;
- jmethodID getKeyCode;
- jmethodID getScanCode;
- jmethodID getUnicodeChar;
-} gKeyEventClassInfo;
-
-extern "C" void GameActivityKeyEvent_fromJava(JNIEnv *env, jobject keyEvent,
- GameActivityKeyEvent *out_event) {
- static bool gKeyEventClassInfoInitialized = false;
- if (!gKeyEventClassInfoInitialized) {
- int sdkVersion = 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");
-
- gKeyEventClassInfoInitialized = true;
- }
-
- *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)};
-}
-
static bool onTouchEvent_native(JNIEnv *env, jobject javaGameActivity,
jlong handle, jobject motionEvent) {
if (handle == 0) return false;
diff --git a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h
index a52ba138..67f0c042 100644
--- a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h
+++ b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivity.h
@@ -36,6 +36,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include "game-activity/GameActivityEvents.h"
#include "game-text-input/gametextinput.h"
#ifdef __cplusplus
@@ -124,272 +125,6 @@ typedef struct GameActivity {
} GameActivity;
/**
- * The maximum number of axes supported in an Android MotionEvent.
- * See https://developer.android.com/ndk/reference/group/input.
- */
-#define GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT 48
-
-/**
- * \brief Describe information about a pointer, found in a
- * GameActivityMotionEvent.
- *
- * You can read values directly from this structure, or use helper functions
- * (`GameActivityPointerAxes_getX`, `GameActivityPointerAxes_getY` and
- * `GameActivityPointerAxes_getAxisValue`).
- *
- * The X axis and Y axis are enabled by default but any other axis that you want
- * to read **must** be enabled first, using
- * `GameActivityPointerAxes_enableAxis`.
- *
- * \see GameActivityMotionEvent
- */
-typedef struct GameActivityPointerAxes {
- int32_t id;
- int32_t toolType;
- float axisValues[GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
- float rawX;
- float rawY;
-} GameActivityPointerAxes;
-
-/** \brief Get the toolType of the pointer. */
-inline int32_t GameActivityPointerAxes_getToolType(
- const GameActivityPointerAxes* pointerInfo) {
- return pointerInfo->toolType;
-}
-
-/** \brief Get the current X coordinate of the pointer. */
-inline float GameActivityPointerAxes_getX(
- const GameActivityPointerAxes* pointerInfo) {
- return pointerInfo->axisValues[AMOTION_EVENT_AXIS_X];
-}
-
-/** \brief Get the current Y coordinate of the pointer. */
-inline float GameActivityPointerAxes_getY(
- const GameActivityPointerAxes* pointerInfo) {
- return pointerInfo->axisValues[AMOTION_EVENT_AXIS_Y];
-}
-
-/**
- * \brief Enable the specified axis, so that its value is reported in the
- * GameActivityPointerAxes structures stored in a motion event.
- *
- * You must enable any axis that you want to read, apart from
- * `AMOTION_EVENT_AXIS_X` and `AMOTION_EVENT_AXIS_Y` that are enabled by
- * default.
- *
- * If the axis index is out of range, nothing is done.
- */
-void GameActivityPointerAxes_enableAxis(int32_t axis);
-
-/**
- * \brief Disable the specified axis. Its value won't be reported in the
- * GameActivityPointerAxes structures stored in a motion event anymore.
- *
- * Apart from X and Y, any axis that you want to read **must** be enabled first,
- * using `GameActivityPointerAxes_enableAxis`.
- *
- * If the axis index is out of range, nothing is done.
- */
-void GameActivityPointerAxes_disableAxis(int32_t axis);
-
-/**
- * \brief Get the value of the requested axis.
- *
- * Apart from X and Y, any axis that you want to read **must** be enabled first,
- * using `GameActivityPointerAxes_enableAxis`.
- *
- * Find the valid enums for the axis (`AMOTION_EVENT_AXIS_X`,
- * `AMOTION_EVENT_AXIS_Y`, `AMOTION_EVENT_AXIS_PRESSURE`...)
- * in https://developer.android.com/ndk/reference/group/input.
- *
- * @param pointerInfo The structure containing information about the pointer,
- * obtained from GameActivityMotionEvent.
- * @param axis The axis to get the value from
- * @return The value of the axis, or 0 if the axis is invalid or was not
- * enabled.
- */
-float GameActivityPointerAxes_getAxisValue(
- const GameActivityPointerAxes* pointerInfo, int32_t axis);
-
-inline float GameActivityPointerAxes_getPressure(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_PRESSURE);
-}
-
-inline float GameActivityPointerAxes_getSize(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_SIZE);
-}
-
-inline float GameActivityPointerAxes_getTouchMajor(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_TOUCH_MAJOR);
-}
-
-inline float GameActivityPointerAxes_getTouchMinor(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_TOUCH_MINOR);
-}
-
-inline float GameActivityPointerAxes_getToolMajor(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_TOOL_MAJOR);
-}
-
-inline float GameActivityPointerAxes_getToolMinor(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_TOOL_MINOR);
-}
-
-inline float GameActivityPointerAxes_getOrientation(
- const GameActivityPointerAxes* pointerInfo) {
- return GameActivityPointerAxes_getAxisValue(pointerInfo,
- AMOTION_EVENT_AXIS_ORIENTATION);
-}
-
-/**
- * The maximum number of pointers returned inside a motion event.
- */
-#if (defined GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE)
-#define GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT \
- GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE
-#else
-#define GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT 8
-#endif
-
-/**
- * \brief Describe a motion event that happened on the GameActivity SurfaceView.
- *
- * This is 1:1 mapping to the information contained in a Java `MotionEvent`
- * (see https://developer.android.com/reference/android/view/MotionEvent).
- * The only exception is the event times, which are reported as
- * nanoseconds in this struct.
- */
-typedef struct GameActivityMotionEvent {
- int32_t deviceId;
- int32_t source;
- int32_t action;
-
- int64_t eventTime;
- int64_t downTime;
-
- int32_t flags;
- int32_t metaState;
-
- int32_t actionButton;
- int32_t buttonState;
- int32_t classification;
- int32_t edgeFlags;
-
- uint32_t pointerCount;
- GameActivityPointerAxes
- pointers[GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT];
-
- int historySize;
- long* historicalEventTimesMillis;
- long* historicalEventTimesNanos;
- float* historicalAxisValues;
-
- float precisionX;
- float precisionY;
-} GameActivityMotionEvent;
-
-/**
- * \brief Describe a key event that happened on the GameActivity SurfaceView.
- *
- * This is 1:1 mapping to the information contained in a Java `KeyEvent`
- * (see https://developer.android.com/reference/android/view/KeyEvent).
- * The only exception is the event times, which are reported as
- * nanoseconds in this struct.
- */
-typedef struct GameActivityKeyEvent {
- int32_t deviceId;
- int32_t source;
- int32_t action;
-
- int64_t eventTime;
- int64_t downTime;
-
- int32_t flags;
- int32_t metaState;
-
- int32_t modifiers;
- int32_t repeatCount;
- int32_t keyCode;
- int32_t scanCode;
- int32_t unicodeChar;
-} GameActivityKeyEvent;
-
-float GameActivityMotionEvent_getHistoricalAxisValue(
- const GameActivityMotionEvent* event, int axis, int pointerIndex,
- int historyPos);
-
-inline int GameActivityMotionEvent_getHistorySize(
- const GameActivityMotionEvent* event) {
- return event->historySize;
-}
-
-inline float GameActivityMotionEvent_getHistoricalX(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_X, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalY(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_Y, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalPressure(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalSize(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_SIZE, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalTouchMajor(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalTouchMinor(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalToolMajor(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalToolMinor(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historyPos);
-}
-
-inline float GameActivityMotionEvent_getHistoricalOrientation(
- const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
- return GameActivityMotionEvent_getHistoricalAxisValue(
- event, AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historyPos);
-}
-
-/**
* A function the user should call from their callback with the data, its length
* and the library- supplied context.
*/
@@ -543,33 +278,6 @@ typedef struct GameActivityCallbacks {
void (*onContentRectChanged)(GameActivity *activity, const ARect *rect);
} GameActivityCallbacks;
-/** \brief Handle the freeing of the GameActivityMotionEvent struct. */
-void GameActivityMotionEvent_destroy(GameActivityMotionEvent* c_event);
-
-/**
- * \brief Convert a Java `MotionEvent` to a `GameActivityMotionEvent`.
- *
- * This is done automatically by the GameActivity: see `onTouchEvent` to set
- * a callback to consume the received events.
- * This function can be used if you re-implement events handling in your own
- * activity.
- * Ownership of out_event is maintained by the caller.
- */
-void GameActivityMotionEvent_fromJava(JNIEnv* env, jobject motionEvent,
- GameActivityMotionEvent* out_event);
-
-/**
- * \brief Convert a Java `KeyEvent` to a `GameActivityKeyEvent`.
- *
- * This is done automatically by the GameActivity: see `onKeyUp` and `onKeyDown`
- * to set a callback to consume the received events.
- * This function can be used if you re-implement events handling in your own
- * activity.
- * Ownership of out_event is maintained by the caller.
- */
-void GameActivityKeyEvent_fromJava(JNIEnv* env, jobject motionEvent,
- GameActivityKeyEvent* out_event);
-
/**
* This is the function that must be in the native code to instantiate the
* application's native activity. It is called with the activity instance (see
diff --git a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.cpp b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.cpp
new file mode 100644
index 00000000..2cf2356e
--- /dev/null
+++ b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GameActivityEvents.h"
+
+#include <sys/system_properties.h>
+
+#include <string>
+
+#include "GameActivityLog.h"
+
+// TODO(b/187147166): these functions were extracted from the Game SDK
+// (gamesdk/src/common/system_utils.h). system_utils.h/cpp should be used
+// instead.
+namespace {
+
+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;
+ else
+ return "";
+}
+
+std::string GetSystemProp(const char *key, const char *default_value = "") {
+ return getSystemPropViaGet(key, default_value);
+}
+
+int GetSystemPropAsInt(const char *key, int default_value = 0) {
+ std::string prop = GetSystemProp(key);
+ return prop == "" ? default_value : strtoll(prop.c_str(), nullptr, 10);
+}
+
+} // anonymous namespace
+
+#ifndef NELEM
+#define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
+#endif
+
+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};
+
+extern "C" void GameActivityPointerAxes_enableAxis(int32_t axis) {
+ if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) {
+ return;
+ }
+
+ enabledAxes[axis] = true;
+}
+
+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;
+ }
+
+ return pointerInfo->axisValues[axis];
+}
+
+extern "C" void GameActivityPointerAxes_disableAxis(int32_t axis) {
+ if (axis < 0 || axis >= GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT) {
+ return;
+ }
+
+ 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) {
+ return 0;
+ }
+
+ if (!enabledAxes[axis]) {
+ ALOGW("Axis %d must be enabled before it can be accessed.", axis);
+ return 0;
+ }
+
+ return event->historicalAxisValues[event->pointerCount * historyPos + axis];
+}
+
+static struct {
+ jmethodID getDeviceId;
+ jmethodID getSource;
+ jmethodID getAction;
+
+ jmethodID getEventTime;
+ jmethodID getDownTime;
+
+ jmethodID getFlags;
+ jmethodID getMetaState;
+
+ jmethodID getActionButton;
+ jmethodID getButtonState;
+ jmethodID getClassification;
+ jmethodID getEdgeFlags;
+
+ jmethodID getHistorySize;
+ jmethodID getHistoricalEventTime;
+
+ jmethodID getPointerCount;
+ jmethodID getPointerId;
+
+ jmethodID getToolType;
+
+ jmethodID getRawX;
+ jmethodID getRawY;
+ jmethodID getXPrecision;
+ jmethodID getYPrecision;
+ jmethodID getAxisValue;
+
+ 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_fromJava(
+ JNIEnv *env, jobject motionEvent, GameActivityMotionEvent *out_event) {
+ static bool gMotionEventClassInfoInitialized = false;
+ if (!gMotionEventClassInfoInitialized) {
+ int sdkVersion = 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");
+ gMotionEventClassInfoInitialized = true;
+ }
+
+ int pointerCount =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getPointerCount);
+ 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);
+ }
+ }
+ }
+
+ int historySize =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getHistorySize);
+ out_event->historySize = historySize;
+ out_event->historicalAxisValues =
+ new float[historySize * pointerCount *
+ GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
+ out_event->historicalEventTimesMillis = new long[historySize];
+ out_event->historicalEventTimesNanos = new long[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);
+ }
+ }
+ }
+ }
+
+ out_event->deviceId =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getDeviceId);
+ out_event->source =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getSource);
+ out_event->action =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getAction);
+ out_event->eventTime =
+ env->CallLongMethod(motionEvent, gMotionEventClassInfo.getEventTime) *
+ 1000000;
+ out_event->downTime =
+ env->CallLongMethod(motionEvent, gMotionEventClassInfo.getDownTime) *
+ 1000000;
+ out_event->flags =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getFlags);
+ out_event->metaState =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getMetaState);
+ out_event->actionButton =
+ gMotionEventClassInfo.getActionButton
+ ? env->CallIntMethod(motionEvent,
+ gMotionEventClassInfo.getActionButton)
+ : 0;
+ out_event->buttonState =
+ gMotionEventClassInfo.getButtonState
+ ? env->CallIntMethod(motionEvent,
+ gMotionEventClassInfo.getButtonState)
+ : 0;
+ out_event->classification =
+ gMotionEventClassInfo.getClassification
+ ? env->CallIntMethod(motionEvent,
+ gMotionEventClassInfo.getClassification)
+ : 0;
+ out_event->edgeFlags =
+ env->CallIntMethod(motionEvent, gMotionEventClassInfo.getEdgeFlags);
+ out_event->precisionX =
+ env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getXPrecision);
+ out_event->precisionY =
+ env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getYPrecision);
+}
+
+static struct {
+ jmethodID getDeviceId;
+ jmethodID getSource;
+ jmethodID getAction;
+
+ jmethodID getEventTime;
+ jmethodID getDownTime;
+
+ jmethodID getFlags;
+ jmethodID getMetaState;
+
+ jmethodID getModifiers;
+ jmethodID getRepeatCount;
+ jmethodID getKeyCode;
+ jmethodID getScanCode;
+ jmethodID getUnicodeChar;
+} gKeyEventClassInfo;
+
+extern "C" void GameActivityKeyEvent_fromJava(JNIEnv *env, jobject keyEvent,
+ GameActivityKeyEvent *out_event) {
+ static bool gKeyEventClassInfoInitialized = false;
+ if (!gKeyEventClassInfoInitialized) {
+ int sdkVersion = 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");
+
+ gKeyEventClassInfoInitialized = true;
+ }
+
+ *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)};
+}
diff --git a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h
new file mode 100644
index 00000000..4149ddae
--- /dev/null
+++ b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityEvents.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup GameActivity Game Activity Events
+ * The interface to use Game Activity Events.
+ * @{
+ */
+
+/**
+ * @file GameActivityEvents.h
+ */
+#ifndef ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_H
+#define ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_H
+
+#include <android/input.h>
+#include <jni.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The maximum number of axes supported in an Android MotionEvent.
+ * See https://developer.android.com/ndk/reference/group/input.
+ */
+#define GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT 48
+
+/**
+ * \brief Describe information about a pointer, found in a
+ * GameActivityMotionEvent.
+ *
+ * You can read values directly from this structure, or use helper functions
+ * (`GameActivityPointerAxes_getX`, `GameActivityPointerAxes_getY` and
+ * `GameActivityPointerAxes_getAxisValue`).
+ *
+ * The X axis and Y axis are enabled by default but any other axis that you want
+ * to read **must** be enabled first, using
+ * `GameActivityPointerAxes_enableAxis`.
+ *
+ * \see GameActivityMotionEvent
+ */
+typedef struct GameActivityPointerAxes {
+ int32_t id;
+ int32_t toolType;
+ float axisValues[GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
+ float rawX;
+ float rawY;
+} GameActivityPointerAxes;
+
+/** \brief Get the toolType of the pointer. */
+inline int32_t GameActivityPointerAxes_getToolType(
+ const GameActivityPointerAxes* pointerInfo) {
+ return pointerInfo->toolType;
+}
+
+/** \brief Get the current X coordinate of the pointer. */
+inline float GameActivityPointerAxes_getX(
+ const GameActivityPointerAxes* pointerInfo) {
+ return pointerInfo->axisValues[AMOTION_EVENT_AXIS_X];
+}
+
+/** \brief Get the current Y coordinate of the pointer. */
+inline float GameActivityPointerAxes_getY(
+ const GameActivityPointerAxes* pointerInfo) {
+ return pointerInfo->axisValues[AMOTION_EVENT_AXIS_Y];
+}
+
+/**
+ * \brief Enable the specified axis, so that its value is reported in the
+ * GameActivityPointerAxes structures stored in a motion event.
+ *
+ * You must enable any axis that you want to read, apart from
+ * `AMOTION_EVENT_AXIS_X` and `AMOTION_EVENT_AXIS_Y` that are enabled by
+ * default.
+ *
+ * If the axis index is out of range, nothing is done.
+ */
+void GameActivityPointerAxes_enableAxis(int32_t axis);
+
+/**
+ * \brief Disable the specified axis. Its value won't be reported in the
+ * GameActivityPointerAxes structures stored in a motion event anymore.
+ *
+ * Apart from X and Y, any axis that you want to read **must** be enabled first,
+ * using `GameActivityPointerAxes_enableAxis`.
+ *
+ * If the axis index is out of range, nothing is done.
+ */
+void GameActivityPointerAxes_disableAxis(int32_t axis);
+
+/**
+ * \brief Get the value of the requested axis.
+ *
+ * Apart from X and Y, any axis that you want to read **must** be enabled first,
+ * using `GameActivityPointerAxes_enableAxis`.
+ *
+ * Find the valid enums for the axis (`AMOTION_EVENT_AXIS_X`,
+ * `AMOTION_EVENT_AXIS_Y`, `AMOTION_EVENT_AXIS_PRESSURE`...)
+ * in https://developer.android.com/ndk/reference/group/input.
+ *
+ * @param pointerInfo The structure containing information about the pointer,
+ * obtained from GameActivityMotionEvent.
+ * @param axis The axis to get the value from
+ * @return The value of the axis, or 0 if the axis is invalid or was not
+ * enabled.
+ */
+float GameActivityPointerAxes_getAxisValue(
+ const GameActivityPointerAxes* pointerInfo, int32_t axis);
+
+inline float GameActivityPointerAxes_getPressure(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_PRESSURE);
+}
+
+inline float GameActivityPointerAxes_getSize(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_SIZE);
+}
+
+inline float GameActivityPointerAxes_getTouchMajor(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+}
+
+inline float GameActivityPointerAxes_getTouchMinor(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_TOUCH_MINOR);
+}
+
+inline float GameActivityPointerAxes_getToolMajor(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_TOOL_MAJOR);
+}
+
+inline float GameActivityPointerAxes_getToolMinor(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_TOOL_MINOR);
+}
+
+inline float GameActivityPointerAxes_getOrientation(
+ const GameActivityPointerAxes* pointerInfo) {
+ return GameActivityPointerAxes_getAxisValue(pointerInfo,
+ AMOTION_EVENT_AXIS_ORIENTATION);
+}
+
+/**
+ * The maximum number of pointers returned inside a motion event.
+ */
+#if (defined GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE)
+#define GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT \
+ GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT_OVERRIDE
+#else
+#define GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT 8
+#endif
+
+/**
+ * \brief Describe a motion event that happened on the GameActivity SurfaceView.
+ *
+ * This is 1:1 mapping to the information contained in a Java `MotionEvent`
+ * (see https://developer.android.com/reference/android/view/MotionEvent).
+ */
+typedef struct GameActivityMotionEvent {
+ int32_t deviceId;
+ int32_t source;
+ int32_t action;
+
+ int64_t eventTime;
+ int64_t downTime;
+
+ int32_t flags;
+ int32_t metaState;
+
+ int32_t actionButton;
+ int32_t buttonState;
+ int32_t classification;
+ int32_t edgeFlags;
+
+ uint32_t pointerCount;
+ GameActivityPointerAxes
+ pointers[GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT];
+
+ int historySize;
+ long* historicalEventTimesMillis;
+ long* historicalEventTimesNanos;
+ float* historicalAxisValues;
+
+ float precisionX;
+ float precisionY;
+} GameActivityMotionEvent;
+
+float GameActivityMotionEvent_getHistoricalAxisValue(
+ const GameActivityMotionEvent* event, int axis, int pointerIndex,
+ int historyPos);
+
+inline int GameActivityMotionEvent_getHistorySize(
+ const GameActivityMotionEvent* event) {
+ return event->historySize;
+}
+
+inline float GameActivityMotionEvent_getHistoricalX(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_X, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalY(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_Y, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalPressure(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalSize(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_SIZE, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalTouchMajor(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalTouchMinor(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalToolMajor(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalToolMinor(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historyPos);
+}
+
+inline float GameActivityMotionEvent_getHistoricalOrientation(
+ const GameActivityMotionEvent* event, int pointerIndex, int historyPos) {
+ return GameActivityMotionEvent_getHistoricalAxisValue(
+ event, AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historyPos);
+}
+
+/** \brief Handle the freeing of the GameActivityMotionEvent struct. */
+void GameActivityMotionEvent_destroy(GameActivityMotionEvent* c_event);
+
+/**
+ * \brief Convert a Java `MotionEvent` to a `GameActivityMotionEvent`.
+ *
+ * This is done automatically by the GameActivity: see `onTouchEvent` to set
+ * a callback to consume the received events.
+ * This function can be used if you re-implement events handling in your own
+ * activity.
+ * Ownership of out_event is maintained by the caller.
+ */
+void GameActivityMotionEvent_fromJava(JNIEnv* env, jobject motionEvent,
+ GameActivityMotionEvent* out_event);
+
+/**
+ * \brief Describe a key event that happened on the GameActivity SurfaceView.
+ *
+ * This is 1:1 mapping to the information contained in a Java `KeyEvent`
+ * (see https://developer.android.com/reference/android/view/KeyEvent).
+ * The only exception is the event times, which are reported as
+ * nanoseconds in this struct.
+ */
+typedef struct GameActivityKeyEvent {
+ int32_t deviceId;
+ int32_t source;
+ int32_t action;
+
+ int64_t eventTime;
+ int64_t downTime;
+
+ int32_t flags;
+ int32_t metaState;
+
+ int32_t modifiers;
+ int32_t repeatCount;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t unicodeChar;
+} GameActivityKeyEvent;
+
+/**
+ * \brief Convert a Java `KeyEvent` to a `GameActivityKeyEvent`.
+ *
+ * This is done automatically by the GameActivity: see `onKeyUp` and `onKeyDown`
+ * to set a callback to consume the received events.
+ * This function can be used if you re-implement events handling in your own
+ * activity.
+ * Ownership of out_event is maintained by the caller.
+ */
+void GameActivityKeyEvent_fromJava(JNIEnv* env, jobject motionEvent,
+ GameActivityKeyEvent* out_event);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_EVENTS_H
diff --git a/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h
new file mode 100644
index 00000000..ba9a9e95
--- /dev/null
+++ b/game-activity/prefab-src/modules/game-activity/include/game-activity/GameActivityLog.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_GAME_SDK_GAME_ACTIVITY_LOG_H_
+#define ANDROID_GAME_SDK_GAME_ACTIVITY_LOG_H_
+
+#define LOG_TAG "GameActivity"
+#include <android/log.h>
+
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);
+#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__);
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__);
+#ifdef NDEBUG
+#define ALOGV(...)
+#else
+#define ALOGV(...) \
+ __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__);
+#endif
+
+/* Returns 2nd arg. Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(first, second, ...) second
+
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...) , ##__VA_ARGS__
+
+#define android_printAssert(cond, tag, fmt...) \
+ __android_log_assert(cond, tag, \
+ __android_second(0, ##fmt, NULL) __android_rest(fmt))
+
+#define CONDITION(cond) (__builtin_expect((cond) != 0, 0))
+
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) \
+ : (void)0)
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+ (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__)))
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) \
+ ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+ ((__predict_false(cond)) \
+ ? ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
+#else
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ##__VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds. Uses the current LOG_TAG.
+ */
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
+#endif
+
+#define LOG_TRACE(...)
+
+#endif // ANDROID_GAME_SDK_GAME_ACTIVITY_LOG_H_