507 audioBufferPinned = NULL; |
507 audioBufferPinned = NULL; |
508 } |
508 } |
509 } |
509 } |
510 |
510 |
511 // Test for an exception and call SDL_SetError with its detail if one occurs |
511 // Test for an exception and call SDL_SetError with its detail if one occurs |
512 static bool Android_JNI_ExceptionOccurred() |
512 // If optional parameter silent is truthy then SDL_SetError() is not called. |
|
513 static bool Android_JNI_ExceptionOccurred(bool silent = false) |
513 { |
514 { |
514 SDL_assert(LocalReferenceHolder::IsActive()); |
515 SDL_assert(LocalReferenceHolder::IsActive()); |
515 JNIEnv *mEnv = Android_JNI_GetEnv(); |
516 JNIEnv *mEnv = Android_JNI_GetEnv(); |
516 |
517 |
517 jthrowable exception = mEnv->ExceptionOccurred(); |
518 jthrowable exception = mEnv->ExceptionOccurred(); |
519 jmethodID mid; |
520 jmethodID mid; |
520 |
521 |
521 // Until this happens most JNI operations have undefined behaviour |
522 // Until this happens most JNI operations have undefined behaviour |
522 mEnv->ExceptionClear(); |
523 mEnv->ExceptionClear(); |
523 |
524 |
524 jclass exceptionClass = mEnv->GetObjectClass(exception); |
525 if (!silent) { |
525 jclass classClass = mEnv->FindClass("java/lang/Class"); |
526 jclass exceptionClass = mEnv->GetObjectClass(exception); |
526 |
527 jclass classClass = mEnv->FindClass("java/lang/Class"); |
527 mid = mEnv->GetMethodID(classClass, "getName", "()Ljava/lang/String;"); |
528 |
528 jstring exceptionName = (jstring)mEnv->CallObjectMethod(exceptionClass, mid); |
529 mid = mEnv->GetMethodID(classClass, "getName", "()Ljava/lang/String;"); |
529 const char* exceptionNameUTF8 = mEnv->GetStringUTFChars(exceptionName, 0); |
530 jstring exceptionName = (jstring)mEnv->CallObjectMethod(exceptionClass, mid); |
530 |
531 const char* exceptionNameUTF8 = mEnv->GetStringUTFChars(exceptionName, 0); |
531 mid = mEnv->GetMethodID(exceptionClass, "getMessage", "()Ljava/lang/String;"); |
532 |
532 jstring exceptionMessage = (jstring)mEnv->CallObjectMethod(exception, mid); |
533 mid = mEnv->GetMethodID(exceptionClass, "getMessage", "()Ljava/lang/String;"); |
533 |
534 jstring exceptionMessage = (jstring)mEnv->CallObjectMethod(exception, mid); |
534 if (exceptionMessage != NULL) { |
535 |
535 const char* exceptionMessageUTF8 = mEnv->GetStringUTFChars( |
536 if (exceptionMessage != NULL) { |
536 exceptionMessage, 0); |
537 const char* exceptionMessageUTF8 = mEnv->GetStringUTFChars(exceptionMessage, 0); |
537 SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8); |
538 SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8); |
538 mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8); |
539 mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8); |
539 } else { |
540 } else { |
540 SDL_SetError("%s", exceptionNameUTF8); |
541 SDL_SetError("%s", exceptionNameUTF8); |
541 } |
542 } |
542 |
543 |
543 mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8); |
544 mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8); |
|
545 } |
544 |
546 |
545 return true; |
547 return true; |
546 } |
548 } |
547 |
549 |
548 return false; |
550 return false; |
586 /* First let's try opening the file to obtain an AssetFileDescriptor. |
588 /* First let's try opening the file to obtain an AssetFileDescriptor. |
587 * This method reads the files directly from the APKs using standard *nix calls |
589 * This method reads the files directly from the APKs using standard *nix calls |
588 */ |
590 */ |
589 mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager), "openFd", "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); |
591 mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager), "openFd", "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); |
590 inputStream = mEnv->CallObjectMethod(assetManager, mid, fileNameJString); |
592 inputStream = mEnv->CallObjectMethod(assetManager, mid, fileNameJString); |
591 if (Android_JNI_ExceptionOccurred()) { |
593 if (Android_JNI_ExceptionOccurred(true)) { |
592 goto fallback; |
594 goto fallback; |
593 } |
595 } |
594 |
596 |
595 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "getStartOffset", "()J"); |
597 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "getStartOffset", "()J"); |
596 ctx->hidden.androidio.offset = mEnv->CallLongMethod(inputStream, mid); |
598 ctx->hidden.androidio.offset = mEnv->CallLongMethod(inputStream, mid); |
597 if (Android_JNI_ExceptionOccurred()) { |
599 if (Android_JNI_ExceptionOccurred(true)) { |
598 goto fallback; |
600 goto fallback; |
599 } |
601 } |
600 |
602 |
601 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "getDeclaredLength", "()J"); |
603 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "getDeclaredLength", "()J"); |
602 ctx->hidden.androidio.size = mEnv->CallLongMethod(inputStream, mid); |
604 ctx->hidden.androidio.size = mEnv->CallLongMethod(inputStream, mid); |
603 if (Android_JNI_ExceptionOccurred()) { |
605 if (Android_JNI_ExceptionOccurred(true)) { |
604 goto fallback; |
606 goto fallback; |
605 } |
607 } |
606 |
608 |
607 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "getFileDescriptor", "()Ljava/io/FileDescriptor;"); |
609 mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "getFileDescriptor", "()Ljava/io/FileDescriptor;"); |
608 fd = mEnv->CallObjectMethod(inputStream, mid); |
610 fd = mEnv->CallObjectMethod(inputStream, mid); |