• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //---------------------------------------------------------------------------
GetInstance()35 JNIHelper* JNIHelper::GetInstance()
36 {
37     static JNIHelper helper;
38     return &helper;
39 }
40 
41 //---------------------------------------------------------------------------
42 //Ctor
43 //---------------------------------------------------------------------------
JNIHelper()44 JNIHelper::JNIHelper()
45 {
46     pthread_mutex_init( &mutex_, NULL );
47 }
48 
49 //---------------------------------------------------------------------------
50 //Dtor
51 //---------------------------------------------------------------------------
~JNIHelper()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 //---------------------------------------------------------------------------
Init(ANativeActivity * activity,const char * helper_class_name)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 //---------------------------------------------------------------------------
ReadFile(const char * fileName,std::vector<uint8_t> * buffer_ref)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 
GetExternalFilesDir()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 
LoadTexture(const char * file_name)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 
ConvertString(const char * str,const char * encode)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 //---------------------------------------------------------------------------
GetNativeAudioBufferSize()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 
GetNativeAudioSampleRate()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 //---------------------------------------------------------------------------
RetrieveClass(JNIEnv * jni,const char * class_name)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 
GetExternalFilesDirJString(JNIEnv * env)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