PlatformAndroid.cpp 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641
  1. #ifdef __ANDROID__
  2. #include "Base.h"
  3. #include "Platform.h"
  4. #include "FileSystem.h"
  5. #include "Game.h"
  6. #include "Form.h"
  7. #include "ScriptController.h"
  8. #include <unistd.h>
  9. #include <android/sensor.h>
  10. #include <android_native_app_glue.h>
  11. #include <android/log.h>
  12. // Externally referenced global variables.
  13. struct android_app* __state;
  14. AAssetManager* __assetManager;
  15. static bool __initialized;
  16. static bool __suspended;
  17. static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
  18. static EGLContext __eglContext = EGL_NO_CONTEXT;
  19. static EGLSurface __eglSurface = EGL_NO_SURFACE;
  20. static EGLConfig __eglConfig = 0;
  21. static int __width;
  22. static int __height;
  23. static struct timespec __timespec;
  24. static double __timeStart;
  25. static double __timeAbsolute;
  26. static bool __vsync = WINDOW_VSYNC;
  27. static ASensorManager* __sensorManager;
  28. static ASensorEventQueue* __sensorEventQueue;
  29. static ASensorEvent __sensorEvent;
  30. static const ASensor* __accelerometerSensor;
  31. static const ASensor* __gyroscopeSensor;
  32. static float __accelRawX;
  33. static float __accelRawY;
  34. static float __accelRawZ;
  35. static float __gyroRawX;
  36. static float __gyroRawY;
  37. static float __gyroRawZ;
  38. static int __orientationAngle = 90;
  39. static bool __multiSampling = false;
  40. static bool __multiTouch = false;
  41. static int __primaryTouchId = -1;
  42. static bool __displayKeyboard = false;
  43. // OpenGL VAO functions.
  44. static const char* __glExtensions;
  45. PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
  46. PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
  47. PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
  48. PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
  49. #define GESTURE_TAP_DURATION_MAX 200
  50. #define GESTURE_LONG_TAP_DURATION_MIN GESTURE_TAP_DURATION_MAX
  51. #define GESTURE_DRAG_START_DURATION_MIN GESTURE_LONG_TAP_DURATION_MIN
  52. #define GESTURE_DRAG_DISTANCE_MIN 30
  53. #define GESTURE_SWIPE_DURATION_MAX 400
  54. #define GESTURE_SWIPE_DISTANCE_MIN 50
  55. #define GESTURE_PINCH_DISTANCE_MIN GESTURE_DRAG_DISTANCE_MIN
  56. static bool __gestureDraging = false;
  57. static bool __gesturePinching = false;
  58. static std::pair<int, int> __gesturePointer0LastPosition, __gesturePointer1LastPosition;
  59. static std::pair<int, int> __gesturePointer0CurrentPosition, __gesturePointer1CurrentPosition;
  60. static std::pair<int, int> __gesturePinchCentroid;
  61. static int __gesturePointer0Delta, __gesturePointer1Delta;
  62. static std::bitset<6> __gestureEventsProcessed;
  63. struct TouchPointerData
  64. {
  65. size_t pointerId;
  66. bool pressed;
  67. double time;
  68. int x;
  69. int y;
  70. };
  71. TouchPointerData __pointer0;
  72. TouchPointerData __pointer1;
  73. namespace gameplay
  74. {
  75. static double timespec2millis(struct timespec *a)
  76. {
  77. GP_ASSERT(a);
  78. return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
  79. }
  80. extern void print(const char* format, ...)
  81. {
  82. GP_ASSERT(format);
  83. va_list argptr;
  84. va_start(argptr, format);
  85. __android_log_vprint(ANDROID_LOG_INFO, "gameplay-native-activity", format, argptr);
  86. va_end(argptr);
  87. }
  88. extern int strcmpnocase(const char* s1, const char* s2)
  89. {
  90. return strcasecmp(s1, s2);
  91. }
  92. static EGLenum checkErrorEGL(const char* msg)
  93. {
  94. GP_ASSERT(msg);
  95. static const char* errmsg[] =
  96. {
  97. "EGL function succeeded",
  98. "EGL is not initialized, or could not be initialized, for the specified display",
  99. "EGL cannot access a requested resource",
  100. "EGL failed to allocate resources for the requested operation",
  101. "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
  102. "EGLConfig argument does not name a valid EGLConfig",
  103. "EGLContext argument does not name a valid EGLContext",
  104. "EGL current surface of the calling thread is no longer valid",
  105. "EGLDisplay argument does not name a valid EGLDisplay",
  106. "EGL arguments are inconsistent",
  107. "EGLNativePixmapType argument does not refer to a valid native pixmap",
  108. "EGLNativeWindowType argument does not refer to a valid native window",
  109. "EGL one or more argument values are invalid",
  110. "EGLSurface argument does not name a valid surface configured for rendering",
  111. "EGL power management event has occurred",
  112. };
  113. EGLenum error = eglGetError();
  114. print("%s: %s.", msg, errmsg[error - EGL_SUCCESS]);
  115. return error;
  116. }
  117. static int getRotation()
  118. {
  119. jint rotation;
  120. // Get the android application's activity.
  121. ANativeActivity* activity = __state->activity;
  122. JavaVM* jvm = __state->activity->vm;
  123. JNIEnv* env = NULL;
  124. jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
  125. jint res = jvm->AttachCurrentThread(&env, NULL);
  126. if (res == JNI_ERR)
  127. {
  128. GP_ERROR("Failed to retrieve JVM environment when entering message pump.");
  129. return -1;
  130. }
  131. GP_ASSERT(env);
  132. jclass clsContext = env->FindClass("android/content/Context");
  133. GP_ASSERT(clsContext != NULL);
  134. jmethodID getSystemService = env->GetMethodID(clsContext, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
  135. GP_ASSERT(getSystemService != NULL);
  136. jfieldID WINDOW_SERVICE_ID = env->GetStaticFieldID(clsContext, "WINDOW_SERVICE", "Ljava/lang/String;");
  137. GP_ASSERT(WINDOW_SERVICE_ID != NULL);
  138. jstring WINDOW_SERVICE = (jstring) env->GetStaticObjectField(clsContext, WINDOW_SERVICE_ID);
  139. GP_ASSERT(WINDOW_SERVICE != NULL);
  140. jobject windowManager = env->CallObjectMethod(activity->clazz, getSystemService, WINDOW_SERVICE);
  141. GP_ASSERT(windowManager != NULL);
  142. jclass clsWindowManager = env->FindClass("android/view/WindowManager");
  143. GP_ASSERT(clsWindowManager != NULL);
  144. jmethodID getDefaultDisplay = env->GetMethodID(clsWindowManager, "getDefaultDisplay", "()Landroid/view/Display;");
  145. GP_ASSERT(getDefaultDisplay != NULL);
  146. jobject defaultDisplay = env->CallObjectMethod(windowManager, getDefaultDisplay);
  147. GP_ASSERT(defaultDisplay != NULL);
  148. jclass clsDisplay = env->FindClass("android/view/Display");
  149. GP_ASSERT(clsDisplay != NULL);
  150. jmethodID getRotation = env->GetMethodID(clsDisplay, "getRotation", "()I");
  151. GP_ASSERT(getRotation != NULL)
  152. rotation = env->CallIntMethod(defaultDisplay, getRotation);
  153. return rotation;
  154. }
  155. // Initialized EGL resources.
  156. static bool initEGL()
  157. {
  158. int samples = 0;
  159. Properties* config = Game::getInstance()->getConfig()->getNamespace("window", true);
  160. if (config)
  161. {
  162. samples = std::max(config->getInt("samples"), 0);
  163. }
  164. // Hard-coded to 32-bit/OpenGL ES 2.0.
  165. // NOTE: EGL_SAMPLE_BUFFERS, EGL_SAMPLES and EGL_DEPTH_SIZE MUST remain at the beginning of the attribute list
  166. // since they are expected to be at indices 0-5 in config fallback code later.
  167. // EGL_DEPTH_SIZE is also expected to
  168. EGLint eglConfigAttrs[] =
  169. {
  170. EGL_SAMPLE_BUFFERS, samples > 0 ? 1 : 0,
  171. EGL_SAMPLES, samples,
  172. EGL_DEPTH_SIZE, 24,
  173. EGL_RED_SIZE, 8,
  174. EGL_GREEN_SIZE, 8,
  175. EGL_BLUE_SIZE, 8,
  176. EGL_ALPHA_SIZE, 8,
  177. EGL_STENCIL_SIZE, 8,
  178. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  179. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  180. EGL_NONE
  181. };
  182. __multiSampling = samples > 0;
  183. EGLint eglConfigCount;
  184. const EGLint eglContextAttrs[] =
  185. {
  186. EGL_CONTEXT_CLIENT_VERSION, 2,
  187. EGL_NONE
  188. };
  189. const EGLint eglSurfaceAttrs[] =
  190. {
  191. EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
  192. EGL_NONE
  193. };
  194. if (__eglDisplay == EGL_NO_DISPLAY && __eglContext == EGL_NO_CONTEXT)
  195. {
  196. // Get the EGL display and initialize.
  197. __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  198. if (__eglDisplay == EGL_NO_DISPLAY)
  199. {
  200. checkErrorEGL("eglGetDisplay");
  201. goto error;
  202. }
  203. if (eglInitialize(__eglDisplay, NULL, NULL) != EGL_TRUE)
  204. {
  205. checkErrorEGL("eglInitialize");
  206. goto error;
  207. }
  208. // Try both 24 and 16-bit depth sizes since some hardware (i.e. Tegra) does not support 24-bit depth
  209. bool validConfig = false;
  210. EGLint depthSizes[] = { 24, 16 };
  211. for (unsigned int i = 0; i < 2; ++i)
  212. {
  213. eglConfigAttrs[1] = samples > 0 ? 1 : 0;
  214. eglConfigAttrs[3] = samples;
  215. eglConfigAttrs[5] = depthSizes[i];
  216. if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
  217. {
  218. validConfig = true;
  219. break;
  220. }
  221. if (samples)
  222. {
  223. // Try lowering the MSAA sample size until we find a config
  224. int sampleCount = samples;
  225. while (sampleCount)
  226. {
  227. GP_WARN("No EGL config found for depth_size=%d and samples=%d. Trying samples=%d instead.", depthSizes[i], sampleCount, sampleCount / 2);
  228. sampleCount /= 2;
  229. eglConfigAttrs[1] = sampleCount > 0 ? 1 : 0;
  230. eglConfigAttrs[3] = sampleCount;
  231. if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
  232. {
  233. validConfig = true;
  234. break;
  235. }
  236. }
  237. __multiSampling = sampleCount > 0;
  238. if (validConfig)
  239. break;
  240. }
  241. else
  242. {
  243. GP_WARN("No EGL config found for depth_size=%d.", depthSizes[i]);
  244. }
  245. }
  246. if (!validConfig)
  247. {
  248. checkErrorEGL("eglChooseConfig");
  249. goto error;
  250. }
  251. __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
  252. if (__eglContext == EGL_NO_CONTEXT)
  253. {
  254. checkErrorEGL("eglCreateContext");
  255. goto error;
  256. }
  257. }
  258. // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
  259. // guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
  260. // As soon as we picked a EGLConfig, we can safely reconfigure the
  261. // ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
  262. EGLint format;
  263. eglGetConfigAttrib(__eglDisplay, __eglConfig, EGL_NATIVE_VISUAL_ID, &format);
  264. ANativeWindow_setBuffersGeometry(__state->window, 0, 0, format);
  265. __eglSurface = eglCreateWindowSurface(__eglDisplay, __eglConfig, __state->window, eglSurfaceAttrs);
  266. if (__eglSurface == EGL_NO_SURFACE)
  267. {
  268. checkErrorEGL("eglCreateWindowSurface");
  269. goto error;
  270. }
  271. if (eglMakeCurrent(__eglDisplay, __eglSurface, __eglSurface, __eglContext) != EGL_TRUE)
  272. {
  273. checkErrorEGL("eglMakeCurrent");
  274. goto error;
  275. }
  276. eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
  277. eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
  278. __orientationAngle = getRotation() * 90;
  279. // Set vsync.
  280. eglSwapInterval(__eglDisplay, WINDOW_VSYNC ? 1 : 0);
  281. // Initialize OpenGL ES extensions.
  282. __glExtensions = (const char*)glGetString(GL_EXTENSIONS);
  283. if (strstr(__glExtensions, "GL_OES_vertex_array_object") || strstr(__glExtensions, "GL_ARB_vertex_array_object"))
  284. {
  285. // Disable VAO extension for now.
  286. glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
  287. glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
  288. glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
  289. glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
  290. }
  291. return true;
  292. error:
  293. return false;
  294. }
  295. static void destroyEGLSurface()
  296. {
  297. if (__eglDisplay != EGL_NO_DISPLAY)
  298. {
  299. eglMakeCurrent(__eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  300. }
  301. if (__eglSurface != EGL_NO_SURFACE)
  302. {
  303. eglDestroySurface(__eglDisplay, __eglSurface);
  304. __eglSurface = EGL_NO_SURFACE;
  305. }
  306. }
  307. static void destroyEGLMain()
  308. {
  309. destroyEGLSurface();
  310. if (__eglContext != EGL_NO_CONTEXT)
  311. {
  312. eglDestroyContext(__eglDisplay, __eglContext);
  313. __eglContext = EGL_NO_CONTEXT;
  314. }
  315. if (__eglDisplay != EGL_NO_DISPLAY)
  316. {
  317. eglTerminate(__eglDisplay);
  318. __eglDisplay = EGL_NO_DISPLAY;
  319. }
  320. }
  321. // Display the android virtual keyboard.
  322. static void displayKeyboard(android_app* state, bool show)
  323. {
  324. // The following functions is supposed to show / hide functins from a native activity.. but currently do not work.
  325. // ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
  326. // ANativeActivity_hideSoftInput(state->activity, ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY);
  327. GP_ASSERT(state && state->activity && state->activity->vm);
  328. // Show or hide the keyboard by calling the appropriate Java method through JNI instead.
  329. jint flags = 0;
  330. JavaVM* jvm = state->activity->vm;
  331. JNIEnv* env = NULL;
  332. jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
  333. jint result = jvm->AttachCurrentThread(&env, NULL);
  334. if (result == JNI_ERR)
  335. {
  336. GP_ERROR("Failed to retrieve JVM environment to display keyboard.");
  337. return;
  338. }
  339. GP_ASSERT(env);
  340. // Retrieves NativeActivity.
  341. jobject lNativeActivity = state->activity->clazz;
  342. jclass ClassNativeActivity = env->GetObjectClass(lNativeActivity);
  343. // Retrieves Context.INPUT_METHOD_SERVICE.
  344. jclass ClassContext = env->FindClass("android/content/Context");
  345. jfieldID FieldINPUT_METHOD_SERVICE = env->GetStaticFieldID(ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
  346. jobject INPUT_METHOD_SERVICE = env->GetStaticObjectField(ClassContext, FieldINPUT_METHOD_SERVICE);
  347. // Runs getSystemService(Context.INPUT_METHOD_SERVICE).
  348. jclass ClassInputMethodManager = env->FindClass("android/view/inputmethod/InputMethodManager");
  349. jmethodID MethodGetSystemService = env->GetMethodID(ClassNativeActivity, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
  350. jobject lInputMethodManager = env->CallObjectMethod(lNativeActivity, MethodGetSystemService, INPUT_METHOD_SERVICE);
  351. // Runs getWindow().getDecorView().
  352. jmethodID MethodGetWindow = env->GetMethodID(ClassNativeActivity, "getWindow", "()Landroid/view/Window;");
  353. jobject lWindow = env->CallObjectMethod(lNativeActivity, MethodGetWindow);
  354. jclass ClassWindow = env->FindClass("android/view/Window");
  355. jmethodID MethodGetDecorView = env->GetMethodID(ClassWindow, "getDecorView", "()Landroid/view/View;");
  356. jobject lDecorView = env->CallObjectMethod(lWindow, MethodGetDecorView);
  357. if (show)
  358. {
  359. // Runs lInputMethodManager.showSoftInput(...).
  360. jmethodID MethodShowSoftInput = env->GetMethodID( ClassInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z");
  361. jboolean result = env->CallBooleanMethod(lInputMethodManager, MethodShowSoftInput, lDecorView, flags);
  362. }
  363. else
  364. {
  365. // Runs lWindow.getViewToken()
  366. jclass ClassView = env->FindClass("android/view/View");
  367. jmethodID MethodGetWindowToken = env->GetMethodID(ClassView, "getWindowToken", "()Landroid/os/IBinder;");
  368. jobject lBinder = env->CallObjectMethod(lDecorView, MethodGetWindowToken);
  369. // lInputMethodManager.hideSoftInput(...).
  370. jmethodID MethodHideSoftInput = env->GetMethodID(ClassInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
  371. jboolean lRes = env->CallBooleanMethod( lInputMethodManager, MethodHideSoftInput, lBinder, flags);
  372. }
  373. // Finished with the JVM.
  374. jvm->DetachCurrentThread();
  375. }
  376. // Gets the Keyboard::Key enumeration constant that corresponds to the given Android key code.
  377. static Keyboard::Key getKey(int keycode, int metastate)
  378. {
  379. bool shiftOn = (metastate == AMETA_SHIFT_ON);
  380. switch(keycode)
  381. {
  382. case AKEYCODE_HOME:
  383. return Keyboard::KEY_HOME;
  384. case AKEYCODE_0:
  385. return Keyboard::KEY_ZERO;
  386. case AKEYCODE_1:
  387. return Keyboard::KEY_ONE;
  388. case AKEYCODE_2:
  389. return Keyboard::KEY_TWO;
  390. case AKEYCODE_3:
  391. return Keyboard::KEY_THREE;
  392. case AKEYCODE_4:
  393. return Keyboard::KEY_FOUR;
  394. case AKEYCODE_5:
  395. return Keyboard::KEY_FIVE;
  396. case AKEYCODE_6:
  397. return Keyboard::KEY_SIX;
  398. case AKEYCODE_7:
  399. return Keyboard::KEY_SEVEN;
  400. case AKEYCODE_8:
  401. return Keyboard::KEY_EIGHT;
  402. case AKEYCODE_9:
  403. return Keyboard::KEY_NINE;
  404. case AKEYCODE_STAR:
  405. return Keyboard::KEY_ASTERISK;
  406. case AKEYCODE_POUND:
  407. return Keyboard::KEY_NUMBER;
  408. case AKEYCODE_DPAD_UP:
  409. return Keyboard::KEY_UP_ARROW;
  410. case AKEYCODE_DPAD_DOWN:
  411. return Keyboard::KEY_DOWN_ARROW;
  412. case AKEYCODE_DPAD_LEFT:
  413. return Keyboard::KEY_LEFT_ARROW;
  414. case AKEYCODE_DPAD_RIGHT:
  415. return Keyboard::KEY_RIGHT_ARROW;
  416. case AKEYCODE_A:
  417. return (shiftOn) ? Keyboard::KEY_CAPITAL_A : Keyboard::KEY_A;
  418. case AKEYCODE_B:
  419. return (shiftOn) ? Keyboard::KEY_CAPITAL_B : Keyboard::KEY_B;
  420. case AKEYCODE_C:
  421. return (shiftOn) ? Keyboard::KEY_CAPITAL_C : Keyboard::KEY_C;
  422. case AKEYCODE_D:
  423. return (shiftOn) ? Keyboard::KEY_CAPITAL_D : Keyboard::KEY_D;
  424. case AKEYCODE_E:
  425. return (shiftOn) ? Keyboard::KEY_CAPITAL_E : Keyboard::KEY_E;
  426. case AKEYCODE_F:
  427. return (shiftOn) ? Keyboard::KEY_CAPITAL_F : Keyboard::KEY_F;
  428. case AKEYCODE_G:
  429. return (shiftOn) ? Keyboard::KEY_CAPITAL_G : Keyboard::KEY_G;
  430. case AKEYCODE_H:
  431. return (shiftOn) ? Keyboard::KEY_CAPITAL_H : Keyboard::KEY_H;
  432. case AKEYCODE_I:
  433. return (shiftOn) ? Keyboard::KEY_CAPITAL_I : Keyboard::KEY_I;
  434. case AKEYCODE_J:
  435. return (shiftOn) ? Keyboard::KEY_CAPITAL_J : Keyboard::KEY_J;
  436. case AKEYCODE_K:
  437. return (shiftOn) ? Keyboard::KEY_CAPITAL_K : Keyboard::KEY_K;
  438. case AKEYCODE_L:
  439. return (shiftOn) ? Keyboard::KEY_CAPITAL_L : Keyboard::KEY_L;
  440. case AKEYCODE_M:
  441. return (shiftOn) ? Keyboard::KEY_CAPITAL_M : Keyboard::KEY_M;
  442. case AKEYCODE_N:
  443. return (shiftOn) ? Keyboard::KEY_CAPITAL_N : Keyboard::KEY_N;
  444. case AKEYCODE_O:
  445. return (shiftOn) ? Keyboard::KEY_CAPITAL_O : Keyboard::KEY_O;
  446. case AKEYCODE_P:
  447. return (shiftOn) ? Keyboard::KEY_CAPITAL_P : Keyboard::KEY_P;
  448. case AKEYCODE_Q:
  449. return (shiftOn) ? Keyboard::KEY_CAPITAL_Q : Keyboard::KEY_Q;
  450. case AKEYCODE_R:
  451. return (shiftOn) ? Keyboard::KEY_CAPITAL_R : Keyboard::KEY_R;
  452. case AKEYCODE_S:
  453. return (shiftOn) ? Keyboard::KEY_CAPITAL_S : Keyboard::KEY_S;
  454. case AKEYCODE_T:
  455. return (shiftOn) ? Keyboard::KEY_CAPITAL_T : Keyboard::KEY_T;
  456. case AKEYCODE_U:
  457. return (shiftOn) ? Keyboard::KEY_CAPITAL_U : Keyboard::KEY_U;
  458. case AKEYCODE_V:
  459. return (shiftOn) ? Keyboard::KEY_CAPITAL_V : Keyboard::KEY_V;
  460. case AKEYCODE_W:
  461. return (shiftOn) ? Keyboard::KEY_CAPITAL_W : Keyboard::KEY_W;
  462. case AKEYCODE_X:
  463. return (shiftOn) ? Keyboard::KEY_CAPITAL_X : Keyboard::KEY_X;
  464. case AKEYCODE_Y:
  465. return (shiftOn) ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
  466. case AKEYCODE_Z:
  467. return (shiftOn) ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
  468. case AKEYCODE_COMMA:
  469. return Keyboard::KEY_COMMA;
  470. case AKEYCODE_PERIOD:
  471. return Keyboard::KEY_PERIOD;
  472. case AKEYCODE_ALT_LEFT:
  473. case AKEYCODE_ALT_RIGHT:
  474. return Keyboard::KEY_ALT;
  475. case AKEYCODE_SHIFT_LEFT:
  476. case AKEYCODE_SHIFT_RIGHT:
  477. return Keyboard::KEY_SHIFT;
  478. case AKEYCODE_TAB:
  479. return Keyboard::KEY_TAB;
  480. case AKEYCODE_SPACE:
  481. return Keyboard::KEY_SPACE;
  482. case AKEYCODE_ENTER:
  483. return Keyboard::KEY_RETURN;
  484. case AKEYCODE_DEL:
  485. return Keyboard::KEY_BACKSPACE;
  486. case AKEYCODE_GRAVE:
  487. return Keyboard::KEY_GRAVE;
  488. case AKEYCODE_MINUS:
  489. return Keyboard::KEY_MINUS;
  490. case AKEYCODE_EQUALS:
  491. return Keyboard::KEY_EQUAL;
  492. case AKEYCODE_LEFT_BRACKET:
  493. return Keyboard::KEY_LEFT_BRACKET;
  494. case AKEYCODE_RIGHT_BRACKET:
  495. return Keyboard::KEY_RIGHT_BRACKET;
  496. case AKEYCODE_BACKSLASH:
  497. return Keyboard::KEY_BACK_SLASH;
  498. case AKEYCODE_SEMICOLON:
  499. return Keyboard::KEY_SEMICOLON;
  500. case AKEYCODE_APOSTROPHE:
  501. return Keyboard::KEY_APOSTROPHE;
  502. case AKEYCODE_SLASH:
  503. return Keyboard::KEY_SLASH;
  504. case AKEYCODE_AT:
  505. return Keyboard::KEY_AT;
  506. case AKEYCODE_PLUS:
  507. return Keyboard::KEY_PLUS;
  508. case AKEYCODE_PAGE_UP:
  509. return Keyboard::KEY_PG_UP;
  510. case AKEYCODE_PAGE_DOWN:
  511. return Keyboard::KEY_PG_DOWN;
  512. case AKEYCODE_MENU:
  513. return Keyboard::KEY_MENU;
  514. case AKEYCODE_SEARCH:
  515. return Keyboard::KEY_SEARCH;
  516. case AKEYCODE_BACK:
  517. return Keyboard::KEY_ESCAPE;
  518. default:
  519. return Keyboard::KEY_NONE;
  520. }
  521. }
  522. /**
  523. * Returns the unicode value for the given keycode or zero if the key is not a valid printable character.
  524. */
  525. static int getUnicode(int keycode, int metastate)
  526. {
  527. if (keycode == AKEYCODE_DEL)
  528. return 0x0008;
  529. // TODO: Doesn't support unicode currently.
  530. Keyboard::Key key = getKey(keycode, metastate);
  531. switch (key)
  532. {
  533. case Keyboard::KEY_BACKSPACE:
  534. return 0x0008;
  535. case Keyboard::KEY_TAB:
  536. return 0x0009;
  537. case Keyboard::KEY_RETURN:
  538. case Keyboard::KEY_KP_ENTER:
  539. return 0x000A;
  540. case Keyboard::KEY_ESCAPE:
  541. return 0x001B;
  542. case Keyboard::KEY_SPACE:
  543. case Keyboard::KEY_EXCLAM:
  544. case Keyboard::KEY_QUOTE:
  545. case Keyboard::KEY_NUMBER:
  546. case Keyboard::KEY_DOLLAR:
  547. case Keyboard::KEY_PERCENT:
  548. case Keyboard::KEY_CIRCUMFLEX:
  549. case Keyboard::KEY_AMPERSAND:
  550. case Keyboard::KEY_APOSTROPHE:
  551. case Keyboard::KEY_LEFT_PARENTHESIS:
  552. case Keyboard::KEY_RIGHT_PARENTHESIS:
  553. case Keyboard::KEY_ASTERISK:
  554. case Keyboard::KEY_PLUS:
  555. case Keyboard::KEY_COMMA:
  556. case Keyboard::KEY_MINUS:
  557. case Keyboard::KEY_PERIOD:
  558. case Keyboard::KEY_SLASH:
  559. case Keyboard::KEY_ZERO:
  560. case Keyboard::KEY_ONE:
  561. case Keyboard::KEY_TWO:
  562. case Keyboard::KEY_THREE:
  563. case Keyboard::KEY_FOUR:
  564. case Keyboard::KEY_FIVE:
  565. case Keyboard::KEY_SIX:
  566. case Keyboard::KEY_SEVEN:
  567. case Keyboard::KEY_EIGHT:
  568. case Keyboard::KEY_NINE:
  569. case Keyboard::KEY_COLON:
  570. case Keyboard::KEY_SEMICOLON:
  571. case Keyboard::KEY_LESS_THAN:
  572. case Keyboard::KEY_EQUAL:
  573. case Keyboard::KEY_GREATER_THAN:
  574. case Keyboard::KEY_QUESTION:
  575. case Keyboard::KEY_AT:
  576. case Keyboard::KEY_CAPITAL_A:
  577. case Keyboard::KEY_CAPITAL_B:
  578. case Keyboard::KEY_CAPITAL_C:
  579. case Keyboard::KEY_CAPITAL_D:
  580. case Keyboard::KEY_CAPITAL_E:
  581. case Keyboard::KEY_CAPITAL_F:
  582. case Keyboard::KEY_CAPITAL_G:
  583. case Keyboard::KEY_CAPITAL_H:
  584. case Keyboard::KEY_CAPITAL_I:
  585. case Keyboard::KEY_CAPITAL_J:
  586. case Keyboard::KEY_CAPITAL_K:
  587. case Keyboard::KEY_CAPITAL_L:
  588. case Keyboard::KEY_CAPITAL_M:
  589. case Keyboard::KEY_CAPITAL_N:
  590. case Keyboard::KEY_CAPITAL_O:
  591. case Keyboard::KEY_CAPITAL_P:
  592. case Keyboard::KEY_CAPITAL_Q:
  593. case Keyboard::KEY_CAPITAL_R:
  594. case Keyboard::KEY_CAPITAL_S:
  595. case Keyboard::KEY_CAPITAL_T:
  596. case Keyboard::KEY_CAPITAL_U:
  597. case Keyboard::KEY_CAPITAL_V:
  598. case Keyboard::KEY_CAPITAL_W:
  599. case Keyboard::KEY_CAPITAL_X:
  600. case Keyboard::KEY_CAPITAL_Y:
  601. case Keyboard::KEY_CAPITAL_Z:
  602. case Keyboard::KEY_LEFT_BRACKET:
  603. case Keyboard::KEY_BACK_SLASH:
  604. case Keyboard::KEY_RIGHT_BRACKET:
  605. case Keyboard::KEY_UNDERSCORE:
  606. case Keyboard::KEY_GRAVE:
  607. case Keyboard::KEY_A:
  608. case Keyboard::KEY_B:
  609. case Keyboard::KEY_C:
  610. case Keyboard::KEY_D:
  611. case Keyboard::KEY_E:
  612. case Keyboard::KEY_F:
  613. case Keyboard::KEY_G:
  614. case Keyboard::KEY_H:
  615. case Keyboard::KEY_I:
  616. case Keyboard::KEY_J:
  617. case Keyboard::KEY_K:
  618. case Keyboard::KEY_L:
  619. case Keyboard::KEY_M:
  620. case Keyboard::KEY_N:
  621. case Keyboard::KEY_O:
  622. case Keyboard::KEY_P:
  623. case Keyboard::KEY_Q:
  624. case Keyboard::KEY_R:
  625. case Keyboard::KEY_S:
  626. case Keyboard::KEY_T:
  627. case Keyboard::KEY_U:
  628. case Keyboard::KEY_V:
  629. case Keyboard::KEY_W:
  630. case Keyboard::KEY_X:
  631. case Keyboard::KEY_Y:
  632. case Keyboard::KEY_Z:
  633. case Keyboard::KEY_LEFT_BRACE:
  634. case Keyboard::KEY_BAR:
  635. case Keyboard::KEY_RIGHT_BRACE:
  636. case Keyboard::KEY_TILDE:
  637. return key;
  638. default:
  639. return 0;
  640. }
  641. }
  642. // Process the next input event.
  643. static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
  644. {
  645. if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
  646. {
  647. int32_t action = AMotionEvent_getAction(event);
  648. size_t pointerIndex;
  649. size_t pointerId;
  650. size_t pointerCount;
  651. int x;
  652. int y;
  653. switch (action & AMOTION_EVENT_ACTION_MASK)
  654. {
  655. case AMOTION_EVENT_ACTION_DOWN:
  656. {
  657. pointerId = AMotionEvent_getPointerId(event, 0);
  658. x = AMotionEvent_getX(event, 0);
  659. y = AMotionEvent_getY(event, 0);
  660. // Gesture handling
  661. if ( __gestureEventsProcessed.test(Gesture::GESTURE_TAP) ||
  662. __gestureEventsProcessed.test(Gesture::GESTURE_SWIPE) ||
  663. __gestureEventsProcessed.test(Gesture::GESTURE_DRAG) ||
  664. __gestureEventsProcessed.test(Gesture::GESTURE_DROP) ||
  665. __gestureEventsProcessed.test(Gesture::GESTURE_PINCH) ||
  666. __gestureEventsProcessed.test(Gesture::GESTURE_LONG_TAP))
  667. {
  668. __pointer0.pressed = true;
  669. __pointer0.time = Game::getInstance()->getAbsoluteTime();
  670. __pointer0.pointerId = pointerId;
  671. __pointer0.x = x;
  672. __pointer0.y = y;
  673. __gesturePointer0CurrentPosition = __gesturePointer0LastPosition = std::pair<int, int>(x, y);
  674. }
  675. // Primary pointer down.
  676. gameplay::Platform::touchEventInternal(Touch::TOUCH_PRESS, x, y, pointerId);
  677. __primaryTouchId = pointerId;
  678. }
  679. break;
  680. case AMOTION_EVENT_ACTION_UP:
  681. {
  682. pointerId = AMotionEvent_getPointerId(event, 0);
  683. x = AMotionEvent_getX(event, 0);
  684. y = AMotionEvent_getY(event, 0);
  685. // Gestures
  686. bool gestureDetected = false;
  687. if (__pointer0.pressed && __pointer0.pointerId == pointerId)
  688. {
  689. int deltaX = x - __pointer0.x;
  690. int deltaY = y - __pointer0.y;
  691. // Test for drop
  692. if (__gesturePinching)
  693. {
  694. __gesturePinching = false;
  695. gestureDetected = true;
  696. }
  697. else if (__gestureDraging)
  698. {
  699. if (__gestureEventsProcessed.test(Gesture::GESTURE_DROP))
  700. {
  701. gameplay::Platform::gestureDropEventInternal(x, y);
  702. gestureDetected = true;
  703. }
  704. __gestureDraging = false;
  705. }
  706. // Test for swipe
  707. else if (__gestureEventsProcessed.test(Gesture::GESTURE_SWIPE) &&
  708. gameplay::Game::getInstance()->getAbsoluteTime() - __pointer0.time < GESTURE_SWIPE_DURATION_MAX &&
  709. (abs(deltaX) > GESTURE_SWIPE_DISTANCE_MIN || abs(deltaY) > GESTURE_SWIPE_DISTANCE_MIN) )
  710. {
  711. int direction = 0;
  712. if ( abs(deltaX) > abs(deltaY) )
  713. {
  714. if (deltaX > 0)
  715. direction = gameplay::Gesture::SWIPE_DIRECTION_RIGHT;
  716. else if (deltaX < 0)
  717. direction = gameplay::Gesture::SWIPE_DIRECTION_LEFT;
  718. }
  719. else
  720. {
  721. if (deltaY > 0)
  722. direction = gameplay::Gesture::SWIPE_DIRECTION_DOWN;
  723. else if (deltaY < 0)
  724. direction = gameplay::Gesture::SWIPE_DIRECTION_UP;
  725. }
  726. gameplay::Platform::gestureSwipeEventInternal(x, y, direction);
  727. gestureDetected = true;
  728. }
  729. // Test for tap
  730. else if(__gestureEventsProcessed.test(Gesture::GESTURE_TAP) &&
  731. gameplay::Game::getInstance()->getAbsoluteTime() - __pointer0.time < GESTURE_TAP_DURATION_MAX)
  732. {
  733. gameplay::Platform::gestureTapEventInternal(x, y);
  734. gestureDetected = true;
  735. }
  736. // Test for long tap
  737. else if(__gestureEventsProcessed.test(Gesture::GESTURE_LONG_TAP) &&
  738. gameplay::Game::getInstance()->getAbsoluteTime() - __pointer0.time >= GESTURE_LONG_TAP_DURATION_MIN)
  739. {
  740. gameplay::Platform::gestureLongTapEventInternal(x, y, gameplay::Game::getInstance()->getAbsoluteTime() - __pointer0.time);
  741. gestureDetected = true;
  742. }
  743. }
  744. __pointer0.pressed = false;
  745. if (!gestureDetected && (__multiTouch || __primaryTouchId == pointerId) )
  746. {
  747. gameplay::Platform::touchEventInternal(Touch::TOUCH_RELEASE, x, y, pointerId);
  748. }
  749. __primaryTouchId = -1;
  750. }
  751. break;
  752. case AMOTION_EVENT_ACTION_POINTER_DOWN:
  753. {
  754. pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
  755. pointerId = AMotionEvent_getPointerId(event, pointerIndex);
  756. x = AMotionEvent_getX(event, pointerIndex);
  757. y = AMotionEvent_getY(event, pointerIndex);
  758. // Gesture handling
  759. if ( __gestureEventsProcessed.test(Gesture::GESTURE_TAP) ||
  760. __gestureEventsProcessed.test(Gesture::GESTURE_SWIPE) ||
  761. __gestureEventsProcessed.test(Gesture::GESTURE_DRAG) ||
  762. __gestureEventsProcessed.test(Gesture::GESTURE_DROP) ||
  763. __gestureEventsProcessed.test(Gesture::GESTURE_PINCH) ||
  764. __gestureEventsProcessed.test(Gesture::GESTURE_LONG_TAP))
  765. {
  766. __pointer1.pressed = true;
  767. __pointer1.time = Game::getInstance()->getAbsoluteTime();
  768. __pointer1.pointerId = pointerId;
  769. __pointer1.x = x;
  770. __pointer1.y = y;
  771. __gesturePointer1CurrentPosition = __gesturePointer1LastPosition = std::pair<int, int>(x, y);
  772. }
  773. // Non-primary pointer down.
  774. if (__multiTouch)
  775. {
  776. gameplay::Platform::touchEventInternal(Touch::TOUCH_PRESS, AMotionEvent_getX(event, pointerIndex), AMotionEvent_getY(event, pointerIndex), pointerId);
  777. }
  778. }
  779. break;
  780. case AMOTION_EVENT_ACTION_POINTER_UP:
  781. {
  782. pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
  783. pointerId = AMotionEvent_getPointerId(event, pointerIndex);
  784. x = AMotionEvent_getX(event, pointerIndex);
  785. y = AMotionEvent_getY(event, pointerIndex);
  786. bool gestureDetected = false;
  787. if (__pointer1.pressed && __pointer1.pointerId == pointerId)
  788. {
  789. int deltaX = x - __pointer1.x;
  790. int deltaY = y - __pointer1.y;
  791. if (__gesturePinching)
  792. {
  793. __gesturePinching = false;
  794. gestureDetected = true;
  795. }
  796. // Test for swipe
  797. else if (__gestureEventsProcessed.test(Gesture::GESTURE_SWIPE) &&
  798. gameplay::Game::getInstance()->getAbsoluteTime() - __pointer1.time < GESTURE_SWIPE_DURATION_MAX &&
  799. (abs(deltaX) > GESTURE_SWIPE_DISTANCE_MIN || abs(deltaY) > GESTURE_SWIPE_DISTANCE_MIN) )
  800. {
  801. int direction = 0;
  802. if (deltaX > 0)
  803. direction |= gameplay::Gesture::SWIPE_DIRECTION_RIGHT;
  804. else if (deltaX < 0)
  805. direction |= gameplay::Gesture::SWIPE_DIRECTION_LEFT;
  806. if (deltaY > 0)
  807. direction |= gameplay::Gesture::SWIPE_DIRECTION_DOWN;
  808. else if (deltaY < 0)
  809. direction |= gameplay::Gesture::SWIPE_DIRECTION_UP;
  810. gameplay::Platform::gestureSwipeEventInternal(x, y, direction);
  811. gestureDetected = true;
  812. }
  813. else if(__gestureEventsProcessed.test(Gesture::GESTURE_TAP) &&
  814. gameplay::Game::getInstance()->getAbsoluteTime() - __pointer1.time < GESTURE_TAP_DURATION_MAX)
  815. {
  816. gameplay::Platform::gestureTapEventInternal(x, y);
  817. gestureDetected = true;
  818. }
  819. else if(__gestureEventsProcessed.test(Gesture::GESTURE_LONG_TAP) &&
  820. gameplay::Game::getInstance()->getAbsoluteTime() - __pointer1.time >= GESTURE_LONG_TAP_DURATION_MIN)
  821. {
  822. gameplay::Platform::gestureLongTapEventInternal(x, y, gameplay::Game::getInstance()->getAbsoluteTime() - __pointer1.time);
  823. gestureDetected = true;
  824. }
  825. }
  826. __pointer1.pressed = false;
  827. if (!gestureDetected && (__multiTouch || __primaryTouchId == pointerId) )
  828. {
  829. gameplay::Platform::touchEventInternal(Touch::TOUCH_RELEASE, AMotionEvent_getX(event, pointerIndex), AMotionEvent_getY(event, pointerIndex), pointerId);
  830. }
  831. if (__primaryTouchId == pointerId)
  832. __primaryTouchId = -1;
  833. }
  834. break;
  835. case AMOTION_EVENT_ACTION_MOVE:
  836. {
  837. // ACTION_MOVE events are batched, unlike the other events.
  838. pointerCount = AMotionEvent_getPointerCount(event);
  839. for (size_t i = 0; i < pointerCount; ++i)
  840. {
  841. pointerId = AMotionEvent_getPointerId(event, i);
  842. x = AMotionEvent_getX(event, i);
  843. y = AMotionEvent_getY(event, i);
  844. bool gestureDetected = false;
  845. if (__pointer0.pressed)
  846. {
  847. //The two pointers are pressed and the event was done by one of it
  848. if (__pointer1.pressed && (pointerId == __pointer0.pointerId || pointerId == __pointer1.pointerId))
  849. {
  850. if (__pointer0.pointerId == __pointer1.pointerId)
  851. {
  852. __gesturePinching = false;
  853. break;
  854. }
  855. //Test for pinch
  856. if (__gestureEventsProcessed.test(Gesture::GESTURE_PINCH))
  857. {
  858. int pointer0Distance, pointer1Distance;
  859. if (__pointer0.pointerId == pointerId)
  860. {
  861. __gesturePointer0LastPosition = __gesturePointer0CurrentPosition;
  862. __gesturePointer0CurrentPosition = std::pair<int, int>(x, y);
  863. __gesturePointer0Delta = sqrt(pow(static_cast<float>(x - __pointer0.x), 2) +
  864. pow(static_cast<float>(y - __pointer0.y), 2));
  865. }
  866. else
  867. {
  868. __gesturePointer1LastPosition = __gesturePointer1CurrentPosition;
  869. __gesturePointer1CurrentPosition = std::pair<int, int>(x, y);
  870. __gesturePointer1Delta = sqrt(pow(static_cast<float>(x - __pointer1.x), 2) +
  871. pow(static_cast<float>(y - __pointer1.y), 2));
  872. }
  873. if (!__gesturePinching &&
  874. __gesturePointer0Delta >= GESTURE_PINCH_DISTANCE_MIN &&
  875. __gesturePointer1Delta >= GESTURE_PINCH_DISTANCE_MIN)
  876. {
  877. __gesturePinching = true;
  878. __gesturePinchCentroid = std::pair<int, int>((__pointer0.x + __pointer1.x) / 2,
  879. (__pointer0.y + __pointer1.y) / 2);
  880. }
  881. if (__gesturePinching)
  882. {
  883. int currentDistancePointer0, currentDistancePointer1;
  884. int lastDistancePointer0, lastDistancePointer1;
  885. float scale;
  886. currentDistancePointer0 = sqrt(pow(static_cast<float>(__gesturePinchCentroid.first - __gesturePointer0CurrentPosition.first), 2) + pow(static_cast<float>(__gesturePinchCentroid.second - __gesturePointer0CurrentPosition.second), 2));
  887. lastDistancePointer0 = sqrt(pow(static_cast<float>(__gesturePinchCentroid.first - __gesturePointer0LastPosition.first), 2) + pow(static_cast<float>(__gesturePinchCentroid.second - __gesturePointer0LastPosition.second), 2));
  888. currentDistancePointer1 = sqrt(pow(static_cast<float>(__gesturePinchCentroid.first - __gesturePointer1CurrentPosition.first), 2) + pow(static_cast<float>(__gesturePinchCentroid.second - __gesturePointer1CurrentPosition.second), 2));
  889. lastDistancePointer1 = sqrt(pow(static_cast<float>(__gesturePinchCentroid.first - __gesturePointer1LastPosition.first), 2) + pow(static_cast<float>(__gesturePinchCentroid.second - __gesturePointer1LastPosition.second), 2));
  890. if (pointerId == __pointer0.pointerId)
  891. scale = ((float) currentDistancePointer0) / ((float) lastDistancePointer0);
  892. else
  893. scale = ((float) currentDistancePointer1) / ((float) lastDistancePointer1);
  894. if (((currentDistancePointer0 >= lastDistancePointer0) && (currentDistancePointer1 >= lastDistancePointer1)) ||
  895. ((currentDistancePointer0 <= lastDistancePointer0) && (currentDistancePointer1 <= lastDistancePointer1)))
  896. {
  897. gameplay::Platform::gesturePinchEventInternal(__gesturePinchCentroid.first, __gesturePinchCentroid.second, scale);
  898. gestureDetected = true;
  899. }
  900. else
  901. __gesturePinching = false;
  902. }
  903. }
  904. }
  905. //Only the primary pointer is done and the event was done by it
  906. else if (!gestureDetected && pointerId == __pointer0.pointerId)
  907. {
  908. //Test for drag
  909. if (__gestureEventsProcessed.test(Gesture::GESTURE_DRAG))
  910. {
  911. int delta = sqrt(pow(static_cast<float>(x - __pointer0.x), 2) +
  912. pow(static_cast<float>(y - __pointer0.y), 2));
  913. if ((__gestureDraging || __gestureEventsProcessed.test(Gesture::GESTURE_DRAG)) &&
  914. (gameplay::Game::getInstance()->getAbsoluteTime() - __pointer0.time >= GESTURE_DRAG_START_DURATION_MIN) &&
  915. (delta >= GESTURE_DRAG_DISTANCE_MIN))
  916. {
  917. gameplay::Platform::gestureDragEventInternal(x, y);
  918. __gestureDraging = true;
  919. gestureDetected = true;
  920. }
  921. }
  922. }
  923. }
  924. if (!gestureDetected && (__multiTouch || __primaryTouchId == pointerId))
  925. {
  926. gameplay::Platform::touchEventInternal(Touch::TOUCH_MOVE, AMotionEvent_getX(event, i), AMotionEvent_getY(event, i), pointerId);
  927. }
  928. }
  929. }
  930. break;
  931. }
  932. return 1;
  933. }
  934. else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
  935. {
  936. int32_t action = AKeyEvent_getAction(event);
  937. int32_t keycode = AKeyEvent_getKeyCode(event);
  938. int32_t metastate = AKeyEvent_getMetaState(event);
  939. //Don't consume volume up/down events.
  940. if (keycode == AKEYCODE_VOLUME_DOWN || keycode == AKEYCODE_VOLUME_UP)
  941. return 0;
  942. switch(action)
  943. {
  944. case AKEY_EVENT_ACTION_DOWN:
  945. gameplay::Platform::keyEventInternal(Keyboard::KEY_PRESS, getKey(keycode, metastate));
  946. if (int character = getUnicode(keycode, metastate))
  947. gameplay::Platform::keyEventInternal(Keyboard::KEY_CHAR, character);
  948. break;
  949. case AKEY_EVENT_ACTION_UP:
  950. gameplay::Platform::keyEventInternal(Keyboard::KEY_RELEASE, getKey(keycode, metastate));
  951. break;
  952. }
  953. return 1;
  954. }
  955. return 0;
  956. }
  957. // Process the next main command.
  958. static void engine_handle_cmd(struct android_app* app, int32_t cmd)
  959. {
  960. switch (cmd)
  961. {
  962. case APP_CMD_INIT_WINDOW:
  963. // The window is being shown, get it ready.
  964. if (app->window != NULL)
  965. {
  966. initEGL();
  967. __initialized = true;
  968. }
  969. break;
  970. case APP_CMD_TERM_WINDOW:
  971. destroyEGLSurface();
  972. __initialized = false;
  973. break;
  974. case APP_CMD_DESTROY:
  975. Game::getInstance()->exit();
  976. destroyEGLMain();
  977. __initialized = false;
  978. break;
  979. case APP_CMD_GAINED_FOCUS:
  980. // When our app gains focus, we start monitoring the sensors.
  981. if (__accelerometerSensor != NULL)
  982. {
  983. ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
  984. // We'd like to get 60 events per second (in microseconds).
  985. ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
  986. }
  987. if (__gyroscopeSensor != NULL)
  988. {
  989. ASensorEventQueue_enableSensor(__sensorEventQueue, __gyroscopeSensor);
  990. // We'd like to get 60 events per second (in microseconds).
  991. ASensorEventQueue_setEventRate(__sensorEventQueue, __gyroscopeSensor, (1000L/60)*1000);
  992. }
  993. if (Game::getInstance()->getState() == Game::UNINITIALIZED)
  994. {
  995. Game::getInstance()->run();
  996. }
  997. else
  998. {
  999. Game::getInstance()->resume();
  1000. }
  1001. break;
  1002. case APP_CMD_RESUME:
  1003. if (__initialized)
  1004. {
  1005. Game::getInstance()->resume();
  1006. }
  1007. __suspended = false;
  1008. break;
  1009. case APP_CMD_PAUSE:
  1010. Game::getInstance()->pause();
  1011. __suspended = true;
  1012. break;
  1013. case APP_CMD_LOST_FOCUS:
  1014. // When our app loses focus, we stop monitoring the sensors.
  1015. // This is to avoid consuming battery while not being used.
  1016. if (__accelerometerSensor != NULL)
  1017. {
  1018. ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
  1019. }
  1020. if (__gyroscopeSensor != NULL)
  1021. {
  1022. ASensorEventQueue_disableSensor(__sensorEventQueue, __gyroscopeSensor);
  1023. }
  1024. break;
  1025. }
  1026. }
  1027. Platform::Platform(Game* game)
  1028. : _game(game)
  1029. {
  1030. }
  1031. Platform::~Platform()
  1032. {
  1033. }
  1034. Platform* Platform::create(Game* game)
  1035. {
  1036. Platform* platform = new Platform(game);
  1037. return platform;
  1038. }
  1039. int Platform::enterMessagePump()
  1040. {
  1041. GP_ASSERT(__state && __state->activity && __state->activity->vm);
  1042. __initialized = false;
  1043. __suspended = false;
  1044. // Get the android application's activity.
  1045. ANativeActivity* activity = __state->activity;
  1046. JavaVM* jvm = __state->activity->vm;
  1047. JNIEnv* env = NULL;
  1048. jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
  1049. jint res = jvm->AttachCurrentThread(&env, NULL);
  1050. if (res == JNI_ERR)
  1051. {
  1052. GP_ERROR("Failed to retrieve JVM environment when entering message pump.");
  1053. return -1;
  1054. }
  1055. GP_ASSERT(env);
  1056. /* Get external files directory on Android; this will result in a directory where all app files
  1057. * should be stored, like /mnt/sdcard/android/<package-name>/files/
  1058. */
  1059. jboolean isCopy;
  1060. jclass clazz = env->GetObjectClass(activity->clazz);
  1061. jmethodID methodGetExternalStorage = env->GetMethodID(clazz, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
  1062. jclass clazzFile = env->FindClass("java/io/File");
  1063. jmethodID methodGetPath = env->GetMethodID(clazzFile, "getPath", "()Ljava/lang/String;");
  1064. // Now has java.io.File object pointing to directory
  1065. jobject objectFile = env->CallObjectMethod(activity->clazz, methodGetExternalStorage, NULL);
  1066. // Now has String object containing path to directory
  1067. jstring stringExternalPath = static_cast<jstring>(env->CallObjectMethod(objectFile, methodGetPath));
  1068. const char* externalPath = env->GetStringUTFChars(stringExternalPath, &isCopy);
  1069. // Set the default path to store the resources.
  1070. std::string assetsPath(externalPath);
  1071. if (externalPath[strlen(externalPath)-1] != '/')
  1072. assetsPath += "/";
  1073. FileSystem::setResourcePath(assetsPath.c_str());
  1074. // Release string data
  1075. env->ReleaseStringUTFChars(stringExternalPath, externalPath);
  1076. jvm->DetachCurrentThread();
  1077. // Get the asset manager to get the resources from the .apk file.
  1078. __assetManager = activity->assetManager;
  1079. // Set the event call back functions.
  1080. __state->onAppCmd = engine_handle_cmd;
  1081. __state->onInputEvent = engine_handle_input;
  1082. // Prepare to monitor accelerometer.
  1083. __sensorManager = ASensorManager_getInstance();
  1084. __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
  1085. __gyroscopeSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_GYROSCOPE);
  1086. __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
  1087. // Get the initial time.
  1088. clock_gettime(CLOCK_REALTIME, &__timespec);
  1089. __timeStart = timespec2millis(&__timespec);
  1090. __timeAbsolute = 0L;
  1091. while (true)
  1092. {
  1093. // Read all pending events.
  1094. int ident;
  1095. int events;
  1096. struct android_poll_source* source;
  1097. while ((ident=ALooper_pollAll(!__suspended ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
  1098. {
  1099. // Process this event.
  1100. if (source != NULL)
  1101. source->process(__state, source);
  1102. // If a sensor has data, process it now.
  1103. if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
  1104. {
  1105. ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
  1106. if (__sensorEvent.type == ASENSOR_TYPE_ACCELEROMETER)
  1107. {
  1108. __accelRawX = __sensorEvent.acceleration.x;
  1109. __accelRawY = __sensorEvent.acceleration.y;
  1110. __accelRawZ = __sensorEvent.acceleration.z;
  1111. }
  1112. else if (__sensorEvent.type == ASENSOR_TYPE_GYROSCOPE)
  1113. {
  1114. __gyroRawX = __sensorEvent.vector.x;
  1115. __gyroRawY = __sensorEvent.vector.y;
  1116. __gyroRawZ = __sensorEvent.vector.z;
  1117. }
  1118. }
  1119. if (__state->destroyRequested != 0)
  1120. {
  1121. return 0;
  1122. }
  1123. }
  1124. // Idle time (no events left to process) is spent rendering.
  1125. // We skip rendering when the app is paused.
  1126. if (__initialized && !__suspended)
  1127. {
  1128. _game->frame();
  1129. // Post the new frame to the display.
  1130. // Note that there are a couple cases where eglSwapBuffers could fail
  1131. // with an error code that requires a certain level of re-initialization:
  1132. //
  1133. // 1) EGL_BAD_NATIVE_WINDOW - Called when the surface we're currently using
  1134. // is invalidated. This would require us to destroy our EGL surface,
  1135. // close our OpenKODE window, and start again.
  1136. //
  1137. // 2) EGL_CONTEXT_LOST - Power management event that led to our EGL context
  1138. // being lost. Requires us to re-create and re-initalize our EGL context
  1139. // and all OpenGL ES state.
  1140. //
  1141. // For now, if we get these, we'll simply exit.
  1142. int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
  1143. if (rc != EGL_TRUE)
  1144. {
  1145. EGLint error = eglGetError();
  1146. if (error == EGL_BAD_NATIVE_WINDOW)
  1147. {
  1148. if (__state->window != NULL)
  1149. {
  1150. destroyEGLSurface();
  1151. initEGL();
  1152. }
  1153. __initialized = true;
  1154. }
  1155. else
  1156. {
  1157. perror("eglSwapBuffers");
  1158. break;
  1159. }
  1160. }
  1161. }
  1162. // Display the keyboard.
  1163. gameplay::displayKeyboard(__state, __displayKeyboard);
  1164. }
  1165. return 0;
  1166. }
  1167. void Platform::signalShutdown()
  1168. {
  1169. // nothing to do
  1170. }
  1171. bool Platform::canExit()
  1172. {
  1173. return true;
  1174. }
  1175. unsigned int Platform::getDisplayWidth()
  1176. {
  1177. return __width;
  1178. }
  1179. unsigned int Platform::getDisplayHeight()
  1180. {
  1181. return __height;
  1182. }
  1183. double Platform::getAbsoluteTime()
  1184. {
  1185. clock_gettime(CLOCK_REALTIME, &__timespec);
  1186. double now = timespec2millis(&__timespec);
  1187. __timeAbsolute = now - __timeStart;
  1188. return __timeAbsolute;
  1189. }
  1190. void Platform::setAbsoluteTime(double time)
  1191. {
  1192. __timeAbsolute = time;
  1193. }
  1194. bool Platform::isVsync()
  1195. {
  1196. return __vsync;
  1197. }
  1198. void Platform::setVsync(bool enable)
  1199. {
  1200. eglSwapInterval(__eglDisplay, enable ? 1 : 0);
  1201. __vsync = enable;
  1202. }
  1203. void Platform::swapBuffers()
  1204. {
  1205. if (__eglDisplay && __eglSurface)
  1206. eglSwapBuffers(__eglDisplay, __eglSurface);
  1207. }
  1208. void Platform::sleep(long ms)
  1209. {
  1210. usleep(ms * 1000);
  1211. }
  1212. void Platform::setMultiSampling(bool enabled)
  1213. {
  1214. if (enabled == __multiSampling)
  1215. {
  1216. return;
  1217. }
  1218. // TODO
  1219. __multiSampling = enabled;
  1220. }
  1221. bool Platform::isMultiSampling()
  1222. {
  1223. return __multiSampling;
  1224. }
  1225. void Platform::setMultiTouch(bool enabled)
  1226. {
  1227. __multiTouch = enabled;
  1228. }
  1229. bool Platform::isMultiTouch()
  1230. {
  1231. return __multiTouch;
  1232. }
  1233. bool Platform::hasAccelerometer()
  1234. {
  1235. return true;
  1236. }
  1237. void Platform::getAccelerometerValues(float* pitch, float* roll)
  1238. {
  1239. double tx, ty, tz;
  1240. ASensorEvent event;
  1241. // By default, android accelerometer values are oriented to the portrait mode.
  1242. // flipping the x and y to get the desired landscape mode values.
  1243. switch (__orientationAngle)
  1244. {
  1245. case 90:
  1246. tx = -__accelRawY;
  1247. ty = __accelRawX;
  1248. break;
  1249. case 180:
  1250. tx = -__accelRawX;
  1251. ty = -__accelRawY;
  1252. break;
  1253. case 270:
  1254. tx = __accelRawY;
  1255. ty = -__accelRawX;
  1256. break;
  1257. default:
  1258. tx = __accelRawX;
  1259. ty = __accelRawY;
  1260. break;
  1261. }
  1262. tz = __accelRawZ;
  1263. if (pitch != NULL)
  1264. {
  1265. GP_ASSERT(tx * tx + tz * tz);
  1266. *pitch = -atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
  1267. }
  1268. if (roll != NULL)
  1269. {
  1270. GP_ASSERT(ty * ty + tz * tz);
  1271. *roll = -atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
  1272. }
  1273. }
  1274. void Platform::getSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
  1275. {
  1276. if (accelX)
  1277. {
  1278. *accelX = __accelRawX;
  1279. }
  1280. if (accelY)
  1281. {
  1282. *accelY = __accelRawY;
  1283. }
  1284. if (accelZ)
  1285. {
  1286. *accelZ = __accelRawZ;
  1287. }
  1288. if (gyroX)
  1289. {
  1290. *gyroX = __gyroRawX;
  1291. }
  1292. if (gyroY)
  1293. {
  1294. *gyroY = __gyroRawY;
  1295. }
  1296. if (gyroZ)
  1297. {
  1298. *gyroZ = __gyroRawZ;
  1299. }
  1300. }
  1301. void Platform::getArguments(int* argc, char*** argv)
  1302. {
  1303. if (argc)
  1304. *argc = 0;
  1305. if (argv)
  1306. *argv = 0;
  1307. }
  1308. bool Platform::hasMouse()
  1309. {
  1310. // not
  1311. return false;
  1312. }
  1313. void Platform::setMouseCaptured(bool captured)
  1314. {
  1315. // not
  1316. }
  1317. bool Platform::isMouseCaptured()
  1318. {
  1319. // not
  1320. return false;
  1321. }
  1322. void Platform::setCursorVisible(bool visible)
  1323. {
  1324. // not
  1325. }
  1326. bool Platform::isCursorVisible()
  1327. {
  1328. // not
  1329. return false;
  1330. }
  1331. void Platform::displayKeyboard(bool display)
  1332. {
  1333. if (display)
  1334. __displayKeyboard = true;
  1335. else
  1336. __displayKeyboard = false;
  1337. }
  1338. void Platform::shutdownInternal()
  1339. {
  1340. Game::getInstance()->shutdown();
  1341. }
  1342. bool Platform::isGestureSupported(Gesture::GestureEvent evt)
  1343. {
  1344. // Pinch currently not implemented
  1345. return evt == gameplay::Gesture::GESTURE_SWIPE || evt == gameplay::Gesture::GESTURE_TAP || evt == gameplay::Gesture::GESTURE_LONG_TAP ||
  1346. evt == gameplay::Gesture::GESTURE_DRAG || evt == gameplay::Gesture::GESTURE_DROP || evt == gameplay::Gesture::GESTURE_PINCH;
  1347. }
  1348. void Platform::registerGesture(Gesture::GestureEvent evt)
  1349. {
  1350. switch(evt)
  1351. {
  1352. case Gesture::GESTURE_ANY_SUPPORTED:
  1353. __gestureEventsProcessed.set();
  1354. break;
  1355. case Gesture::GESTURE_TAP:
  1356. case Gesture::GESTURE_SWIPE:
  1357. case Gesture::GESTURE_LONG_TAP:
  1358. case Gesture::GESTURE_DRAG:
  1359. case Gesture::GESTURE_DROP:
  1360. case Gesture::GESTURE_PINCH:
  1361. __gestureEventsProcessed.set(evt);
  1362. break;
  1363. default:
  1364. break;
  1365. }
  1366. }
  1367. void Platform::unregisterGesture(Gesture::GestureEvent evt)
  1368. {
  1369. switch(evt)
  1370. {
  1371. case Gesture::GESTURE_ANY_SUPPORTED:
  1372. __gestureEventsProcessed.reset();
  1373. break;
  1374. case Gesture::GESTURE_TAP:
  1375. case Gesture::GESTURE_SWIPE:
  1376. case Gesture::GESTURE_LONG_TAP:
  1377. case Gesture::GESTURE_DRAG:
  1378. case Gesture::GESTURE_DROP:
  1379. __gestureEventsProcessed.set(evt, 0);
  1380. break;
  1381. default:
  1382. break;
  1383. }
  1384. }
  1385. bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
  1386. {
  1387. return __gestureEventsProcessed.test(evt);
  1388. }
  1389. void Platform::pollGamepadState(Gamepad* gamepad)
  1390. {
  1391. }
  1392. bool Platform::launchURL(const char *url)
  1393. {
  1394. if (url == NULL || *url == '\0')
  1395. return false;
  1396. bool result = true;
  1397. android_app* state = __state;
  1398. GP_ASSERT(state && state->activity && state->activity->vm);
  1399. JavaVM* jvm = state->activity->vm;
  1400. JNIEnv* env = NULL;
  1401. jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
  1402. jint r = jvm->AttachCurrentThread(&env, NULL);
  1403. if (r == JNI_ERR)
  1404. {
  1405. GP_ERROR("Failed to retrieve JVM environment to display keyboard.");
  1406. return false;
  1407. }
  1408. GP_ASSERT(env);
  1409. jclass classActivity = env->FindClass("android/app/NativeActivity");
  1410. jclass classIntent = env->FindClass("android/content/Intent");
  1411. jclass classUri = env->FindClass("android/net/Uri");
  1412. GP_ASSERT(classActivity && classIntent && classUri);
  1413. // Get static field ID Intent.ACTION_VIEW
  1414. jfieldID fieldActionView = env->GetStaticFieldID(classIntent, "ACTION_VIEW", "Ljava/lang/String;");
  1415. GP_ASSERT(fieldActionView);
  1416. // Get string value of Intent.ACTION_VIEW, we'll need that to pass to Intent's constructor later on
  1417. jstring paramActionView = (jstring)env->GetStaticObjectField(classIntent, fieldActionView);
  1418. GP_ASSERT(paramActionView);
  1419. // Get method ID Uri.parse, will be needed to parse the url given into Uri object
  1420. jmethodID methodUriParse = env->GetStaticMethodID(classUri, "parse","(Ljava/lang/String;)Landroid/net/Uri;");
  1421. GP_ASSERT(methodUriParse);
  1422. // Get method ID Activity.startActivity, so we can start the appropriate activity for the View action of our Uri
  1423. jmethodID methodActivityStartActivity = env->GetMethodID(classActivity, "startActivity","(Landroid/content/Intent;)V");
  1424. GP_ASSERT(methodActivityStartActivity);
  1425. // Get method ID Intent constructor, the one that takes action and uri (String;Uri)
  1426. jmethodID methodIntentInit = env->GetMethodID(classIntent, "<init>","(Ljava/lang/String;Landroid/net/Uri;)V");
  1427. GP_ASSERT(methodIntentInit);
  1428. // Convert our url to Java's string and parse it to Uri
  1429. jstring paramUrlString = env->NewStringUTF(url);
  1430. jobject paramUri = env->CallStaticObjectMethod(classUri, methodUriParse, paramUrlString);
  1431. GP_ASSERT(paramUri);
  1432. // Create Intent with Intent.ACTION_VIEW and parsed Uri arguments
  1433. jobject paramIntent = env->NewObject(classIntent, methodIntentInit, paramActionView, paramUri);
  1434. GP_ASSERT(paramIntent);
  1435. // Launch NativeActivity.startActivity with our intent to view the url! state->activity->clazz holds
  1436. // our NativeActivity object
  1437. env->CallVoidMethod(state->activity->clazz, methodActivityStartActivity, paramIntent);
  1438. /* startActivity may throw a ActivitNotFoundException if, well, activity is not found.
  1439. Example: http://<url> is passed to the intent but there is no browser installed in the system
  1440. we need to handle it. */
  1441. jobject exception = env->ExceptionOccurred();
  1442. // We're not lucky here
  1443. if (exception)
  1444. {
  1445. // Print out the exception data to logcat
  1446. env->ExceptionDescribe();
  1447. // Exception needs to be cleared
  1448. env->ExceptionClear();
  1449. // Launching the url failed
  1450. result = false;
  1451. }
  1452. // See you Space Cowboy
  1453. jvm->DetachCurrentThread();
  1454. return result;
  1455. }
  1456. std::string Platform::displayFileDialog(size_t mode, const char* title, const char* filterDescription, const char* filterExtensions, const char* initialDirectory)
  1457. {
  1458. return "";
  1459. }
  1460. }
  1461. #endif