Home | History | Annotate | Download | only in ndk_helper
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #include <EGL/egl.h>
     17 #include <GLES2/gl2.h>
     18 #include <fstream>
     19 #include <iostream>
     20 
     21 #include "JNIHelper.h"
     22 
     23 namespace ndk_helper
     24 {
     25 
     26 #define CLASS_NAME "android/app/NativeActivity"
     27 
     28 //---------------------------------------------------------------------------
     29 //JNI Helper functions
     30 //---------------------------------------------------------------------------
     31 
     32 //---------------------------------------------------------------------------
     33 //Singleton
     34 //---------------------------------------------------------------------------
     35 JNIHelper* JNIHelper::GetInstance()
     36 {
     37     static JNIHelper helper;
     38     return &helper;
     39 }
     40 
     41 //---------------------------------------------------------------------------
     42 //Ctor
     43 //---------------------------------------------------------------------------
     44 JNIHelper::JNIHelper()
     45 {
     46     pthread_mutex_init( &mutex_, NULL );
     47 }
     48 
     49 //---------------------------------------------------------------------------
     50 //Dtor
     51 //---------------------------------------------------------------------------
     52 JNIHelper::~JNIHelper()
     53 {
     54     pthread_mutex_lock( &mutex_ );
     55 
     56     JNIEnv *env;
     57     activity_->vm->AttachCurrentThread( &env, NULL );
     58 
     59     env->DeleteGlobalRef( jni_helper_java_ref_ );
     60     env->DeleteGlobalRef( jni_helper_java_class_ );
     61 
     62     activity_->vm->DetachCurrentThread();
     63 
     64     pthread_mutex_destroy( &mutex_ );
     65 }
     66 
     67 //---------------------------------------------------------------------------
     68 //Init
     69 //---------------------------------------------------------------------------
     70 void JNIHelper::Init( ANativeActivity* activity,
     71         const char* helper_class_name )
     72 {
     73     JNIHelper& helper = *GetInstance();
     74     pthread_mutex_lock( &helper.mutex_ );
     75 
     76     helper.activity_ = activity;
     77 
     78     JNIEnv *env;
     79     helper.activity_->vm->AttachCurrentThread( &env, NULL );
     80 
     81     //Retrieve app name
     82     jclass android_content_Context = env->GetObjectClass( helper.activity_->clazz );
     83     jmethodID midGetPackageName = env->GetMethodID( android_content_Context, "getPackageName",
     84             "()Ljava/lang/String;" );
     85 
     86     jstring packageName = (jstring) env->CallObjectMethod( helper.activity_->clazz,
     87             midGetPackageName );
     88     const char* appname = env->GetStringUTFChars( packageName, NULL );
     89     helper.app_name_ = std::string( appname );
     90 
     91     jclass cls = helper.RetrieveClass( env, helper_class_name );
     92     helper.jni_helper_java_class_ = (jclass) env->NewGlobalRef( cls );
     93 
     94     jmethodID constructor = env->GetMethodID( helper.jni_helper_java_class_, "<init>", "()V" );
     95     helper.jni_helper_java_ref_ = env->NewObject( helper.jni_helper_java_class_, constructor );
     96     helper.jni_helper_java_ref_ = env->NewGlobalRef( helper.jni_helper_java_ref_ );
     97 
     98     env->ReleaseStringUTFChars( packageName, appname );
     99     helper.activity_->vm->DetachCurrentThread();
    100 
    101     pthread_mutex_unlock( &helper.mutex_ );
    102 }
    103 
    104 //---------------------------------------------------------------------------
    105 //readFile
    106 //---------------------------------------------------------------------------
    107 bool JNIHelper::ReadFile( const char* fileName,
    108         std::vector<uint8_t>* buffer_ref )
    109 {
    110     if( activity_ == NULL )
    111     {
    112         LOGI( "JNIHelper has not been initialized.Call init() to initialize the helper" );
    113         return false;
    114     }
    115 
    116     //First, try reading from externalFileDir;
    117     JNIEnv *env;
    118     jmethodID mid;
    119 
    120     pthread_mutex_lock( &mutex_ );
    121     activity_->vm->AttachCurrentThread( &env, NULL );
    122 
    123     jstring str_path = GetExternalFilesDirJString( env );
    124     const char* path = env->GetStringUTFChars( str_path, NULL );
    125     std::string s( path );
    126 
    127     if( fileName[0] != '/' )
    128     {
    129         s.append( "/" );
    130     }
    131     s.append( fileName );
    132     std::ifstream f( s.c_str(), std::ios::binary );
    133 
    134     env->ReleaseStringUTFChars( str_path, path );
    135     env->DeleteLocalRef( str_path );
    136     activity_->vm->DetachCurrentThread();
    137 
    138     if( f )
    139     {
    140         LOGI( "reading:%s", s.c_str() );
    141         f.seekg( 0, std::ifstream::end );
    142         int32_t fileSize = f.tellg();
    143         f.seekg( 0, std::ifstream::beg );
    144         buffer_ref->reserve( fileSize );
    145         buffer_ref->assign( std::istreambuf_iterator<char>( f ), std::istreambuf_iterator<char>() );
    146         f.close();
    147         pthread_mutex_unlock( &mutex_ );
    148         return true;
    149     }
    150     else
    151     {
    152         //Fallback to assetManager
    153         AAssetManager* assetManager = activity_->assetManager;
    154         AAsset* assetFile = AAssetManager_open( assetManager, fileName, AASSET_MODE_BUFFER );
    155         if( !assetFile )
    156         {
    157             pthread_mutex_unlock( &mutex_ );
    158             return false;
    159         }
    160         uint8_t* data = (uint8_t*) AAsset_getBuffer( assetFile );
    161         int32_t size = AAsset_getLength( assetFile );
    162         if( data == NULL )
    163         {
    164             AAsset_close( assetFile );
    165 
    166             LOGI( "Failed to load:%s", fileName );
    167             pthread_mutex_unlock( &mutex_ );
    168             return false;
    169         }
    170 
    171         buffer_ref->reserve( size );
    172         buffer_ref->assign( data, data + size );
    173 
    174         AAsset_close( assetFile );
    175         pthread_mutex_unlock( &mutex_ );
    176         return true;
    177     }
    178 }
    179 
    180 std::string JNIHelper::GetExternalFilesDir()
    181 {
    182     if( activity_ == NULL )
    183     {
    184         LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" );
    185         return std::string( "" );
    186     }
    187 
    188     pthread_mutex_lock( &mutex_ );
    189 
    190     //First, try reading from externalFileDir;
    191     JNIEnv *env;
    192     jmethodID mid;
    193 
    194     activity_->vm->AttachCurrentThread( &env, NULL );
    195 
    196     jstring strPath = GetExternalFilesDirJString( env );
    197     const char* path = env->GetStringUTFChars( strPath, NULL );
    198     std::string s( path );
    199 
    200     env->ReleaseStringUTFChars( strPath, path );
    201     env->DeleteLocalRef( strPath );
    202     activity_->vm->DetachCurrentThread();
    203 
    204     pthread_mutex_unlock( &mutex_ );
    205     return s;
    206 }
    207 
    208 uint32_t JNIHelper::LoadTexture( const char* file_name )
    209 {
    210     if( activity_ == NULL )
    211     {
    212         LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" );
    213         return 0;
    214     }
    215 
    216     JNIEnv *env;
    217     jmethodID mid;
    218 
    219     pthread_mutex_lock( &mutex_ );
    220     activity_->vm->AttachCurrentThread( &env, NULL );
    221 
    222     jstring name = env->NewStringUTF( file_name );
    223 
    224     GLuint tex;
    225     glGenTextures( 1, &tex );
    226     glBindTexture( GL_TEXTURE_2D, tex );
    227 
    228     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
    229     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    230 
    231     mid = env->GetMethodID( jni_helper_java_class_, "loadTexture", "(Ljava/lang/String;)Z" );
    232     jboolean ret = env->CallBooleanMethod( jni_helper_java_ref_, mid, name );
    233     if( !ret )
    234     {
    235         glDeleteTextures( 1, &tex );
    236         tex = -1;
    237         LOGI( "Texture load failed %s", file_name );
    238     }
    239 
    240     //Generate mipmap
    241     glGenerateMipmap( GL_TEXTURE_2D );
    242 
    243     env->DeleteLocalRef( name );
    244     activity_->vm->DetachCurrentThread();
    245     pthread_mutex_unlock( &mutex_ );
    246 
    247     return tex;
    248 
    249 }
    250 
    251 std::string JNIHelper::ConvertString( const char* str,
    252         const char* encode )
    253 {
    254     if( activity_ == NULL )
    255     {
    256         LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" );
    257         return std::string( "" );
    258     }
    259 
    260     JNIEnv *env;
    261 
    262     pthread_mutex_lock( &mutex_ );
    263     activity_->vm->AttachCurrentThread( &env, NULL );
    264 
    265     int32_t iLength = strlen( (const char*) str );
    266 
    267     jbyteArray array = env->NewByteArray( iLength );
    268     env->SetByteArrayRegion( array, 0, iLength, (const signed char*) str );
    269 
    270     jstring strEncode = env->NewStringUTF( encode );
    271 
    272     jclass cls = env->FindClass( "java/lang/String" );
    273     jmethodID ctor = env->GetMethodID( cls, "<init>", "([BLjava/lang/String;)V" );
    274     jstring object = (jstring) env->NewObject( cls, ctor, array, strEncode );
    275 
    276     const char *cparam = env->GetStringUTFChars( object, NULL );
    277 
    278     std::string s = std::string( cparam );
    279 
    280     env->ReleaseStringUTFChars( object, cparam );
    281     env->DeleteLocalRef( strEncode );
    282     env->DeleteLocalRef( object );
    283     activity_->vm->DetachCurrentThread();
    284     pthread_mutex_unlock( &mutex_ );
    285 
    286     return s;
    287 }
    288 
    289 //---------------------------------------------------------------------------
    290 //Audio helpers
    291 //---------------------------------------------------------------------------
    292 int32_t JNIHelper::GetNativeAudioBufferSize()
    293 {
    294     if( activity_ == NULL )
    295     {
    296         LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" );
    297         return 0;
    298     }
    299 
    300     JNIEnv *env;
    301     jmethodID mid;
    302 
    303     pthread_mutex_lock( &mutex_ );
    304     activity_->vm->AttachCurrentThread( &env, NULL );
    305 
    306     mid = env->GetMethodID( jni_helper_java_class_, "getNativeAudioBufferSize", "()I" );
    307     int32_t i = env->CallIntMethod( jni_helper_java_ref_, mid );
    308     activity_->vm->DetachCurrentThread();
    309     pthread_mutex_unlock( &mutex_ );
    310 
    311     return i;
    312 }
    313 
    314 int32_t JNIHelper::GetNativeAudioSampleRate()
    315 {
    316     if( activity_ == NULL )
    317     {
    318         LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" );
    319         return 0;
    320     }
    321 
    322     JNIEnv *env;
    323     jmethodID mid;
    324 
    325     pthread_mutex_lock( &mutex_ );
    326     activity_->vm->AttachCurrentThread( &env, NULL );
    327 
    328     mid = env->GetMethodID( jni_helper_java_class_, "getNativeAudioSampleRate", "()I" );
    329     int32_t i = env->CallIntMethod( jni_helper_java_ref_, mid );
    330     activity_->vm->DetachCurrentThread();
    331     pthread_mutex_unlock( &mutex_ );
    332 
    333     return i;
    334 }
    335 
    336 //---------------------------------------------------------------------------
    337 //Misc implementations
    338 //---------------------------------------------------------------------------
    339 jclass JNIHelper::RetrieveClass( JNIEnv *jni,
    340         const char* class_name )
    341 {
    342     jclass activity_class = jni->FindClass( CLASS_NAME );
    343     jmethodID get_class_loader = jni->GetMethodID( activity_class, "getClassLoader",
    344             "()Ljava/lang/ClassLoader;" );
    345     jobject cls = jni->CallObjectMethod( activity_->clazz, get_class_loader );
    346     jclass class_loader = jni->FindClass( "java/lang/ClassLoader" );
    347     jmethodID find_class = jni->GetMethodID( class_loader, "loadClass",
    348             "(Ljava/lang/String;)Ljava/lang/Class;" );
    349 
    350     jstring str_class_name = jni->NewStringUTF( class_name );
    351     jclass class_retrieved = (jclass) jni->CallObjectMethod( cls, find_class, str_class_name );
    352     jni->DeleteLocalRef( str_class_name );
    353     return class_retrieved;
    354 }
    355 
    356 jstring JNIHelper::GetExternalFilesDirJString( JNIEnv *env )
    357 {
    358     if( activity_ == NULL )
    359     {
    360         LOGI( "JNIHelper has not been initialized. Call init() to initialize the helper" );
    361         return NULL;
    362     }
    363 
    364     // Invoking getExternalFilesDir() java API
    365     jclass cls_Env = env->FindClass( CLASS_NAME );
    366     jmethodID mid = env->GetMethodID( cls_Env, "getExternalFilesDir",
    367             "(Ljava/lang/String;)Ljava/io/File;" );
    368     jobject obj_File = env->CallObjectMethod( activity_->clazz, mid, NULL );
    369     jclass cls_File = env->FindClass( "java/io/File" );
    370     jmethodID mid_getPath = env->GetMethodID( cls_File, "getPath", "()Ljava/lang/String;" );
    371     jstring obj_Path = (jstring) env->CallObjectMethod( obj_File, mid_getPath );
    372 
    373     return obj_Path;
    374 }
    375 
    376 } //namespace ndkHelper
    377