- Immersive mode in android-19 - Fixed local reference release in JNI helper - Misc fixes Change-Id: I3ab19c2b66648bb7a011c462d9d98e75bc136ce6
377 lines
12 KiB
C++
377 lines
12 KiB
C++
/*
|
|
* 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
|