| /* |
| * Copyright 2013 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 <EGL/egl.h> |
| #include <GLES2/gl2.h> |
| #include <fstream> |
| #include <iostream> |
| |
| #include "JNIHelper.h" |
| |
| namespace ndk_helper |
| { |
| |
| #define CLASS_NAME "android/app/NativeActivity" |
| |
| //--------------------------------------------------------------------------- |
| //JNI Helper functions |
| //--------------------------------------------------------------------------- |
| |
| //--------------------------------------------------------------------------- |
| //Singleton |
| //--------------------------------------------------------------------------- |
| JNIHelper* JNIHelper::GetInstance() |
| { |
| static JNIHelper helper; |
| return &helper; |
| } |
| |
| //--------------------------------------------------------------------------- |
| //Ctor |
| //--------------------------------------------------------------------------- |
| JNIHelper::JNIHelper() |
| { |
| pthread_mutex_init( &mutex_, NULL ); |
| } |
| |
| //--------------------------------------------------------------------------- |
| //Dtor |
| //--------------------------------------------------------------------------- |
| JNIHelper::~JNIHelper() |
| { |
| pthread_mutex_lock( &mutex_ ); |
| |
| JNIEnv *env; |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| env->DeleteGlobalRef( jni_helper_java_ref_ ); |
| env->DeleteGlobalRef( jni_helper_java_class_ ); |
| |
| activity_->vm->DetachCurrentThread(); |
| |
| pthread_mutex_destroy( &mutex_ ); |
| } |
| |
| //--------------------------------------------------------------------------- |
| //Init |
| //--------------------------------------------------------------------------- |
| void JNIHelper::Init( ANativeActivity* activity, |
| const char* helper_class_name ) |
| { |
| JNIHelper& helper = *GetInstance(); |
| pthread_mutex_lock( &helper.mutex_ ); |
| |
| helper.activity_ = activity; |
| |
| JNIEnv *env; |
| helper.activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| //Retrieve app name |
| jclass android_content_Context = env->GetObjectClass( helper.activity_->clazz ); |
| jmethodID midGetPackageName = env->GetMethodID( android_content_Context, "getPackageName", |
| "()Ljava/lang/String;" ); |
| |
| jstring packageName = (jstring) env->CallObjectMethod( helper.activity_->clazz, |
| midGetPackageName ); |
| const char* appname = env->GetStringUTFChars( packageName, NULL ); |
| helper.app_name_ = std::string( appname ); |
| |
| jclass cls = helper.RetrieveClass( env, helper_class_name ); |
| helper.jni_helper_java_class_ = (jclass) env->NewGlobalRef( cls ); |
| |
| jmethodID constructor = env->GetMethodID( helper.jni_helper_java_class_, "<init>", "()V" ); |
| helper.jni_helper_java_ref_ = env->NewObject( helper.jni_helper_java_class_, constructor ); |
| helper.jni_helper_java_ref_ = env->NewGlobalRef( helper.jni_helper_java_ref_ ); |
| |
| env->ReleaseStringUTFChars( packageName, appname ); |
| helper.activity_->vm->DetachCurrentThread(); |
| |
| pthread_mutex_unlock( &helper.mutex_ ); |
| } |
| |
| //--------------------------------------------------------------------------- |
| //readFile |
| //--------------------------------------------------------------------------- |
| bool JNIHelper::ReadFile( const char* fileName, |
| std::vector<uint8_t>* buffer_ref ) |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized.Call init() to initialize the helper" ); |
| return false; |
| } |
| |
| //First, try reading from externalFileDir; |
| JNIEnv *env; |
| jmethodID mid; |
| |
| pthread_mutex_lock( &mutex_ ); |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| jstring str_path = GetExternalFilesDirJString( env ); |
| const char* path = env->GetStringUTFChars( str_path, NULL ); |
| std::string s( path ); |
| |
| if( fileName[0] != '/' ) |
| { |
| s.append( "/" ); |
| } |
| s.append( fileName ); |
| std::ifstream f( s.c_str(), std::ios::binary ); |
| |
| env->ReleaseStringUTFChars( str_path, path ); |
| env->DeleteLocalRef( str_path ); |
| activity_->vm->DetachCurrentThread(); |
| |
| if( f ) |
| { |
| LOGI( "reading:%s", s.c_str() ); |
| f.seekg( 0, std::ifstream::end ); |
| int32_t fileSize = f.tellg(); |
| f.seekg( 0, std::ifstream::beg ); |
| buffer_ref->reserve( fileSize ); |
| buffer_ref->assign( std::istreambuf_iterator<char>( f ), std::istreambuf_iterator<char>() ); |
| f.close(); |
| pthread_mutex_unlock( &mutex_ ); |
| return true; |
| } |
| else |
| { |
| //Fallback to assetManager |
| AAssetManager* assetManager = activity_->assetManager; |
| AAsset* assetFile = AAssetManager_open( assetManager, fileName, AASSET_MODE_BUFFER ); |
| if( !assetFile ) |
| { |
| pthread_mutex_unlock( &mutex_ ); |
| return false; |
| } |
| uint8_t* data = (uint8_t*) AAsset_getBuffer( assetFile ); |
| int32_t size = AAsset_getLength( assetFile ); |
| if( data == NULL ) |
| { |
| AAsset_close( assetFile ); |
| |
| LOGI( "Failed to load:%s", fileName ); |
| pthread_mutex_unlock( &mutex_ ); |
| return false; |
| } |
| |
| buffer_ref->reserve( size ); |
| buffer_ref->assign( data, data + size ); |
| |
| AAsset_close( assetFile ); |
| pthread_mutex_unlock( &mutex_ ); |
| return true; |
| } |
| } |
| |
| std::string JNIHelper::GetExternalFilesDir() |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" ); |
| return std::string( "" ); |
| } |
| |
| pthread_mutex_lock( &mutex_ ); |
| |
| //First, try reading from externalFileDir; |
| JNIEnv *env; |
| jmethodID mid; |
| |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| jstring strPath = GetExternalFilesDirJString( env ); |
| const char* path = env->GetStringUTFChars( strPath, NULL ); |
| std::string s( path ); |
| |
| env->ReleaseStringUTFChars( strPath, path ); |
| env->DeleteLocalRef( strPath ); |
| activity_->vm->DetachCurrentThread(); |
| |
| pthread_mutex_unlock( &mutex_ ); |
| return s; |
| } |
| |
| uint32_t JNIHelper::LoadTexture( const char* file_name ) |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" ); |
| return 0; |
| } |
| |
| JNIEnv *env; |
| jmethodID mid; |
| |
| pthread_mutex_lock( &mutex_ ); |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| jstring name = env->NewStringUTF( file_name ); |
| |
| GLuint tex; |
| glGenTextures( 1, &tex ); |
| glBindTexture( GL_TEXTURE_2D, tex ); |
| |
| glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); |
| glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); |
| |
| mid = env->GetMethodID( jni_helper_java_class_, "loadTexture", "(Ljava/lang/String;)Z" ); |
| jboolean ret = env->CallBooleanMethod( jni_helper_java_ref_, mid, name ); |
| if( !ret ) |
| { |
| glDeleteTextures( 1, &tex ); |
| tex = -1; |
| LOGI( "Texture load failed %s", file_name ); |
| } |
| |
| //Generate mipmap |
| glGenerateMipmap( GL_TEXTURE_2D ); |
| |
| env->DeleteLocalRef( name ); |
| activity_->vm->DetachCurrentThread(); |
| pthread_mutex_unlock( &mutex_ ); |
| |
| return tex; |
| |
| } |
| |
| std::string JNIHelper::ConvertString( const char* str, |
| const char* encode ) |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" ); |
| return std::string( "" ); |
| } |
| |
| JNIEnv *env; |
| |
| pthread_mutex_lock( &mutex_ ); |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| int32_t iLength = strlen( (const char*) str ); |
| |
| jbyteArray array = env->NewByteArray( iLength ); |
| env->SetByteArrayRegion( array, 0, iLength, (const signed char*) str ); |
| |
| jstring strEncode = env->NewStringUTF( encode ); |
| |
| jclass cls = env->FindClass( "java/lang/String" ); |
| jmethodID ctor = env->GetMethodID( cls, "<init>", "([BLjava/lang/String;)V" ); |
| jstring object = (jstring) env->NewObject( cls, ctor, array, strEncode ); |
| |
| const char *cparam = env->GetStringUTFChars( object, NULL ); |
| |
| std::string s = std::string( cparam ); |
| |
| env->ReleaseStringUTFChars( object, cparam ); |
| env->DeleteLocalRef( strEncode ); |
| env->DeleteLocalRef( object ); |
| activity_->vm->DetachCurrentThread(); |
| pthread_mutex_unlock( &mutex_ ); |
| |
| return s; |
| } |
| |
| //--------------------------------------------------------------------------- |
| //Audio helpers |
| //--------------------------------------------------------------------------- |
| int32_t JNIHelper::GetNativeAudioBufferSize() |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" ); |
| return 0; |
| } |
| |
| JNIEnv *env; |
| jmethodID mid; |
| |
| pthread_mutex_lock( &mutex_ ); |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| mid = env->GetMethodID( jni_helper_java_class_, "getNativeAudioBufferSize", "()I" ); |
| int32_t i = env->CallIntMethod( jni_helper_java_ref_, mid ); |
| activity_->vm->DetachCurrentThread(); |
| pthread_mutex_unlock( &mutex_ ); |
| |
| return i; |
| } |
| |
| int32_t JNIHelper::GetNativeAudioSampleRate() |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" ); |
| return 0; |
| } |
| |
| JNIEnv *env; |
| jmethodID mid; |
| |
| pthread_mutex_lock( &mutex_ ); |
| activity_->vm->AttachCurrentThread( &env, NULL ); |
| |
| mid = env->GetMethodID( jni_helper_java_class_, "getNativeAudioSampleRate", "()I" ); |
| int32_t i = env->CallIntMethod( jni_helper_java_ref_, mid ); |
| activity_->vm->DetachCurrentThread(); |
| pthread_mutex_unlock( &mutex_ ); |
| |
| return i; |
| } |
| |
| //--------------------------------------------------------------------------- |
| //Misc implementations |
| //--------------------------------------------------------------------------- |
| jclass JNIHelper::RetrieveClass( JNIEnv *jni, |
| const char* class_name ) |
| { |
| jclass activity_class = jni->FindClass( CLASS_NAME ); |
| jmethodID get_class_loader = jni->GetMethodID( activity_class, "getClassLoader", |
| "()Ljava/lang/ClassLoader;" ); |
| jobject cls = jni->CallObjectMethod( activity_->clazz, get_class_loader ); |
| jclass class_loader = jni->FindClass( "java/lang/ClassLoader" ); |
| jmethodID find_class = jni->GetMethodID( class_loader, "loadClass", |
| "(Ljava/lang/String;)Ljava/lang/Class;" ); |
| |
| jstring str_class_name = jni->NewStringUTF( class_name ); |
| jclass class_retrieved = (jclass) jni->CallObjectMethod( cls, find_class, str_class_name ); |
| jni->DeleteLocalRef( str_class_name ); |
| return class_retrieved; |
| } |
| |
| jstring JNIHelper::GetExternalFilesDirJString( JNIEnv *env ) |
| { |
| if( activity_ == NULL ) |
| { |
| LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" ); |
| return NULL; |
| } |
| |
| // Invoking getExternalFilesDir() java API |
| jclass cls_Env = env->FindClass( CLASS_NAME ); |
| jmethodID mid = env->GetMethodID( cls_Env, "getExternalFilesDir", |
| "(Ljava/lang/String;)Ljava/io/File;" ); |
| jobject obj_File = env->CallObjectMethod( activity_->clazz, mid, NULL ); |
| jclass cls_File = env->FindClass( "java/io/File" ); |
| jmethodID mid_getPath = env->GetMethodID( cls_File, "getPath", "()Ljava/lang/String;" ); |
| jstring obj_Path = (jstring) env->CallObjectMethod( obj_File, mid_getPath ); |
| |
| return obj_Path; |
| } |
| |
| } //namespace ndkHelper |