diff options
Diffstat (limited to 'game-activity/prefab-src/modules')
5 files changed, 849 insertions, 751 deletions
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_ |