/src/compiler/android-ndk/jni/ftkapp/ftk_jni.cpp
C++ | 544 lines | 460 code | 79 blank | 5 comment | 46 complexity | d0c540bef07ba948e8e7c812377a3b93 MD5 | raw file
1 2#include <jni.h> 3#include <android/log.h> 4#include <unistd.h> 5#include "ftk.h" 6#include "ftk_jni.h" 7#include "ftk_log.h" 8#include "ftk_key.h" 9#include "ftk_event.h" 10#include "ftk_globals.h" 11#include "ftk_display.h" 12#include "ftk_display_rotate.h" 13 14typedef struct _FtkJni 15{ 16 JNIEnv* env; 17 18 jclass activity; 19 jmethodID get_asset_file_descriptor; 20 jmethodID decode_image; 21 jmethodID init_egl; 22 jmethodID create_egl_surface; 23 jmethodID destroy_egl_surface; 24 jmethodID flip_egl; 25 jmethodID draw_bitmap; 26 jmethodID show_keyboard; 27 jmethodID hide_keyboard; 28 jmethodID show_input_method_picker; 29 30 jmethodID get_file_descriptor; 31 jmethodID get_start_offset; 32 jmethodID get_length; 33 jmethodID close_file_descriptor; 34 35 jfieldID descriptor; 36 37 jmethodID get_pixels; 38 jmethodID get_width; 39 jmethodID get_height; 40 41 jintArray pixels; 42 43 int render_enabled; 44 int surface_valid; 45 FtkEvent event; 46}FtkJni; 47 48FtkJni jni; 49 50#if 0 51FTK_KEY_EXCLAM 52FTK_KEY_QUOTEDBL 53FTK_KEY_NUMBERSIGN 54FTK_KEY_DOLLAR 55FTK_KEY_PERCENT 56FTK_KEY_AMPERSAND 57FTK_KEY_QUOTERIGHT 58FTK_KEY_PARENLEFT 59FTK_KEY_PARENRIGHT 60FTK_KEY_ASTERISK 61FTK_KEY_COLON 62FTK_KEY_LESS 63FTK_KEY_GREATER 64FTK_KEY_QUESTION 65FTK_KEY_ASCIICIRCUM 66FTK_KEY_UNDERSCORE 67FTK_KEY_QUOTELEFT 68FTK_KEY_LEFTBRACE 69FTK_KEY_OR 70FTK_KEY_RIGHTBRACE 71FTK_KEY_NOT 72FTK_KEY_DOT 73FTK_KEY_HOME 74FTK_KEY_PRIOR 75FTK_KEY_NEXT 76FTK_KEY_END 77FTK_KEY_BEGIN 78FTK_KEY_INSERT 79FTK_KEY_ESC 80FTK_KEY_RIGHTCTRL 81FTK_KEY_LEFTCTRL 82FTK_KEY_CAPSLOCK 83FTK_KEY_SEND 84FTK_KEY_REPLY 85FTK_KEY_SAVE 86FTK_KEY_BATTERY 87FTK_KEY_BLUETOOTH 88FTK_KEY_WLAN 89FTK_KEY_DELETE 90#endif 91 92static const int key_maps[] = 93{ 94 /*KeyCodeUnknown[0] = */0, 95 /*KeyCodeSoftLeft[1] = */0, 96 /*KeyCodeSoftRight[2] = */0, 97 /*KeyCodeHome[3] = */0, 98 /*KeyCodeBack[4] = */0,//FTK_KEY_RETURN, 99 /*KeyCodeCall[5] = */0, 100 /*KeyCodeEndCall[6] = */0, 101 /*KeyCode0[7] = */FTK_KEY_0, 102 /*KeyCode1[8] = */FTK_KEY_1, 103 /*KeyCode2[9] = */FTK_KEY_2, 104 /*KeyCode3[10] = */FTK_KEY_3, 105 /*KeyCode4[11] = */FTK_KEY_4, 106 /*KeyCode5[12] = */FTK_KEY_5, 107 /*KeyCode6[13] = */FTK_KEY_6, 108 /*KeyCode7[14] = */FTK_KEY_7, 109 /*KeyCode8[15] = */FTK_KEY_8, 110 /*KeyCode9[16] = */FTK_KEY_9, 111 /*KeyCodeStar[17] = */0, 112 /*KeyCodePound[18] = */0, 113 /*KeyCodeDpadUp[19] = */FTK_KEY_UP, 114 /*KeyCodeDpadDown[20] = */FTK_KEY_DOWN, 115 /*KeyCodeDpadLeft[21] = */FTK_KEY_LEFT, 116 /*KeyCodeDpadRight[22] = */FTK_KEY_RIGHT, 117 /*KeyCodeDpadCenter[23] = */0, 118 /*KeyCodeVolumeUp[24] = */0, 119 /*KeyCodeVolumeDown[25] = */0, 120 /*KeyCodePower[26] = */FTK_KEY_POWER, 121 /*KeyCodeCamera[27] = */0, 122 /*KeyCodeClear[28] = */0, 123 /*KeyCodeA[29] = */FTK_KEY_A, 124 /*KeyCodeB[30] = */FTK_KEY_B, 125 /*KeyCodeC[31] = */FTK_KEY_C, 126 /*KeyCodeD[32] = */FTK_KEY_D, 127 /*KeyCodeE[33] = */FTK_KEY_E, 128 /*KeyCodeF[34] = */FTK_KEY_F, 129 /*KeyCodeG[35] = */FTK_KEY_G, 130 /*KeyCodeH[36] = */FTK_KEY_H, 131 /*KeyCodeI[37] = */FTK_KEY_I, 132 /*KeyCodeJ[38] = */FTK_KEY_J, 133 /*KeyCodeK[39] = */FTK_KEY_K, 134 /*KeyCodeL[40] = */FTK_KEY_L, 135 /*KeyCodeM[41] = */FTK_KEY_M, 136 /*KeyCodeN[42] = */FTK_KEY_N, 137 /*KeyCodeO[43] = */FTK_KEY_O, 138 /*KeyCodeP[44] = */FTK_KEY_P, 139 /*KeyCodeQ[45] = */FTK_KEY_Q, 140 /*KeyCodeR[46] = */FTK_KEY_R, 141 /*KeyCodeS[47] = */FTK_KEY_S, 142 /*KeyCodeT[48] = */FTK_KEY_T, 143 /*KeyCodeU[49] = */FTK_KEY_U, 144 /*KeyCodeV[50] = */FTK_KEY_V, 145 /*KeyCodeW[51] = */FTK_KEY_W, 146 /*KeyCodeX[52] = */FTK_KEY_X, 147 /*KeyCodeY[53] = */FTK_KEY_Y, 148 /*KeyCodeZ[54] = */FTK_KEY_Z, 149 /*KeyCodeComma[55] = */FTK_KEY_COMMA, 150 /*KeyCodePeriod[56] = */FTK_KEY_PERIOD, 151 /*KeyCodeAltLeft[57] = */FTK_KEY_LEFTALT, 152 /*KeyCodeAltRight[58] = */FTK_KEY_RIGHTALT, 153 /*KeyCodeShiftLeft[59] = */FTK_KEY_LEFTSHIFT, 154 /*KeyCodeShiftRight[60] = */FTK_KEY_RIGHTSHIFT, 155 /*KeyCodeTab[61] = */FTK_KEY_TAB, 156 /*KeyCodeSpace[62] = */FTK_KEY_SPACE, 157 /*KeyCodeSym[63] = */0, 158 /*KeyCodeExplorer[64] = */0, 159 /*KeyCodeEnvelope[65] = */0, 160 /*KeyCodeNewline[66] = */0, 161 /*KeyCodeDel[67] = */FTK_KEY_BACKSPACE, 162 /*KeyCodeGrave[68] = */FTK_KEY_GRAVE, 163 /*KeyCodeMinus[69] = */FTK_KEY_MINUS, 164 /*KeyCodeEquals[70] = */FTK_KEY_EQUAL, 165 /*KeyCodeLeftBracket[71] = */FTK_KEY_BRACKETLEFT, 166 /*KeyCodeRightBracket[72] = */FTK_KEY_BRACKETRIGHT, 167 /*KeyCodeBackslash[73] = */FTK_KEY_BACKSLASH, 168 /*KeyCodeSemicolon[74] = */FTK_KEY_SEMICOLON, 169 /*KeyCodeApostrophe[75] = */FTK_KEY_APOSTROPHE, 170 /*KeyCodeSlash[76] = */FTK_KEY_SLASH, 171 /*KeyCodeAt[77] = */FTK_KEY_AT, 172 /*KeyCodeNum[78] = */0, 173 /*KeyCodeHeadSetHook[79] = */0, 174 /*KeyCodeFocus[80] = */0, 175 /*KeyCodePlus[81] = */FTK_KEY_PLUS, 176 /*KeyCodeMenu[82] = */FTK_KEY_MENU, 177 /*KeyCodeNotification[83] = */0, 178 /*KeyCodeSearch[84] = */0, 179 /*KeyCodePlayPause[85] = */0, 180 /*KeyCodeStop[86] = */0, 181 /*KeyCodeNextSong[87] = */0, 182 /*KeyCodePreviousSong[88] = */0, 183 /*KeyCodeRewind[89] = */0, 184 /*KeyCodeForward[90] = */0, 185 /*KeyCodeMute[91] = */0, 186 /*KeyCodePageUp[92] = */FTK_KEY_PAGEUP, 187 /*KeyCodePageDown[93] = */FTK_KEY_PAGEDOWN, 188 /*KeyCodePictSymbols[94] = */0, 189 /*KeyCodeSwitchCharset[95] = */0 190}; 191 192/******************************************************************************/ 193 194extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) 195{ 196 JNIEnv* env = NULL; 197 198 ftk_logd("JNI: OnLoad()"); 199 200 if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) 201 { 202 return -1; 203 } 204 205 jni.env = env; 206 207 jclass cls = jni.env->FindClass("org/libftk/app/FtkActivity"); 208 jni.activity = (jclass)jni.env->NewGlobalRef(cls); 209 210 jni.get_asset_file_descriptor = jni.env->GetStaticMethodID(cls, "getAssetFileDescriptor", 211 "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); 212 jni.decode_image = jni.env->GetStaticMethodID(cls, "decodeImage", "(Ljava/lang/String;)Landroid/graphics/Bitmap;"); 213 214 jni.init_egl = jni.env->GetStaticMethodID(cls, "initEGL", "()V"); 215 jni.create_egl_surface = jni.env->GetStaticMethodID(cls, "createEGLSurface", "()V"); 216 jni.destroy_egl_surface = jni.env->GetStaticMethodID(cls, "destroyEGLSurface", "()V"); 217 jni.flip_egl = jni.env->GetStaticMethodID(cls, "flipEGL", "()V"); 218 jni.draw_bitmap = jni.env->GetStaticMethodID(cls, "drawBitmap", "([IIIIIII)V"); 219 220 jni.show_keyboard = jni.env->GetStaticMethodID(cls, "showKeyboard", "()V"); 221 jni.hide_keyboard = jni.env->GetStaticMethodID(cls, "hideKeyboard", "()V"); 222 jni.show_input_method_picker = jni.env->GetStaticMethodID(cls, "showInputMethodPicker", "()V"); 223 224 cls = jni.env->FindClass("android/content/res/AssetFileDescriptor"); 225 jni.get_file_descriptor = jni.env->GetMethodID(cls, "getFileDescriptor", "()Ljava/io/FileDescriptor;"); 226 jni.get_start_offset = jni.env->GetMethodID(cls, "getStartOffset", "()J"); 227 jni.get_length = jni.env->GetMethodID(cls, "getLength", "()J"); 228 jni.close_file_descriptor = jni.env->GetMethodID(cls, "close", "()V"); 229 230 cls = jni.env->FindClass("java/io/FileDescriptor"); 231 jni.descriptor = jni.env->GetFieldID(cls, "descriptor", "I"); 232 233 cls = jni.env->FindClass("android/graphics/Bitmap"); 234 jni.get_pixels = jni.env->GetMethodID(cls, "getPixels", "([IIIIIII)V"); 235 jni.get_width = jni.env->GetMethodID(cls, "getWidth", "()I"); 236 jni.get_height = jni.env->GetMethodID(cls, "getHeight", "()I"); 237 238 if(!jni.get_asset_file_descriptor || !jni.decode_image 239 || !jni.init_egl || !jni.create_egl_surface || !jni.destroy_egl_surface || !jni.flip_egl || !jni.draw_bitmap 240 || !jni.show_keyboard || !jni.hide_keyboard || !jni.show_input_method_picker 241 || !jni.get_file_descriptor || !jni.get_start_offset || !jni.get_length || !jni.close_file_descriptor 242 || !jni.descriptor 243 || !jni.get_pixels || !jni.get_width || !jni.get_height) 244 { 245 ftk_logd("null method or field id"); 246 return -1; 247 } 248 249 return JNI_VERSION_1_4; 250} 251 252extern "C" void Java_org_libftk_app_FtkActivity_nativeInit(JNIEnv* env, jobject obj) 253{ 254 int argc, rv; 255 char* argv[2]; 256 257 ftk_logd("native init"); 258 259 jni.env = env; 260 261 argv[0] = (char *) "ftk"; 262 argv[1] = NULL; 263 argc = 1; 264 rv = FTK_MAIN(argc, argv); 265 266 env->DeleteGlobalRef(jni.pixels); 267 env->DeleteGlobalRef(jni.activity); 268} 269 270extern "C" void Java_org_libftk_app_FtkActivity_nativeQuit(JNIEnv* env, jobject obj) 271{ 272 FTK_QUIT(); 273 ftk_logd("native quit"); 274} 275 276extern "C" void Java_org_libftk_app_FtkActivity_nativeEnableRender(JNIEnv* env, jobject obj) 277{ 278 jni.render_enabled = 1; 279} 280 281extern "C" void Java_org_libftk_app_FtkActivity_nativeDisableRender(JNIEnv* env, jobject obj) 282{ 283 jni.render_enabled = 0; 284 jni.surface_valid = 0; 285} 286 287extern "C" void Java_org_libftk_app_FtkActivity_onNativeKey(JNIEnv* env, jobject obj, jint action, jint keyCode) 288{ 289 ftk_logd("native key action:%d keyCode:%d", action, keyCode); 290 291 if(action == 2) 292 { 293 return; 294 } 295 jni.event.type = action == 0 ? FTK_EVT_KEY_DOWN : FTK_EVT_KEY_UP; 296 jni.event.u.key.code = key_maps[keyCode]; 297 ftk_wnd_manager_queue_event_auto_rotate(ftk_default_wnd_manager(), &jni.event); 298} 299 300extern "C" void Java_org_libftk_app_FtkActivity_onNativeCommitText(JNIEnv* env, jobject obj, jstring text, jint newCursorPosition) 301{ 302 char* buf; 303 jsize len; 304 const char *str; 305 306 len = env->GetStringUTFLength(text); 307 str = env->GetStringUTFChars(text, NULL); 308 buf = (char*)FTK_ALLOC(len + 1); 309 memcpy(buf, str, len); 310 buf[len] = '\0'; 311 env->ReleaseStringUTFChars(text, str); 312 313 memset(&jni.event, 0, sizeof(FtkEvent)); 314 jni.event.u.extra = buf; 315 jni.event.type = FTK_EVT_OS_IM_COMMIT; 316 ftk_wnd_manager_queue_event_auto_rotate(ftk_default_wnd_manager(), &jni.event); 317} 318 319extern "C" void Java_org_libftk_app_FtkActivity_onNativeTouch(JNIEnv* env, jobject obj, jint action, jfloat x, jfloat y, jfloat p) 320{ 321 ftk_logd("native touch event %d @ %f/%f, pressure %f", action, x, y, p); 322 memset(&jni.event, 0, sizeof(FtkEvent)); 323 if(action==0) 324 { 325 jni.event.type = FTK_EVT_MOUSE_DOWN; 326 } 327 else if(action == 1 || action == 3) 328 { 329 jni.event.type = FTK_EVT_MOUSE_UP; 330 } 331 else if(action == 2) 332 { 333 jni.event.type = FTK_EVT_MOUSE_MOVE; 334 } 335 else 336 { 337 return; 338 } 339 jni.event.u.mouse.x = x; 340 jni.event.u.mouse.y = y; 341 ftk_wnd_manager_queue_event_auto_rotate(ftk_default_wnd_manager(), &jni.event); 342} 343 344extern "C" void Java_org_libftk_app_FtkActivity_nativeSetScreenSize(JNIEnv* env, jobject obj, jint width, jint height) 345{ 346 ftk_logd("nativeSetScreenSize() %dX%d", width, height); 347 Android_SetScreenResolution(width, height); 348 349 jintArray temp = (jintArray)env->NewIntArray(width * height); 350 jni.pixels = (jintArray)env->NewGlobalRef(temp); 351 env->DeleteLocalRef(temp); 352} 353 354extern "C" void Java_org_libftk_app_FtkActivity_onNativeResize(JNIEnv* env, jobject obj, jint width, jint height, jint format) 355{ 356 int w, h; 357 FtkDisplay* display = NULL; 358 FtkRotate r = FTK_ROTATE_0; 359 360 display = ftk_default_display(); 361 r = ftk_display_get_rotate(display); 362 w = ftk_display_width(display); 363 h = ftk_display_height(display); 364 365 ftk_logd("onNativeResize() old size:%dX%d new size:%dX%d format:%d", w, h, width, height, format); 366 367 if(width != w && height != h) 368 { 369 memset(&jni.event, 0, sizeof(FtkEvent)); 370 if(r == FTK_ROTATE_0) 371 { 372 jni.event.u.extra = (void*)FTK_ROTATE_90; 373 } 374 else 375 { 376 jni.event.u.extra = (void*)FTK_ROTATE_0; 377 } 378 jni.event.type = FTK_EVT_OS_SCREEN_ROTATED; 379 //ftk_wnd_manager_queue_event_auto_rotate(ftk_default_wnd_manager(), &jni.event); 380 } 381 382 memset(&jni.event, 0, sizeof(FtkEvent)); 383 jni.event.type = FTK_EVT_RELAYOUT_WND; 384 ftk_wnd_manager_queue_event_auto_rotate(ftk_default_wnd_manager(), &jni.event); 385} 386 387/******************************************************************************/ 388 389void Android_Log(const char* fmt, ...) 390{ 391 va_list ap; 392 va_start(ap, fmt); 393 __android_log_vprint(ANDROID_LOG_INFO, "FTK", fmt, ap); 394 va_end(ap); 395} 396 397int Android_OpenAsset(const char* filename, size_t* size) 398{ 399 int fd; 400 jlong asset_offset, asset_size; 401 jstring file; 402 jobject asset_fd, descriptor; 403 404 //ftk_logd("%s", filename); 405 406 file = jni.env->NewStringUTF(filename); 407 asset_fd = jni.env->CallStaticObjectMethod(jni.activity, jni.get_asset_file_descriptor, file); 408 jni.env->DeleteLocalRef(file); 409 410 descriptor = jni.env->CallObjectMethod(asset_fd, jni.get_file_descriptor); 411 asset_offset = jni.env->CallLongMethod(asset_fd, jni.get_start_offset); 412 asset_size = jni.env->CallLongMethod(asset_fd, jni.get_length); 413 414 ftk_logd("%s %d", filename, (int)asset_size); 415 416 fd = dup(jni.env->GetIntField(descriptor, jni.descriptor)); 417 418 jni.env->CallVoidMethod(asset_fd, jni.close_file_descriptor); 419 jni.env->DeleteLocalRef(descriptor); 420 jni.env->DeleteLocalRef(asset_fd); 421 422 lseek(fd, (int)asset_offset, SEEK_SET); 423 424 *size = asset_size; 425 426 return fd; 427} 428 429FtkBitmap* Android_LoadImage(const char* filename) 430{ 431 jint width, height; 432 jint* pixels; 433 jstring file; 434 jobject image; 435 jintArray temp; 436 FtkBitmap* bitmap; 437 FtkColor bg = {0}; 438 FtkColor* dst; 439 440 //ftk_logd("%s", filename); 441 442 file = jni.env->NewStringUTF(filename); 443 image = jni.env->CallStaticObjectMethod(jni.activity, jni.decode_image, file); 444 jni.env->DeleteLocalRef(file); 445 446 if(image == NULL) 447 { 448 return NULL; 449 } 450 451 width = jni.env->CallIntMethod(image, jni.get_width); 452 height = jni.env->CallIntMethod(image, jni.get_height); 453 454 ftk_logd("%s: %dX%d", filename, width, height); 455 456 temp = jni.env->NewIntArray(width * height); 457 jni.env->CallVoidMethod(image, jni.get_pixels, temp, 0, width, 0, 0, width, height); 458 pixels = jni.env->GetIntArrayElements(temp, NULL); 459 460 bg.a = 0xff; 461 bitmap = ftk_bitmap_create(width, height, bg); 462 dst = ftk_bitmap_lock(bitmap); 463 464 memcpy(dst, pixels, sizeof(FtkColor) * width * height); 465 466 jni.env->ReleaseIntArrayElements(temp, pixels, 0); 467 jni.env->DeleteLocalRef(temp); 468 jni.env->DeleteLocalRef(image); 469 470 return bitmap; 471} 472 473void Android_InitEGL() 474{ 475 ftk_logd("Android_InitEGL()"); 476 jni.env->CallStaticVoidMethod(jni.activity, jni.init_egl); 477} 478 479Ret Android_PreRender() 480{ 481 if(!jni.render_enabled) 482 { 483 if(jni.surface_valid) 484 { 485 jni.env->CallStaticVoidMethod(jni.activity, jni.destroy_egl_surface); 486 } 487 return RET_FAIL; 488 } 489 if(!jni.surface_valid) 490 { 491 jni.env->CallStaticVoidMethod(jni.activity, jni.create_egl_surface); 492 jni.surface_valid = 1; 493 } 494 return RET_OK; 495} 496 497void Android_Render() 498{ 499 if(!jni.render_enabled || !jni.surface_valid) 500 { 501 return; 502 } 503 jni.env->CallStaticVoidMethod(jni.activity, jni.flip_egl); 504} 505 506int* Android_GetBitmapPixels() 507{ 508 return (int*)jni.env->GetIntArrayElements(jni.pixels, NULL); 509} 510 511void Android_ReleaseBitmapPixels(int* pixels) 512{ 513 jni.env->ReleaseIntArrayElements(jni.pixels, pixels, 0); 514} 515 516void Android_DrawBitmap(int offset, int stride, int x, int y, int width, int height) 517{ 518 if(!jni.render_enabled) 519 { 520 return; 521 } 522 523 jintArray temp = (jintArray)jni.env->NewLocalRef(jni.pixels); 524 jni.env->CallStaticVoidMethod(jni.activity, jni.draw_bitmap, temp, offset, stride, x, y, width, height); 525 jni.env->DeleteLocalRef(temp); // TODO: xxx 526} 527 528void Android_ShowKeyboard() 529{ 530 ftk_logd("Android_ShowKeyboard()"); 531 jni.env->CallStaticVoidMethod(jni.activity, jni.show_keyboard); 532} 533 534void Android_HideKeyboard() 535{ 536 ftk_logd("Android_HideKeyboard()"); 537 jni.env->CallStaticVoidMethod(jni.activity, jni.hide_keyboard); 538} 539 540void Android_ShowInputMethodChooser() 541{ 542 ftk_logd("Android_ShowInputMethodChooser()"); 543 jni.env->CallStaticVoidMethod(jni.activity, jni.show_input_method_picker); 544}